ADS: Integrate newest base repository commits

* Add drag and drop to auto hide

Base repository was merged until commit
65600a4dcd072fd2773b661823816db6392c34eb

Change-Id: I09dd6613869368d3cf0c701055a6972db915561d
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Henning Gruendl
2023-07-19 17:03:29 +02:00
committed by Henning Gründl
parent 16ef838f23
commit bb635325e7
26 changed files with 1224 additions and 353 deletions

View File

@@ -63,6 +63,45 @@ DockInsertParam dockAreaInsertParameters(DockWidgetArea area)
return DockInsertParam(Qt::Vertical, false); return DockInsertParam(Qt::Vertical, false);
} }
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) QPixmap createTransparentPixmap(const QPixmap &source, qreal opacity)
{ {
QPixmap transparentPixmap(source.size()); QPixmap transparentPixmap(source.size());

View File

@@ -16,11 +16,11 @@ class QSplitter;
QT_END_NAMESPACE QT_END_NAMESPACE
#if defined(ADVANCEDDOCKINGSYSTEM_LIBRARY) #if defined(ADVANCEDDOCKINGSYSTEM_LIBRARY)
# define ADS_EXPORT Q_DECL_EXPORT #define ADS_EXPORT Q_DECL_EXPORT
#elif defined(ADVANCEDDOCKINGSYSTEM_STATIC_LIBRARY) #elif defined(ADVANCEDDOCKINGSYSTEM_STATIC_LIBRARY)
# define ADS_EXPORT #define ADS_EXPORT
#else #else
# define ADS_EXPORT Q_DECL_IMPORT #define ADS_EXPORT Q_DECL_IMPORT
#endif #endif
//#define ADS_DEBUG_PRINT //#define ADS_DEBUG_PRINT
@@ -47,14 +47,21 @@ enum DockWidgetArea {
TopDockWidgetArea = 0x04, TopDockWidgetArea = 0x04,
BottomDockWidgetArea = 0x08, BottomDockWidgetArea = 0x08,
CenterDockWidgetArea = 0x10, CenterDockWidgetArea = 0x10,
LeftAutoHideArea = 0x20,
RightAutoHideArea = 0x40,
TopAutoHideArea = 0x80,
BottomAutoHideArea = 0x100,
InvalidDockWidgetArea = NoDockWidgetArea, InvalidDockWidgetArea = NoDockWidgetArea,
OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea
| BottomDockWidgetArea, | BottomDockWidgetArea,
AutoHideDockAreas = LeftAutoHideArea | RightAutoHideArea | TopAutoHideArea | BottomAutoHideArea,
AllDockAreas = OuterDockAreas | CenterDockWidgetArea AllDockAreas = OuterDockAreas | CenterDockWidgetArea
}; };
Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea) Q_DECLARE_FLAGS(DockWidgetAreas, DockWidgetArea)
enum eTabIndex { TabDefaultInsertIndex = -1, TabInvalidIndex = -2 };
enum eTitleBarButton { enum eTitleBarButton {
TitleBarButtonTabsMenu, TitleBarButtonTabsMenu,
TitleBarButtonUndock, TitleBarButtonUndock,
@@ -137,6 +144,21 @@ public:
*/ */
DockInsertParam dockAreaInsertParameters(DockWidgetArea area); DockInsertParam 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 * Searches for the parent widget of the given type. Returns the parent widget of the given
* widget or 0 if the widget is not child of any widget of type T. * widget or 0 if the widget is not child of any widget of type T.

View File

@@ -90,6 +90,7 @@ struct AutoHideDockContainerPrivate
ResizeHandle *m_resizeHandle = nullptr; ResizeHandle *m_resizeHandle = nullptr;
QSize m_size; // creates invalid size QSize m_size; // creates invalid size
QPointer<AutoHideTab> m_sideTab; QPointer<AutoHideTab> m_sideTab;
QSize m_sizeCache;
/** /**
* Private data constructor * Private data constructor
@@ -181,6 +182,7 @@ AutoHideDockContainer::AutoHideDockContainer(DockWidget *dockWidget,
bool opaqueResize = DockManager::testConfigFlag(DockManager::OpaqueSplitterResize); bool opaqueResize = DockManager::testConfigFlag(DockManager::OpaqueSplitterResize);
d->m_resizeHandle->setOpaqueResize(opaqueResize); d->m_resizeHandle->setOpaqueResize(opaqueResize);
d->m_size = d->m_dockArea->size(); d->m_size = d->m_dockArea->size();
d->m_sizeCache = dockWidget->size();
addDockWidget(dockWidget); addDockWidget(dockWidget);
parent->registerAutoHideWidget(this); parent->registerAutoHideWidget(this);
@@ -228,6 +230,11 @@ void AutoHideDockContainer::updateSize()
default: default:
break; break;
} }
if (orientation() == Qt::Horizontal)
d->m_sizeCache.setHeight(this->height());
else
d->m_sizeCache.setWidth(this->width());
} }
AutoHideDockContainer::~AutoHideDockContainer() AutoHideDockContainer::~AutoHideDockContainer()
@@ -245,13 +252,13 @@ AutoHideDockContainer::~AutoHideDockContainer()
delete d; delete d;
} }
AutoHideSideBar *AutoHideDockContainer::sideBar() const AutoHideSideBar *AutoHideDockContainer::autoHideSideBar() const
{ {
if (d->m_sideTab) { if (d->m_sideTab) {
return d->m_sideTab->sideBar(); return d->m_sideTab->sideBar();
} else { } else {
auto container = dockContainer(); auto container = dockContainer();
return container ? container->sideTabBar(d->m_sideTabBarArea) : nullptr; return container ? container->autoHideSideBar(d->m_sideTabBarArea) : nullptr;
} }
} }
@@ -277,14 +284,18 @@ void AutoHideDockContainer::addDockWidget(DockWidget *dockWidget)
DockAreaWidget *oldDockArea = dockWidget->dockAreaWidget(); DockAreaWidget *oldDockArea = dockWidget->dockAreaWidget();
auto isRestoringState = dockWidget->dockManager()->isRestoringState(); auto isRestoringState = dockWidget->dockManager()->isRestoringState();
if (oldDockArea && !isRestoringState) { if (oldDockArea && !isRestoringState) {
// The initial size should be a little bit bigger than the original dock // The initial size should be a little bit bigger than the original dock area size to
// area size to prevent that the resize handle of this auto hid dock area // prevent that the resize handle of this auto hid dock area is near of the splitter of
// is near of the splitter of the old dock area. // the old dock area.
d->m_size = oldDockArea->size() + QSize(16, 16); d->m_size = oldDockArea->size() + QSize(16, 16);
oldDockArea->removeDockWidget(dockWidget); oldDockArea->removeDockWidget(dockWidget);
} }
d->m_dockArea->addDockWidget(dockWidget); d->m_dockArea->addDockWidget(dockWidget);
updateSize(); updateSize();
// The dock area is not visible and will not update the size when updateSize() is called for
// this auto hide container. Therefore we explicitly resize it here. As soon as it will
// become visible, it will get the right size
d->m_dockArea->resize(size());
} }
SideBarLocation AutoHideDockContainer::sideBarLocation() const SideBarLocation AutoHideDockContainer::sideBarLocation() const
@@ -393,6 +404,39 @@ void AutoHideDockContainer::setSize(int size)
updateSize(); updateSize();
} }
Qt::Orientation AutoHideDockContainer::orientation() const
{
return internal::isHorizontalSideBarLocation(d->m_sideTabBarArea) ? Qt::Horizontal
: Qt::Vertical;
}
void AutoHideDockContainer::resetToInitialDockWidgetSize()
{
if (orientation() == Qt::Horizontal)
setSize(d->m_sizeCache.height());
else
setSize(d->m_sizeCache.width());
}
void AutoHideDockContainer::moveToNewSideBarLocation(SideBarLocation newSideBarLocation, int index)
{
if (newSideBarLocation == sideBarLocation() && index == tabIndex())
return;
auto oldOrientation = orientation();
auto sideBar = dockContainer()->autoHideSideBar(newSideBarLocation);
sideBar->addAutoHideWidget(this, index);
// 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 stretched dock widget after insertion.
if (sideBar->orientation() != oldOrientation)
resetToInitialDockWidgetSize();
}
int AutoHideDockContainer::tabIndex() const
{
return d->m_sideTab->tabIndex();
}
/** /**
* Returns true if the object given in ancestor is an ancestor of the object given in descendant * Returns true if the object given in ancestor is an ancestor of the object given in descendant
*/ */

View File

@@ -66,7 +66,7 @@ public:
/** /**
* Get's the side tab bar * Get's the side tab bar
*/ */
AutoHideSideBar *sideBar() const; AutoHideSideBar *autoHideSideBar() const;
/** /**
* Returns the side tab * Returns the side tab
@@ -137,6 +137,32 @@ public:
* Depending on the sidebar location this will set the width or height of this auto hide container. * Depending on the sidebar location this will set the width or height of this auto hide container.
*/ */
void setSize(int size); void setSize(int size);
/**
* 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;
/**
* 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();
/**
* 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 index = -1);
/**
* Returns the index of this container in the sidebar.
*/
int tabIndex() const;
}; };
} // namespace ADS } // namespace ADS

View File

@@ -147,6 +147,7 @@ void AutoHideSideBar::insertTab(int index, AutoHideTab *sideTab)
{ {
sideTab->setSideBar(this); sideTab->setSideBar(this);
sideTab->installEventFilter(this); sideTab->installEventFilter(this);
// Default insertion is append
if (index < 0) if (index < 0)
d->m_tabsLayout->insertWidget(d->m_tabsLayout->count() - 1, sideTab); d->m_tabsLayout->insertWidget(d->m_tabsLayout->count() - 1, sideTab);
else else
@@ -177,19 +178,28 @@ void AutoHideSideBar::removeAutoHideWidget(AutoHideDockContainer *autoHideWidget
autoHideWidget->setParent(nullptr); autoHideWidget->setParent(nullptr);
} }
void AutoHideSideBar::addAutoHideWidget(AutoHideDockContainer *autoHideWidget) void AutoHideSideBar::addAutoHideWidget(AutoHideDockContainer *autoHideWidget, int index)
{ {
auto sideBar = autoHideWidget->autoHideTab()->sideBar(); auto sideBar = autoHideWidget->autoHideTab()->sideBar();
if (sideBar == this) if (sideBar == this) {
// 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() == index || (autoHideWidget->tabIndex() + 1) == index)
return; 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() < index)
--index;
}
if (sideBar) if (sideBar)
sideBar->removeAutoHideWidget(autoHideWidget); sideBar->removeAutoHideWidget(autoHideWidget);
autoHideWidget->setParent(d->m_containerWidget); autoHideWidget->setParent(d->m_containerWidget);
autoHideWidget->setSideBarLocation(d->m_sideTabArea); autoHideWidget->setSideBarLocation(d->m_sideTabArea);
d->m_containerWidget->registerAutoHideWidget(autoHideWidget); d->m_containerWidget->registerAutoHideWidget(autoHideWidget);
insertTab(-1, autoHideWidget->autoHideTab()); insertTab(index, autoHideWidget->autoHideTab());
} }
void AutoHideSideBar::removeTab(AutoHideTab *sideTab) void AutoHideSideBar::removeTab(AutoHideTab *sideTab)
@@ -228,33 +238,73 @@ Qt::Orientation AutoHideSideBar::orientation() const
return d->m_orientation; return d->m_orientation;
} }
AutoHideTab *AutoHideSideBar::tabAt(int index) const AutoHideTab *AutoHideSideBar::tab(int index) const
{ {
return qobject_cast<AutoHideTab *>(d->m_tabsLayout->itemAt(index)->widget()); return qobject_cast<AutoHideTab *>(d->m_tabsLayout->itemAt(index)->widget());
} }
int AutoHideSideBar::tabCount() const int AutoHideSideBar::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 AutoHideSideBar::tabInsertIndexAt(const QPoint &pos) const
{
int index = tabAt(pos);
if (index == TabInvalidIndex)
return TabDefaultInsertIndex;
else
return (index < 0) ? 0 : index;
}
int AutoHideSideBar::indexOfTab(const AutoHideTab &autoHideTab) const
{
for (auto i = 0; i < count(); i++) {
if (tab(i) == &autoHideTab)
return i;
}
return -1;
}
int AutoHideSideBar::count() const
{ {
return d->m_tabsLayout->count() - 1; return d->m_tabsLayout->count() - 1;
} }
int AutoHideSideBar::visibleTabCount() const int AutoHideSideBar::visibleTabCount() const
{ {
int count = 0; int c = 0;
auto parent = parentWidget(); auto parent = parentWidget();
for (auto i = 0; i < tabCount(); i++) { for (auto i = 0; i < count(); i++) {
if (tabAt(i)->isVisibleTo(parent)) if (tab(i)->isVisibleTo(parent))
count++; c++;
} }
return count; return c;
} }
bool AutoHideSideBar::hasVisibleTabs() const bool AutoHideSideBar::hasVisibleTabs() const
{ {
auto parent = parentWidget(); auto parent = parentWidget();
for (auto i = 0; i < tabCount(); i++) { for (auto i = 0; i < count(); i++) {
if (tabAt(i)->isVisibleTo(parent)) if (tab(i)->isVisibleTo(parent))
return true; return true;
} }
@@ -268,19 +318,19 @@ SideBarLocation AutoHideSideBar::sideBarLocation() const
void AutoHideSideBar::saveState(QXmlStreamWriter &s) const void AutoHideSideBar::saveState(QXmlStreamWriter &s) const
{ {
if (!tabCount()) if (!count())
return; return;
s.writeStartElement("sideBar"); s.writeStartElement("sideBar");
s.writeAttribute("area", QString::number(sideBarLocation())); 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 currentTab = tab(i);
if (!tab) if (!currentTab)
continue; continue;
tab->dockWidget()->autoHideDockContainer()->saveState(s); currentTab->dockWidget()->autoHideDockContainer()->saveState(s);
} }
s.writeEndElement(); s.writeEndElement();

View File

@@ -91,7 +91,7 @@ public:
* Adds the given AutoHideWidget to this sidebar. If the AutoHideWidget is in another sidebar, * Adds the given AutoHideWidget to this sidebar. If the AutoHideWidget is in another sidebar,
* then it will be removed from this sidebar. * then it will be removed from this sidebar.
*/ */
void addAutoHideWidget(AutoHideDockContainer *autoHideWidget); void addAutoHideWidget(AutoHideDockContainer *autoHideWidget, int index = TabDefaultInsertIndex);
/** /**
* Returns orientation of side tab. * Returns orientation of side tab.
@@ -101,12 +101,29 @@ public:
/** /**
* 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.
*/ */
AutoHideTab *tabAt(int index) const; AutoHideTab *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 AutoHideTab &tab) const;
/** /**
* Gets the count of the tab widgets. * Gets the count of the tab widgets.
*/ */
int tabCount() const; int count() const;
/** /**
* Returns the number of visible tabs to its parent widget. * Returns the number of visible tabs to its parent widget.

View File

@@ -6,14 +6,22 @@
#include "ads_globals_p.h" #include "ads_globals_p.h"
#include "autohidedockcontainer.h" #include "autohidedockcontainer.h"
#include "autohidesidebar.h" #include "autohidesidebar.h"
#include "dockareawidget.h"
#include "dockmanager.h" #include "dockmanager.h"
#include "dockoverlay.h"
#include "dockwidget.h" #include "dockwidget.h"
#include "floatingdragpreview.h"
#include <QApplication> #include <QApplication>
#include <QBoxLayout> #include <QBoxLayout>
#include <QContextMenuEvent>
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QMenu>
namespace ADS { namespace ADS {
static const char *const g_locationProperty = "Location";
/** /**
* Private data class of CDockWidgetTab class (pimpl) * Private data class of CDockWidgetTab class (pimpl)
*/ */
@@ -24,6 +32,12 @@ struct AutoHideTabPrivate
AutoHideSideBar *m_sideBar = nullptr; AutoHideSideBar *m_sideBar = nullptr;
Qt::Orientation m_orientation{Qt::Vertical}; Qt::Orientation m_orientation{Qt::Vertical};
QElapsedTimer m_timeSinceHoverMousePress; QElapsedTimer m_timeSinceHoverMousePress;
bool m_mousePressed = false;
eDragState m_dragState = DraggingInactive;
QPoint m_globalDragStartMousePosition;
QPoint m_dragStartMousePosition;
AbstractFloatingWidget *m_floatingWidget = nullptr;
Qt::Orientation m_dragStartOrientation;
/** /**
* Private data constructor * Private data constructor
@@ -52,6 +66,48 @@ struct AutoHideTabPrivate
if (container) if (container)
container->handleAutoHideWidgetEvent(event, q); container->handleAutoHideWidgetEvent(event, q);
} }
/**
* 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, q, &AutoHideTab::onAutoHideToActionClicked);
action->setEnabled(location != q->sideBarLocation());
return action;
}
/**
* Test function for current drag state.
*/
bool isDraggingState(eDragState dragState) const { return m_dragState == dragState; }
/**
* Saves the drag start position in global and local coordinates.
*/
void saveDragStartMousePosition(const QPoint &globalPos)
{
m_globalDragStartMousePosition = globalPos;
m_dragStartMousePosition = q->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>
AbstractFloatingWidget *createFloatingWidget(T *widget)
{
auto w = new FloatingDragPreview(widget);
q->connect(w, &FloatingDragPreview::draggingCanceled, [=]() {
m_dragState = DraggingInactive;
});
return w;
}
}; // struct DockWidgetTabPrivate }; // struct DockWidgetTabPrivate
AutoHideTabPrivate::AutoHideTabPrivate(AutoHideTab *parent) AutoHideTabPrivate::AutoHideTabPrivate(AutoHideTab *parent)
@@ -71,25 +127,47 @@ void AutoHideTabPrivate::updateOrientation()
} }
} }
void AutoHideTab::setSideBar(AutoHideSideBar *sideTabBar) bool AutoHideTabPrivate::startFloating(eDragState draggingState)
{ {
d->m_sideBar = sideTabBar; auto dockArea = m_dockWidget->dockAreaWidget();
if (d->m_sideBar) qCInfo(adsLog) << Q_FUNC_INFO << "isFloating " << dockContainer()->isFloating();
d->updateOrientation();
}
AutoHideSideBar *AutoHideTab::sideBar() const m_dragState = draggingState;
{ AbstractFloatingWidget *floatingWidget = nullptr;
return d->m_sideBar; floatingWidget = createFloatingWidget(dockArea);
} auto size = dockArea->size();
auto startPos = m_dragStartMousePosition;
auto autoHideContainer = m_dockWidget->autoHideDockContainer();
m_dragStartOrientation = autoHideContainer->orientation();
void AutoHideTab::removeFromSideBar() switch (m_sideBar->sideBarLocation()) {
{ case SideBarLeft:
if (d->m_sideBar == nullptr) startPos.rx() = autoHideContainer->rect().left() + 10;
return; break;
d->m_sideBar->removeTab(this); case SideBarRight:
setSideBar(nullptr); 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, q);
auto dockManager = m_dockWidget->dockManager();
auto overlay = dockManager->containerOverlay();
overlay->setAllowedAreas(OuterDockAreas);
m_floatingWidget = floatingWidget;
qApp->postEvent(m_dockWidget, new QEvent((QEvent::Type) internal::g_dockedWidgetDragStartEvent));
return true;
} }
AutoHideTab::AutoHideTab(QWidget *parent) AutoHideTab::AutoHideTab(QWidget *parent)
@@ -164,6 +242,61 @@ void AutoHideTab::setDockWidget(DockWidget *dockWidget)
setIcon(d->m_dockWidget->icon()); setIcon(d->m_dockWidget->icon());
setToolTip(dockWidget->windowTitle()); setToolTip(dockWidget->windowTitle());
} }
bool AutoHideTab::iconOnly() const
{
return DockManager::testAutoHideConfigFlag(DockManager::AutoHideSideBarsIconOnly)
&& !icon().isNull();
}
AutoHideSideBar *AutoHideTab::sideBar() const
{
return d->m_sideBar;
}
int AutoHideTab::tabIndex() const
{
if (!d->m_sideBar)
return -1;
return d->m_sideBar->indexOfTab(*this);
}
void AutoHideTab::setDockWidgetFloating()
{
d->m_dockWidget->setFloating();
}
void AutoHideTab::unpinDockWidget()
{
d->m_dockWidget->setAutoHide(false);
}
void AutoHideTab::requestCloseDockWidget()
{
d->m_dockWidget->requestCloseDockWidget();
}
void AutoHideTab::onAutoHideToActionClicked()
{
int location = sender()->property(g_locationProperty).toInt();
d->m_dockWidget->setAutoHide(true, (SideBarLocation) location);
}
void AutoHideTab::setSideBar(AutoHideSideBar *sideTabBar)
{
d->m_sideBar = sideTabBar;
if (d->m_sideBar)
d->updateOrientation();
}
void AutoHideTab::removeFromSideBar()
{
if (d->m_sideBar == nullptr)
return;
d->m_sideBar->removeTab(this);
setSideBar(nullptr);
}
bool AutoHideTab::event(QEvent *event) bool AutoHideTab::event(QEvent *event)
{ {
@@ -194,10 +327,138 @@ bool AutoHideTab::event(QEvent *event)
return Super::event(event); return Super::event(event);
} }
bool AutoHideTab::iconOnly() const void AutoHideTab::contextMenuEvent(QContextMenuEvent *event)
{ {
return DockManager::testAutoHideConfigFlag(DockManager::AutoHideSideBarsIconOnly) event->accept();
&& !icon().isNull(); d->saveDragStartMousePosition(event->globalPos());
const bool isFloatable = d->m_dockWidget->features().testFlag(DockWidget::DockWidgetFloatable);
QMenu menu(this);
QAction *detachAction = menu.addAction(tr("Detach"));
detachAction->connect(detachAction,
&QAction::triggered,
this,
&AutoHideTab::setDockWidgetFloating);
detachAction->setEnabled(isFloatable);
auto isPinnable = d->m_dockWidget->features().testFlag(DockWidget::DockWidgetPinnable);
detachAction->setEnabled(isPinnable);
auto pinToMenu = menu.addMenu(tr("Pin To..."));
pinToMenu->setEnabled(isPinnable);
d->createAutoHideToAction(tr("Top"), SideBarTop, pinToMenu);
d->createAutoHideToAction(tr("Left"), SideBarLeft, pinToMenu);
d->createAutoHideToAction(tr("Right"), SideBarRight, pinToMenu);
d->createAutoHideToAction(tr("Bottom"), SideBarBottom, pinToMenu);
QAction *unpinAction = menu.addAction(tr("Unpin (Dock)"));
unpinAction->connect(unpinAction, &QAction::triggered, this, &AutoHideTab::unpinDockWidget);
menu.addSeparator();
QAction *closeAction = menu.addAction(tr("Close"));
closeAction->connect(closeAction,
&QAction::triggered,
this,
&AutoHideTab::requestCloseDockWidget);
closeAction->setEnabled(d->m_dockWidget->features().testFlag(DockWidget::DockWidgetClosable));
menu.exec(event->globalPos());
}
void AutoHideTab::mousePressEvent(QMouseEvent *event)
{
// If AutoHideShowOnMouseOver is active, then the showing is triggered by a MousePressEvent
// sent to this tab. To prevent accidental hiding of the tab by a mouse click, we wait at
// least 500 ms before we accept the mouse click.
if (!event->spontaneous()) {
d->m_timeSinceHoverMousePress.restart();
d->forwardEventToDockContainer(event);
} else if (d->m_timeSinceHoverMousePress.hasExpired(500)) {
d->forwardEventToDockContainer(event);
}
if (event->button() == Qt::LeftButton) {
event->accept();
d->m_mousePressed = true;
d->saveDragStartMousePosition(event->globalPosition().toPoint());
d->m_dragState = DraggingMousePressed;
}
Super::mousePressEvent(event);
}
void AutoHideTab::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
d->m_mousePressed = false;
auto currentDragState = d->m_dragState;
d->m_globalDragStartMousePosition = QPoint();
d->m_dragStartMousePosition = QPoint();
d->m_dragState = DraggingInactive;
switch (currentDragState) {
case DraggingTab:
// End of tab moving, emit signal
//if (d->DockArea) {
// event->accept();
// Q_EMIT moved(internal::globalPositionOf(event));
//}
break;
case DraggingFloatingWidget:
event->accept();
d->m_floatingWidget->finishDragging();
if (d->m_dockWidget->isAutoHide() && d->m_dragStartOrientation != orientation())
d->m_dockWidget->autoHideDockContainer()->resetToInitialDockWidgetSize();
break;
default:
break; // do nothing
}
}
Super::mouseReleaseEvent(event);
}
void AutoHideTab::mouseMoveEvent(QMouseEvent *event)
{
if (!(event->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive)) {
d->m_dragState = DraggingInactive;
Super::mouseMoveEvent(event);
return;
}
// Move floating window
if (d->isDraggingState(DraggingFloatingWidget)) {
d->m_floatingWidget->moveFloating();
Super::mouseMoveEvent(event);
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(event->pos());
bool mouseOutsideBar = (mappedPos.x() < 0) || (mappedPos.x() > parentWidget()->rect().right());
// Maybe a fixed drag distance is better here ?
int dragDistanceY = qAbs(d->m_globalDragStartMousePosition.y()
- event->globalPosition().toPoint().y());
if (dragDistanceY >= DockManager::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->m_dockWidget->features();
if (Features.testFlag(DockWidget::DockWidgetFloatable)
|| (Features.testFlag(DockWidget::DockWidgetMovable))) {
d->startFloating();
}
return;
}
Super::mouseMoveEvent(event);
} }
} // namespace ADS } // namespace ADS

View File

@@ -38,10 +38,16 @@ private:
friend class DockContainerWidget; friend class DockContainerWidget;
friend DockContainerWidgetPrivate; friend DockContainerWidgetPrivate;
void onAutoHideToActionClicked();
protected: protected:
void setSideBar(AutoHideSideBar *sideTabBar); void setSideBar(AutoHideSideBar *sideTabBar);
void removeFromSideBar(); void removeFromSideBar();
virtual bool event(QEvent *event) override; virtual bool event(QEvent *event) override;
virtual void contextMenuEvent(QContextMenuEvent *event) override;
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
public: public:
using Super = PushButton; using Super = PushButton;
@@ -102,6 +108,26 @@ public:
* Returns the side bar that contains this tab or a nullptr if the tab is not in a side bar. * Returns the side bar that contains this tab or a nullptr if the tab is not in a side bar.
*/ */
AutoHideSideBar *sideBar() const; AutoHideSideBar *sideBar() const;
/**
* Returns the index of this tab in the sideBar.
*/
int tabIndex() const;
/**
* 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 }; // class AutoHideTab
} // namespace ADS } // namespace ADS

View File

@@ -104,6 +104,75 @@ DockAreaTabBar::~DockAreaTabBar()
delete d; delete d;
} }
void DockAreaTabBar::onTabClicked(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
if (index < 0)
return;
setCurrentIndex(index);
emit tabBarClicked(index);
}
void DockAreaTabBar::onTabCloseRequested(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
closeTab(index);
}
void DockAreaTabBar::onCloseOtherTabsRequested(DockWidgetTab *sourceTab)
{
for (int i = 0; i < count(); ++i) {
auto currentTab = tab(i);
if (currentTab->isClosable() && !currentTab->isHidden() && currentTab != sourceTab) {
// If the dock widget is deleted with the closeTab() call, its tab it will no longer
// be in the layout, and thus the index needs to be updated to not skip any tabs.
int offset = currentTab->dockWidget()->features().testFlag(
DockWidget::DockWidgetDeleteOnClose)
? 1
: 0;
closeTab(i);
// If the the dock widget blocks closing, i.e. if the flag CustomCloseHandling is set,
// and the dock widget is still open, then we do not need to correct the index.
if (currentTab->dockWidget()->isClosed())
i -= offset;
}
}
}
void DockAreaTabBar::onTabWidgetMoved(DockWidgetTab *sourceTab, const QPoint &globalPosition)
{
const int fromIndex = d->m_tabsLayout->indexOf(sourceTab);
auto mousePos = mapFromGlobal(globalPosition);
mousePos.rx() = qMax(d->firstTab()->geometry().left(), mousePos.x());
mousePos.rx() = qMin(d->lastTab()->geometry().right(), mousePos.x());
int toIndex = -1;
// Find tab under mouse
for (int i = 0; i < count(); ++i) {
DockWidgetTab *dropTab = tab(i);
if (dropTab == sourceTab || !dropTab->isVisibleTo(this)
|| !dropTab->geometry().contains(mousePos))
continue;
toIndex = d->m_tabsLayout->indexOf(dropTab);
if (toIndex == fromIndex)
toIndex = -1;
break;
}
if (toIndex > -1) {
d->m_tabsLayout->removeWidget(sourceTab);
d->m_tabsLayout->insertWidget(toIndex, sourceTab);
qCInfo(adsLog) << "tabMoved from" << fromIndex << "to" << toIndex;
emit tabMoved(fromIndex, toIndex);
setCurrentIndex(toIndex);
} else {
// Ensure that the moved tab is reset to its start position
d->m_tabsLayout->update();
}
}
void DockAreaTabBar::wheelEvent(QWheelEvent *event) void DockAreaTabBar::wheelEvent(QWheelEvent *event)
{ {
event->accept(); event->accept();
@@ -114,23 +183,6 @@ void DockAreaTabBar::wheelEvent(QWheelEvent *event)
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20); horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
} }
void DockAreaTabBar::setCurrentIndex(int index)
{
if (index == d->m_currentIndex)
return;
if (index < -1 || index > (count() - 1)) {
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
return;
}
emit currentChanging(index);
d->m_currentIndex = index;
d->updateTabs();
updateGeometry();
emit currentChanged(index);
}
int DockAreaTabBar::count() const int DockAreaTabBar::count() const
{ {
// The tab bar contains a stretch item as last item // The tab bar contains a stretch item as last item
@@ -226,42 +278,6 @@ DockWidgetTab *DockAreaTabBar::currentTab() const
return qobject_cast<DockWidgetTab *>(d->m_tabsLayout->itemAt(d->m_currentIndex)->widget()); return qobject_cast<DockWidgetTab *>(d->m_tabsLayout->itemAt(d->m_currentIndex)->widget());
} }
void DockAreaTabBar::onTabClicked(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
if (index < 0)
return;
setCurrentIndex(index);
emit tabBarClicked(index);
}
void DockAreaTabBar::onTabCloseRequested(DockWidgetTab *sourceTab)
{
const int index = d->m_tabsLayout->indexOf(sourceTab);
closeTab(index);
}
void DockAreaTabBar::onCloseOtherTabsRequested(DockWidgetTab *sourceTab)
{
for (int i = 0; i < count(); ++i) {
auto currentTab = tab(i);
if (currentTab->isClosable() && !currentTab->isHidden() && currentTab != sourceTab) {
// If the dock widget is deleted with the closeTab() call, its tab it will no longer
// be in the layout, and thus the index needs to be updated to not skip any tabs.
int offset = currentTab->dockWidget()->features().testFlag(
DockWidget::DockWidgetDeleteOnClose)
? 1
: 0;
closeTab(i);
// If the the dock widget blocks closing, i.e. if the flag CustomCloseHandling is set,
// and the dock widget is still open, then we do not need to correct the index.
if (currentTab->dockWidget()->isClosed())
i -= offset;
}
}
}
DockWidgetTab *DockAreaTabBar::tab(int index) const DockWidgetTab *DockAreaTabBar::tab(int index) const
{ {
if (index >= count() || index < 0) if (index >= count() || index < 0)
@@ -270,49 +286,29 @@ DockWidgetTab *DockAreaTabBar::tab(int index) const
return qobject_cast<DockWidgetTab *>(d->m_tabsLayout->itemAt(index)->widget()); return qobject_cast<DockWidgetTab *>(d->m_tabsLayout->itemAt(index)->widget());
} }
void DockAreaTabBar::onTabWidgetMoved(DockWidgetTab *sourceTab, const QPoint &globalPosition) int DockAreaTabBar::tabAt(const QPoint &pos) const
{ {
const int fromIndex = d->m_tabsLayout->indexOf(sourceTab); if (!isVisible())
auto mousePos = mapFromGlobal(globalPosition); return TabInvalidIndex;
mousePos.rx() = qMax(d->firstTab()->geometry().left(), mousePos.x());
mousePos.rx() = qMin(d->lastTab()->geometry().right(), mousePos.x()); if (pos.x() < tab(0)->geometry().x())
int toIndex = -1; return -1;
// Find tab under mouse
for (int i = 0; i < count(); ++i) { for (int i = 0; i < count(); ++i) {
DockWidgetTab *dropTab = tab(i); if (tab(i)->geometry().contains(pos))
if (dropTab == sourceTab || !dropTab->isVisibleTo(this) return i;
|| !dropTab->geometry().contains(mousePos))
continue;
toIndex = d->m_tabsLayout->indexOf(dropTab);
if (toIndex == fromIndex)
toIndex = -1;
break;
} }
if (toIndex > -1) { return count();
d->m_tabsLayout->removeWidget(sourceTab);
d->m_tabsLayout->insertWidget(toIndex, sourceTab);
qCInfo(adsLog) << "tabMoved from" << fromIndex << "to" << toIndex;
emit tabMoved(fromIndex, toIndex);
setCurrentIndex(toIndex);
} else {
// Ensure that the moved tab is reset to its start position
d->m_tabsLayout->update();
}
} }
void DockAreaTabBar::closeTab(int index) int DockAreaTabBar::tabInsertIndexAt(const QPoint &pos) const
{ {
if (index < 0 || index >= count()) int index = tabAt(pos);
return; if (index == TabInvalidIndex)
return TabDefaultInsertIndex;
auto dockWidgetTab = tab(index); else
if (dockWidgetTab->isHidden()) return (index < 0) ? 0 : index;
return;
emit tabCloseRequested(index);
} }
bool DockAreaTabBar::eventFilter(QObject *watched, QEvent *event) bool DockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
@@ -362,4 +358,33 @@ QSize DockAreaTabBar::sizeHint() const
return d->m_tabsContainerWidget->sizeHint(); return d->m_tabsContainerWidget->sizeHint();
} }
void DockAreaTabBar::setCurrentIndex(int index)
{
if (index == d->m_currentIndex)
return;
if (index < -1 || index > (count() - 1)) {
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
return;
}
emit currentChanging(index);
d->m_currentIndex = index;
d->updateTabs();
updateGeometry();
emit currentChanged(index);
}
void DockAreaTabBar::closeTab(int index)
{
if (index < 0 || index >= count())
return;
auto dockWidgetTab = tab(index);
if (dockWidgetTab->isHidden())
return;
emit tabCloseRequested(index);
}
} // namespace ADS } // namespace ADS

View File

@@ -86,6 +86,18 @@ public:
*/ */
DockWidgetTab *tab(int index) const; DockWidgetTab *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 * Filters the tab widget events
*/ */

View File

@@ -44,10 +44,10 @@ class DockAreaTitleBarPrivate
{ {
public: public:
DockAreaTitleBar *q; DockAreaTitleBar *q;
QPointer<TitleBarButtonType> m_tabsMenuButton; QPointer<TitleBarButton> m_tabsMenuButton;
QPointer<TitleBarButtonType> m_autoHideButton; QPointer<TitleBarButton> m_autoHideButton;
QPointer<TitleBarButtonType> m_undockButton; QPointer<TitleBarButton> m_undockButton;
QPointer<TitleBarButtonType> m_closeButton; QPointer<TitleBarButton> m_closeButton;
QBoxLayout *m_layout = nullptr; QBoxLayout *m_layout = nullptr;
DockAreaWidget *m_dockArea = nullptr; DockAreaWidget *m_dockArea = nullptr;
DockAreaTabBar *m_tabBar = nullptr; DockAreaTabBar *m_tabBar = nullptr;
@@ -306,9 +306,9 @@ void DockAreaTitleBarPrivate::startFloating(const QPoint &offset)
qApp->postEvent(m_dockArea, new QEvent((QEvent::Type) internal::g_dockedWidgetDragStartEvent)); qApp->postEvent(m_dockArea, new QEvent((QEvent::Type) internal::g_dockedWidgetDragStartEvent));
} }
TitleBarButton::TitleBarButton(bool visible, QWidget *parent) TitleBarButton::TitleBarButton(bool showInTitleBar, QWidget *parent)
: TitleBarButtonType(parent) : TitleBarButtonType(parent)
, m_visible(visible) , m_showInTitleBar(showInTitleBar)
, m_hideWhenDisabled( , m_hideWhenDisabled(
DockAreaTitleBarPrivate::testConfigFlag(DockManager::DockAreaHideDisabledButtons)) DockAreaTitleBarPrivate::testConfigFlag(DockManager::DockAreaHideDisabledButtons))
{ {
@@ -317,8 +317,8 @@ TitleBarButton::TitleBarButton(bool visible, QWidget *parent)
void TitleBarButton::setVisible(bool visible) void TitleBarButton::setVisible(bool visible)
{ {
// 'visible' can stay 'true' if and only if this button is configured to generaly visible: // 'visible' can stay 'true' if and only if this button is configured to generally visible:
visible = visible && m_visible; visible = visible && m_showInTitleBar;
// 'visible' can stay 'true' unless: this button is configured to be invisible when it // 'visible' can stay 'true' unless: this button is configured to be invisible when it
// is disabled and it is currently disabled: // is disabled and it is currently disabled:
@@ -328,6 +328,14 @@ void TitleBarButton::setVisible(bool visible)
Super::setVisible(visible); Super::setVisible(visible);
} }
void TitleBarButton::setShowInTitleBar(bool show)
{
m_showInTitleBar = show;
if (!show)
setVisible(false);
}
bool TitleBarButton::event(QEvent *event) bool TitleBarButton::event(QEvent *event)
{ {
if (QEvent::EnabledChange == event->type() && m_hideWhenDisabled) { if (QEvent::EnabledChange == event->type() && m_hideWhenDisabled) {
@@ -524,7 +532,7 @@ void DockAreaTitleBar::onAutoHideToActionClicked()
d->m_dockArea->toggleAutoHide((SideBarLocation) location); d->m_dockArea->toggleAutoHide((SideBarLocation) location);
} }
QAbstractButton *DockAreaTitleBar::button(eTitleBarButton which) const TitleBarButton *DockAreaTitleBar::button(eTitleBarButton which) const
{ {
switch (which) { switch (which) {
case TitleBarButtonTabsMenu: case TitleBarButtonTabsMenu:
@@ -733,4 +741,19 @@ QString DockAreaTitleBar::titleBarButtonToolTip(eTitleBarButton button) const
return QString(); return QString();
} }
void DockAreaTitleBar::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->m_dockArea->dockContainer();
if (dockContainer->isFloating() && dockContainer->dockAreaCount() == 1
&& !d->m_dockArea->isAutoHide())
return;
if (!d->m_dockArea->features().testFlag(DockWidget::DockWidgetFloatable))
return;
d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive);
}
} // namespace ADS } // namespace ADS

View File

@@ -30,17 +30,22 @@ using TitleBarButtonType = QToolButton;
class TitleBarButton : public TitleBarButtonType class TitleBarButton : public TitleBarButtonType
{ {
Q_OBJECT Q_OBJECT
bool m_visible = true; bool m_showInTitleBar = true;
bool m_hideWhenDisabled = false; bool m_hideWhenDisabled = false;
public: public:
using Super = TitleBarButtonType; using Super = TitleBarButtonType;
TitleBarButton(bool visible = true, QWidget *parent = nullptr); TitleBarButton(bool showInTitleBar = true, QWidget *parent = nullptr);
/** /**
* Adjust this visibility change request with our internal settings: * Adjust this visibility change request with our internal settings:
*/ */
void setVisible(bool visible) override; void setVisible(bool visible) override;
/**
* Configures, if the title bar button should be shown in title bar
*/
void setShowInTitleBar(bool show);
protected: protected:
/** /**
* Handle EnabledChanged signal to set button invisible if the configured * Handle EnabledChanged signal to set button invisible if the configured
@@ -139,7 +144,7 @@ public:
/** /**
* Returns the button corresponding to the given title bar button identifier * Returns the button corresponding to the given title bar button identifier
*/ */
QAbstractButton *button(eTitleBarButton which) const; TitleBarButton *button(eTitleBarButton which) const;
/** /**
* Returns the auto hide title label, used when the dock area is expanded and auto hidden * Returns the auto hide title label, used when the dock area is expanded and auto hidden
@@ -181,6 +186,11 @@ public:
*/ */
QString titleBarButtonToolTip(eTitleBarButton button) const; QString titleBarButtonToolTip(eTitleBarButton button) const;
/**
* Moves the dock area into its own floating widget if the area DockWidgetFloatable flag is true.
*/
void setAreaFloating();
signals: signals:
/** /**
* This signal is emitted if a tab in the tab bar is clicked by the user * This signal is emitted if a tab in the tab bar is clicked by the user

View File

@@ -374,6 +374,7 @@ void DockAreaWidget::setAutoHideDockContainer(AutoHideDockContainer *autoHideDoc
d->m_autoHideDockContainer = autoHideDockContainer; d->m_autoHideDockContainer = autoHideDockContainer;
updateAutoHideButtonCheckState(); updateAutoHideButtonCheckState();
updateTitleBarButtonsToolTips(); updateTitleBarButtonsToolTips();
d->m_titleBar->button(TitleBarButtonAutoHide)->setShowInTitleBar(true);
} }
void DockAreaWidget::addDockWidget(DockWidget *dockWidget) void DockAreaWidget::addDockWidget(DockWidget *dockWidget)
@@ -504,12 +505,7 @@ void DockAreaWidget::hideAreaWithNoVisibleContent()
void DockAreaWidget::onTabCloseRequested(int index) void DockAreaWidget::onTabCloseRequested(int index)
{ {
qCInfo(adsLog) << Q_FUNC_INFO << "index" << index; qCInfo(adsLog) << Q_FUNC_INFO << "index" << index;
auto *currentDockWidget = dockWidget(index); dockWidget(index)->requestCloseDockWidget();
if (currentDockWidget->features().testFlag(DockWidget::DockWidgetDeleteOnClose)
|| currentDockWidget->features().testFlag(DockWidget::CustomCloseHandling))
currentDockWidget->closeDockWidgetInternal();
else
currentDockWidget->toggleView(false);
} }
DockWidget *DockAreaWidget::currentDockWidget() const DockWidget *DockAreaWidget::currentDockWidget() const
@@ -1075,27 +1071,33 @@ SideBarLocation DockAreaWidget::calculateSideTabBarArea() const
return sideTab; return sideTab;
} }
void DockAreaWidget::setAutoHide(bool enable, SideBarLocation location) void DockAreaWidget::setAutoHide(bool enable, SideBarLocation location, int tabIndex)
{ {
if (!isAutoHideFeatureEnabled()) if (!isAutoHideFeatureEnabled())
return; return;
if (!enable) { if (!enable) {
if (isAutoHide()) if (isAutoHide())
autoHideDockContainer()->moveContentsToParent(); d->m_autoHideDockContainer->moveContentsToParent();
return; return;
} }
// If this is already an auto hide container, then move it to new location.
if (isAutoHide()) {
d->m_autoHideDockContainer->moveToNewSideBarLocation(location, tabIndex);
return;
}
auto area = (SideBarNone == location) ? calculateSideTabBarArea() : location; auto area = (SideBarNone == location) ? calculateSideTabBarArea() : location;
for (const auto DockWidget : openedDockWidgets()) { for (const auto dockWidget : openedDockWidgets()) {
if (enable == isAutoHide()) if (enable == isAutoHide())
continue; continue;
if (!DockWidget->features().testFlag(DockWidget::DockWidgetPinnable)) if (!dockWidget->features().testFlag(DockWidget::DockWidgetPinnable))
continue; continue;
dockContainer()->createAndSetupAutoHideContainer(area, DockWidget); dockContainer()->createAndSetupAutoHideContainer(area, dockWidget, tabIndex++);
} }
} }
@@ -1112,6 +1114,11 @@ void DockAreaWidget::closeOtherAreas()
dockContainer()->closeOtherAreas(this); dockContainer()->closeOtherAreas(this);
} }
void DockAreaWidget::setFloating()
{
d->m_titleBar->setAreaFloating();
}
DockAreaTitleBar *DockAreaWidget::titleBar() const DockAreaTitleBar *DockAreaWidget::titleBar() const
{ {
return d->m_titleBar; return d->m_titleBar;

View File

@@ -369,7 +369,7 @@ public:
* If the dock area is switched to auto hide mode, then all dock widgets * If the dock area is switched to auto hide mode, then all dock widgets
* that are pinable will be added to the sidebar * 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 * Switches the dock area to auto hide mode or vice versa depending on its
@@ -382,6 +382,11 @@ public:
*/ */
void closeOtherAreas(); void closeOtherAreas();
/**
* Moves the dock area into its own floating widget if the area DockWidgetFloatable flag is true.
*/
void setFloating();
signals: signals:
/** /**
* This signal is emitted when user clicks on a tab at an index. * This signal is emitted when user clicks on a tab at an index.

View File

@@ -84,7 +84,7 @@ public:
QList<AutoHideDockContainer *> m_autoHideWidgets; QList<AutoHideDockContainer *> m_autoHideWidgets;
QMap<SideBarLocation, AutoHideSideBar *> m_sideTabBarWidgets; QMap<SideBarLocation, AutoHideSideBar *> m_sideTabBarWidgets;
QGridLayout *m_layout = nullptr; QGridLayout *m_layout = nullptr;
QSplitter *m_rootSplitter = nullptr; DockSplitter *m_rootSplitter = nullptr;
bool m_isFloating = false; bool m_isFloating = false;
DockAreaWidget *m_lastAddedAreaCache[5]; DockAreaWidget *m_lastAddedAreaCache[5];
int m_visibleDockAreaCount = -1; int m_visibleDockAreaCount = -1;
@@ -122,34 +122,51 @@ public:
*/ */
void dropIntoContainer(FloatingDockContainer *floatingWidget, DockWidgetArea area); void dropIntoContainer(FloatingDockContainer *floatingWidget, DockWidgetArea area);
/**
* Drop floating widget into auto hide side bar
*/
void dropIntoAutoHideSideBar(FloatingDockContainer *floatingWidget, DockWidgetArea area);
/**
* Creates a new tab for a widget dropped into the center of a section
*/
void dropIntoCenterOfSection(FloatingDockContainer *floatingWidget,
DockAreaWidget *targetArea,
int tabIndex);
/** /**
* Drop floating widget into dock area * Drop floating widget into dock area
*/ */
void dropIntoSection(FloatingDockContainer *floatingWidget, void dropIntoSection(FloatingDockContainer *floatingWidget,
DockAreaWidget *targetArea, DockAreaWidget *targetArea,
DockWidgetArea area); DockWidgetArea area,
int tabIndex = 0);
/** /**
* Moves the dock widget or dock area given in Widget parameter to a * Moves the dock widget or dock area given in Widget parameter to a new dock widget area.
* new dock widget area
*/ */
void moveToNewSection(QWidget *widget, DockAreaWidget *targetArea, DockWidgetArea area); void moveToNewSection(QWidget *widget,
DockAreaWidget *targetArea,
DockWidgetArea area,
int tabIndex = 0);
/** /**
* Moves the dock widget or dock area given in Widget parameter to a * Moves the dock widget or dock area given in Widget parameter to a dock area in container.
* a dock area in container
*/ */
void moveToContainer(QWidget *widget, DockWidgetArea area); void moveToContainer(QWidget *widget, DockWidgetArea area);
/** /**
* Creates a new tab for a widget dropped into the center of a section * Creates a new tab for a widget dropped into the center of a section
*/ */
void dropIntoCenterOfSection(FloatingDockContainer *floatingWidget, DockAreaWidget *targetArea); void moveIntoCenterOfSection(QWidget *widget, DockAreaWidget *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, DockAreaWidget *targetArea); void moveToAutoHideSideBar(QWidget *widget,
DockWidgetArea area,
int tabIndex = TabDefaultInsertIndex);
/** /**
* Adds new dock areas to the internal dock area list * Adds new dock areas to the internal dock area list
@@ -371,12 +388,12 @@ void DockContainerWidgetPrivate::dropIntoContainer(FloatingDockContainer *floati
auto newDockAreas auto newDockAreas
= floatingDockContainer->findChildren<DockAreaWidget *>(QString(), = floatingDockContainer->findChildren<DockAreaWidget *>(QString(),
Qt::FindChildrenRecursively); Qt::FindChildrenRecursively);
QSplitter *splitter = m_rootSplitter; auto *splitter = m_rootSplitter;
if (m_dockAreas.count() <= 1) { if (m_dockAreas.count() <= 1) {
splitter->setOrientation(insertParam.orientation()); splitter->setOrientation(insertParam.orientation());
} else if (splitter->orientation() != insertParam.orientation()) { } else if (splitter->orientation() != insertParam.orientation()) {
QSplitter *newSplitter = createSplitter(insertParam.orientation()); auto *newSplitter = createSplitter(insertParam.orientation());
QLayoutItem *layoutItem = m_layout->replaceWidget(splitter, newSplitter); QLayoutItem *layoutItem = m_layout->replaceWidget(splitter, newSplitter);
newSplitter->addWidget(splitter); newSplitter->addWidget(splitter);
updateSplitterHandles(newSplitter); updateSplitterHandles(newSplitter);
@@ -411,42 +428,58 @@ void DockContainerWidgetPrivate::dropIntoContainer(FloatingDockContainer *floati
q->dumpLayout(); q->dumpLayout();
} }
void DockContainerWidgetPrivate::dropIntoAutoHideSideBar(FloatingDockContainer *floatingWidget,
DockWidgetArea area)
{
auto sideBarLocation = internal::toSideBarLocation(area);
auto newDockAreas = floatingWidget->findChildren<DockAreaWidget *>(QString(),
Qt::FindChildrenRecursively);
int tabIndex = m_dockManager->containerOverlay()->tabIndexUnderCursor();
for (auto dockArea : newDockAreas) {
auto dockWidgets = dockArea->dockWidgets();
for (auto dockWidget : dockWidgets)
q->createAndSetupAutoHideContainer(sideBarLocation, dockWidget, tabIndex++);
}
}
void DockContainerWidgetPrivate::dropIntoCenterOfSection(FloatingDockContainer *floatingWidget, void DockContainerWidgetPrivate::dropIntoCenterOfSection(FloatingDockContainer *floatingWidget,
DockAreaWidget *targetArea) DockAreaWidget *targetArea,
int tabIndex)
{ {
DockContainerWidget *floatingContainer = floatingWidget->dockContainer(); DockContainerWidget *floatingContainer = floatingWidget->dockContainer();
auto newDockWidgets = floatingContainer->dockWidgets(); auto newDockWidgets = floatingContainer->dockWidgets();
auto topLevelDockArea = floatingContainer->topLevelDockArea(); auto topLevelDockArea = floatingContainer->topLevelDockArea();
int newCurrentIndex = -1; int newCurrentIndex = -1;
tabIndex = qMax(0, tabIndex);
// If the floating widget contains only one single dock are, then the // If the floating widget contains only one single dock are, then the current dock widget of
// current dock widget of the dock area will also be the future current // the dock area will also be the future current dock widget in the drop area.
// dock widget in the drop area.
if (topLevelDockArea) if (topLevelDockArea)
newCurrentIndex = topLevelDockArea->currentIndex(); newCurrentIndex = topLevelDockArea->currentIndex();
for (int i = 0; i < newDockWidgets.count(); ++i) { for (int i = 0; i < newDockWidgets.count(); ++i) {
DockWidget *dockWidget = newDockWidgets[i]; DockWidget *dockWidget = newDockWidgets[i];
targetArea->insertDockWidget(tabIndex + i, dockWidget, false);
targetArea->insertDockWidget(i, dockWidget, false); targetArea->insertDockWidget(i, dockWidget, false);
// If the floating widget contains multiple visible dock areas, then we // If the floating widget contains multiple visible dock areas, then we simply pick the
// simply pick the first visible open dock widget and make it // first visible open dock widget and make it the current one.
// the current one.
if (newCurrentIndex < 0 && !dockWidget->isClosed()) if (newCurrentIndex < 0 && !dockWidget->isClosed())
newCurrentIndex = i; newCurrentIndex = i;
} }
targetArea->setCurrentIndex(newCurrentIndex); targetArea->setCurrentIndex(newCurrentIndex + tabIndex);
targetArea->updateTitleBarVisibility(); targetArea->updateTitleBarVisibility();
return; return;
} }
void DockContainerWidgetPrivate::dropIntoSection(FloatingDockContainer *floatingWidget, void DockContainerWidgetPrivate::dropIntoSection(FloatingDockContainer *floatingWidget,
DockAreaWidget *targetArea, DockAreaWidget *targetArea,
DockWidgetArea area) DockWidgetArea area,
int tabIndex)
{ {
// Dropping into center means all dock widgets in the dropped floating // Dropping into center means all dock widgets in the dropped floating widget will become
// widget will become tabs of the drop area // tabs of the drop area.
if (CenterDockWidgetArea == area) { if (CenterDockWidgetArea == area) {
dropIntoCenterOfSection(floatingWidget, targetArea); dropIntoCenterOfSection(floatingWidget, targetArea, tabIndex);
return; return;
} }
@@ -525,44 +558,15 @@ void DockContainerWidgetPrivate::dropIntoSection(FloatingDockContainer *floating
q->dumpLayout(); q->dumpLayout();
} }
void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget *widget, DockAreaWidget *targetArea)
{
auto droppedDockWidget = qobject_cast<DockWidget *>(widget);
auto droppedArea = qobject_cast<DockAreaWidget *>(widget);
if (droppedDockWidget) {
DockAreaWidget *oldDockArea = droppedDockWidget->dockAreaWidget();
if (oldDockArea == targetArea)
return;
if (oldDockArea)
oldDockArea->removeDockWidget(droppedDockWidget);
targetArea->insertDockWidget(0, droppedDockWidget, true);
} else {
QList<DockWidget *> newDockWidgets = droppedArea->dockWidgets();
int newCurrentIndex = droppedArea->currentIndex();
for (int i = 0; i < newDockWidgets.count(); ++i) {
DockWidget *dockWidget = newDockWidgets[i];
targetArea->insertDockWidget(i, dockWidget, false);
}
targetArea->setCurrentIndex(newCurrentIndex);
droppedArea->dockContainer()->removeDockArea(droppedArea);
droppedArea->deleteLater();
}
targetArea->updateTitleBarVisibility();
return;
}
void DockContainerWidgetPrivate::moveToNewSection(QWidget *widget, void DockContainerWidgetPrivate::moveToNewSection(QWidget *widget,
DockAreaWidget *targetArea, DockAreaWidget *targetArea,
DockWidgetArea area) DockWidgetArea area,
int tabIndex)
{ {
// Dropping into center means all dock widgets in the dropped floating // Dropping into center means all dock widgets in the dropped floating widget will become
// widget will become tabs of the drop area // tabs of the drop area.
if (CenterDockWidgetArea == area) { if (CenterDockWidgetArea == area) {
moveIntoCenterOfSection(widget, targetArea); moveIntoCenterOfSection(widget, targetArea, tabIndex);
return; return;
} }
@@ -612,31 +616,6 @@ void DockContainerWidgetPrivate::moveToNewSection(QWidget *widget,
addDockAreasToList({newDockArea}); addDockAreasToList({newDockArea});
} }
void DockContainerWidgetPrivate::updateSplitterHandles(QSplitter *splitter)
{
if (!m_dockManager->centralWidget() || !splitter)
return;
for (int i = 0; i < splitter->count(); ++i)
splitter->setStretchFactor(i, widgetResizesWithContainer(splitter->widget(i)) ? 1 : 0);
}
bool DockContainerWidgetPrivate::widgetResizesWithContainer(QWidget *widget)
{
if (!m_dockManager->centralWidget())
return true;
auto area = qobject_cast<DockAreaWidget *>(widget);
if (area)
return area->isCentralWidgetArea();
auto innerSplitter = qobject_cast<DockSplitter *>(widget);
if (innerSplitter)
return innerSplitter->isResizingWithContainer();
return false;
}
void DockContainerWidgetPrivate::moveToContainer(QWidget *widget, DockWidgetArea area) void DockContainerWidgetPrivate::moveToContainer(QWidget *widget, DockWidgetArea area)
{ {
DockWidget *droppedDockWidget = qobject_cast<DockWidget *>(widget); DockWidget *droppedDockWidget = qobject_cast<DockWidget *>(widget);
@@ -671,6 +650,92 @@ void DockContainerWidgetPrivate::moveToContainer(QWidget *widget, DockWidgetArea
m_lastAddedAreaCache[areaIdToIndex(area)] = newDockArea; m_lastAddedAreaCache[areaIdToIndex(area)] = newDockArea;
} }
void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget *widget,
DockAreaWidget *targetArea,
int tabIndex)
{
auto droppedDockWidget = qobject_cast<DockWidget *>(widget);
auto droppedArea = qobject_cast<DockAreaWidget *>(widget);
tabIndex = qMax(0, tabIndex);
if (droppedDockWidget) {
DockAreaWidget *oldDockArea = droppedDockWidget->dockAreaWidget();
if (oldDockArea == targetArea)
return;
if (oldDockArea)
oldDockArea->removeDockWidget(droppedDockWidget);
targetArea->insertDockWidget(tabIndex, droppedDockWidget, true);
} else {
QList<DockWidget *> newDockWidgets = droppedArea->dockWidgets();
int newCurrentIndex = droppedArea->currentIndex();
for (int i = 0; i < newDockWidgets.count(); ++i) {
DockWidget *dockWidget = newDockWidgets[i];
targetArea->insertDockWidget(tabIndex + i, dockWidget, false);
}
targetArea->setCurrentIndex(tabIndex + newCurrentIndex);
droppedArea->dockContainer()->removeDockArea(droppedArea);
droppedArea->deleteLater();
}
targetArea->updateTitleBarVisibility();
return;
}
void DockContainerWidgetPrivate::moveToAutoHideSideBar(QWidget *widget,
DockWidgetArea area,
int tabIndex)
{
DockWidget *droppedDockWidget = qobject_cast<DockWidget *>(widget);
DockAreaWidget *droppedDockArea = qobject_cast<DockAreaWidget *>(widget);
auto sideBarLocation = internal::toSideBarLocation(area);
if (droppedDockWidget) {
if (q == droppedDockWidget->dockContainer())
droppedDockWidget->setAutoHide(true, sideBarLocation, tabIndex);
else
q->createAndSetupAutoHideContainer(sideBarLocation, droppedDockWidget, tabIndex);
} else {
if (q == droppedDockArea->dockContainer()) {
droppedDockArea->setAutoHide(true, sideBarLocation, tabIndex);
} else {
for (const auto dockWidget : droppedDockArea->openedDockWidgets()) {
if (!dockWidget->features().testFlag(DockWidget::DockWidgetPinnable))
continue;
q->createAndSetupAutoHideContainer(sideBarLocation, dockWidget, tabIndex++);
}
}
}
}
void DockContainerWidgetPrivate::updateSplitterHandles(QSplitter *splitter)
{
if (!m_dockManager->centralWidget() || !splitter)
return;
for (int i = 0; i < splitter->count(); ++i)
splitter->setStretchFactor(i, widgetResizesWithContainer(splitter->widget(i)) ? 1 : 0);
}
bool DockContainerWidgetPrivate::widgetResizesWithContainer(QWidget *widget)
{
if (!m_dockManager->centralWidget())
return true;
auto area = qobject_cast<DockAreaWidget *>(widget);
if (area)
return area->isCentralWidgetArea();
auto innerSplitter = qobject_cast<DockSplitter *>(widget);
if (innerSplitter)
return innerSplitter->isResizingWithContainer();
return false;
}
void DockContainerWidgetPrivate::addDockAreasToList(const QList<DockAreaWidget *> newDockAreas) void DockContainerWidgetPrivate::addDockAreasToList(const QList<DockAreaWidget *> newDockAreas)
{ {
const int countBefore = m_dockAreas.count(); const int countBefore = m_dockAreas.count();
@@ -740,7 +805,7 @@ void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter &stream, Q
void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter &s) void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter &s)
{ {
for (const auto sideTabBar : m_sideTabBarWidgets.values()) { for (const auto sideTabBar : m_sideTabBarWidgets.values()) {
if (!sideTabBar->tabCount()) if (!sideTabBar->count())
continue; continue;
sideTabBar->saveState(s); sideTabBar->saveState(s);
@@ -896,11 +961,11 @@ bool DockContainerWidgetPrivate::restoreSideBar(DockingStateReader &stateReader,
if (!dockWidget || testing) if (!dockWidget || testing)
continue; continue;
auto sideBar = q->sideTabBar(area); auto sideBar = q->autoHideSideBar(area);
AutoHideDockContainer *autoHideContainer; AutoHideDockContainer *autoHideContainer;
if (dockWidget->isAutoHide()) { if (dockWidget->isAutoHide()) {
autoHideContainer = dockWidget->autoHideDockContainer(); autoHideContainer = dockWidget->autoHideDockContainer();
if (autoHideContainer->sideBar() != sideBar) if (autoHideContainer->autoHideSideBar() != sideBar)
sideBar->addAutoHideWidget(autoHideContainer); sideBar->addAutoHideWidget(autoHideContainer);
} else { } else {
autoHideContainer = sideBar->insertDockWidget(-1, dockWidget); autoHideContainer = sideBar->insertDockWidget(-1, dockWidget);
@@ -931,7 +996,7 @@ void DockContainerWidgetPrivate::addDockArea(DockAreaWidget *newDockArea, DockWi
if (m_dockAreas.count() <= 1) if (m_dockAreas.count() <= 1)
m_rootSplitter->setOrientation(insertParam.orientation()); m_rootSplitter->setOrientation(insertParam.orientation());
QSplitter *splitter = m_rootSplitter; auto *splitter = m_rootSplitter;
if (splitter->orientation() == insertParam.orientation()) { if (splitter->orientation() == insertParam.orientation()) {
insertWidgetIntoSplitter(splitter, newDockArea, insertParam.append()); insertWidgetIntoSplitter(splitter, newDockArea, insertParam.append());
updateSplitterHandles(splitter); updateSplitterHandles(splitter);
@@ -939,7 +1004,7 @@ void DockContainerWidgetPrivate::addDockArea(DockAreaWidget *newDockArea, DockWi
splitter->show(); splitter->show();
} else { } else {
QSplitter *newSplitter = createSplitter(insertParam.orientation()); auto *newSplitter = createSplitter(insertParam.orientation());
if (insertParam.append()) { if (insertParam.append()) {
QLayoutItem *layoutItem = m_layout->replaceWidget(splitter, newSplitter); QLayoutItem *layoutItem = m_layout->replaceWidget(splitter, newSplitter);
newSplitter->addWidget(splitter); newSplitter->addWidget(splitter);
@@ -1108,7 +1173,8 @@ DockAreaWidget *DockContainerWidget::addDockWidget(DockWidgetArea area,
} }
AutoHideDockContainer *DockContainerWidget::createAndSetupAutoHideContainer(SideBarLocation area, AutoHideDockContainer *DockContainerWidget::createAndSetupAutoHideContainer(SideBarLocation area,
DockWidget *dockWidget) DockWidget *dockWidget,
int tabIndex)
{ {
if (!DockManager::testAutoHideConfigFlag(DockManager::AutoHideFeatureEnabled)) { if (!DockManager::testAutoHideConfigFlag(DockManager::AutoHideFeatureEnabled)) {
Q_ASSERT_X(false, Q_ASSERT_X(false,
@@ -1121,7 +1187,7 @@ AutoHideDockContainer *DockContainerWidget::createAndSetupAutoHideContainer(Side
d->m_dockManager); // Auto hide Dock Container needs a valid dock manager d->m_dockManager); // Auto hide Dock Container needs a valid dock manager
} }
return sideTabBar(area)->insertDockWidget(-1, dockWidget); return autoHideSideBar(area)->insertDockWidget(tabIndex, dockWidget);
} }
void DockContainerWidget::removeDockWidget(DockWidget *dockWidget) void DockContainerWidget::removeDockWidget(DockWidget *dockWidget)
@@ -1210,7 +1276,7 @@ void DockContainerWidget::removeDockArea(DockAreaWidget *area)
} }
QWidget *widget = splitter->widget(0); QWidget *widget = splitter->widget(0);
QSplitter *childSplitter = qobject_cast<QSplitter *>(widget); auto *childSplitter = qobject_cast<DockSplitter *>(widget);
// If the one and only content widget of the splitter is not a splitter // If the one and only content widget of the splitter is not a splitter
// then we are finished // then we are finished
if (!childSplitter) { if (!childSplitter) {
@@ -1227,7 +1293,7 @@ void DockContainerWidget::removeDockArea(DockAreaWidget *area)
qCInfo(adsLog) << "RootSplitter replaced by child splitter"; qCInfo(adsLog) << "RootSplitter replaced by child splitter";
} else if (splitter->count() == 1) { } else if (splitter->count() == 1) {
qCInfo(adsLog) << "Replacing splitter with content"; qCInfo(adsLog) << "Replacing splitter with content";
QSplitter *parentSplitter = internal::findParent<QSplitter *>(splitter); auto *parentSplitter = internal::findParent<QSplitter *>(splitter);
auto sizes = parentSplitter->sizes(); auto sizes = parentSplitter->sizes();
QWidget *widget = splitter->widget(0); QWidget *widget = splitter->widget(0);
widget->setParent(this); widget->setParent(this);
@@ -1299,11 +1365,12 @@ void DockContainerWidget::dropFloatingWidget(FloatingDockContainer *floatingWidg
qCInfo(adsLog) << Q_FUNC_INFO; qCInfo(adsLog) << Q_FUNC_INFO;
DockWidget *singleDroppedDockWidget = floatingWidget->topLevelDockWidget(); DockWidget *singleDroppedDockWidget = floatingWidget->topLevelDockWidget();
DockWidget *singleDockWidget = topLevelDockWidget(); DockWidget *singleDockWidget = topLevelDockWidget();
DockAreaWidget *dockArea = dockAreaAt(targetPosition);
auto dropArea = InvalidDockWidgetArea; auto dropArea = InvalidDockWidgetArea;
auto containerDropArea = d->m_dockManager->containerOverlay()->dropAreaUnderCursor(); auto containerDropArea = d->m_dockManager->containerOverlay()->dropAreaUnderCursor();
bool dropped = false; bool dropped = false;
DockAreaWidget *dockArea = dockAreaAt(targetPosition);
// Mouse is over dock area
if (dockArea) { if (dockArea) {
auto dropOverlay = d->m_dockManager->dockAreaOverlay(); auto dropOverlay = d->m_dockManager->dockAreaOverlay();
dropOverlay->setAllowedAreas(dockArea->allowedAreas()); dropOverlay->setAllowedAreas(dockArea->allowedAreas());
@@ -1313,24 +1380,27 @@ void DockContainerWidget::dropFloatingWidget(FloatingDockContainer *floatingWidg
if (dropArea != InvalidDockWidgetArea) { if (dropArea != InvalidDockWidgetArea) {
qCInfo(adsLog) << "Dock Area Drop Content: " << dropArea; qCInfo(adsLog) << "Dock Area Drop Content: " << dropArea;
d->dropIntoSection(floatingWidget, dockArea, dropArea); int tabIndex = d->m_dockManager->dockAreaOverlay()->tabIndexUnderCursor();
d->dropIntoSection(floatingWidget, dockArea, dropArea, tabIndex);
dropped = true; dropped = true;
} }
} }
// mouse is over container // Mouse is over container or auto hide side bar
if (InvalidDockWidgetArea == dropArea) { if (InvalidDockWidgetArea == dropArea && InvalidDockWidgetArea != containerDropArea) {
dropArea = containerDropArea; qCInfo(adsLog) << "Container Drop Content: " << containerDropArea;
qCInfo(adsLog) << "Container Drop Content: " << dropArea;
if (dropArea != InvalidDockWidgetArea) { if (internal::isSideBarArea(containerDropArea))
d->dropIntoContainer(floatingWidget, dropArea); d->dropIntoAutoHideSideBar(floatingWidget, containerDropArea);
else
d->dropIntoContainer(floatingWidget, containerDropArea);
dropped = true; dropped = true;
} }
}
// Remove the auto hide widgets from the FloatingWidget and insert them into this widget // Remove the auto hide widgets from the FloatingWidget and insert them into this widget
for (auto autohideWidget : floatingWidget->dockContainer()->autoHideWidgets()) { for (auto autohideWidget : floatingWidget->dockContainer()->autoHideWidgets()) {
auto sideBar = sideTabBar(autohideWidget->sideBarLocation()); auto sideBar = autoHideSideBar(autohideWidget->sideBarLocation());
sideBar->addAutoHideWidget(autohideWidget); sideBar->addAutoHideWidget(autohideWidget);
} }
@@ -1356,11 +1426,14 @@ void DockContainerWidget::dropFloatingWidget(FloatingDockContainer *floatingWidg
void DockContainerWidget::dropWidget(QWidget *widget, void DockContainerWidget::dropWidget(QWidget *widget,
DockWidgetArea dropArea, DockWidgetArea dropArea,
DockAreaWidget *targetAreaWidget) DockAreaWidget *targetAreaWidget,
int tabIndex)
{ {
DockWidget *singleDockWidget = topLevelDockWidget(); DockWidget *singleDockWidget = topLevelDockWidget();
if (targetAreaWidget) if (targetAreaWidget)
d->moveToNewSection(widget, targetAreaWidget, dropArea); d->moveToNewSection(widget, targetAreaWidget, dropArea, tabIndex);
else if (internal::isSideBarArea(dropArea))
d->moveToAutoHideSideBar(widget, dropArea, tabIndex);
else else
d->moveToContainer(widget, dropArea); d->moveToContainer(widget, dropArea);
@@ -1466,7 +1539,7 @@ bool DockContainerWidget::restoreState(DockingStateReader &stateReader, bool tes
d->m_layout->replaceWidget(d->m_rootSplitter, newRootSplitter); d->m_layout->replaceWidget(d->m_rootSplitter, newRootSplitter);
QSplitter *oldRoot = d->m_rootSplitter; QSplitter *oldRoot = d->m_rootSplitter;
d->m_rootSplitter = qobject_cast<QSplitter *>(newRootSplitter); d->m_rootSplitter = qobject_cast<DockSplitter *>(newRootSplitter);
oldRoot->deleteLater(); oldRoot->deleteLater();
return true; return true;
@@ -1621,7 +1694,7 @@ void DockContainerWidget::closeOtherAreas(DockAreaWidget *keepOpenArea)
} }
} }
AutoHideSideBar *DockContainerWidget::sideTabBar(SideBarLocation area) const AutoHideSideBar *DockContainerWidget::autoHideSideBar(SideBarLocation area) const
{ {
return d->m_sideTabBarWidgets[area]; return d->m_sideTabBarWidgets[area];
} }
@@ -1639,7 +1712,17 @@ QRect DockContainerWidget::contentRectGlobal() const
if (!d->m_rootSplitter) if (!d->m_rootSplitter)
return QRect(); return QRect();
return internal::globalGeometry(d->m_rootSplitter); if (d->m_rootSplitter->hasVisibleContent()) {
return d->m_rootSplitter->geometry();
} else {
auto contentRect = rect();
contentRect.adjust(autoHideSideBar(SideBarLeft)->sizeHint().width(),
autoHideSideBar(SideBarTop)->sizeHint().height(),
-autoHideSideBar(SideBarRight)->sizeHint().width(),
-autoHideSideBar(SideBarBottom)->sizeHint().height());
return contentRect;
}
} }
DockManager *DockContainerWidget::dockManager() const DockManager *DockContainerWidget::dockManager() const

View File

@@ -74,7 +74,8 @@ protected:
* Returns nullptr if you try and insert into an area where the configuration is not enabled * Returns nullptr if you try and insert into an area where the configuration is not enabled
*/ */
AutoHideDockContainer *createAndSetupAutoHideContainer(SideBarLocation area, AutoHideDockContainer *createAndSetupAutoHideContainer(SideBarLocation area,
DockWidget *dockWidget); DockWidget *dockWidget,
int tabIndex = -1);
/** /**
* Helper function for creation of the root splitter * Helper function for creation of the root splitter
@@ -98,7 +99,10 @@ protected:
* a nullptr, then the DropArea indicates the drop area in the given * a nullptr, then the DropArea indicates the drop area in the given
* TargetAreaWidget * TargetAreaWidget
*/ */
void dropWidget(QWidget *widget, DockWidgetArea dropArea, DockAreaWidget *targetAreaWidget); void dropWidget(QWidget *widget,
DockWidgetArea dropArea,
DockAreaWidget *targetAreaWidget,
int tabIndex = -1);
/** /**
* Adds the given dock area to this container widget * Adds the given dock area to this container widget
@@ -299,7 +303,7 @@ public:
/** /**
* Returns the side tab widget for the given area * Returns the side tab widget for the given area
*/ */
AutoHideSideBar *sideTabBar(SideBarLocation area) const; AutoHideSideBar *autoHideSideBar(SideBarLocation area) const;
/** /**
* Access function for auto hide widgets * Access function for auto hide widgets

View File

@@ -48,6 +48,8 @@ struct DockAreaWidgetPrivate;
class IconProvider; class IconProvider;
class DockFocusController; class DockFocusController;
class AutoHideSideBar; class AutoHideSideBar;
class AutoHideTab;
struct AutoHideTabPrivate;
inline constexpr QStringView workspaceFolderName{u"workspaces"}; inline constexpr QStringView workspaceFolderName{u"workspaces"};
inline constexpr QStringView workspaceFileExtension{u"wrk"}; inline constexpr QStringView workspaceFileExtension{u"wrk"};
@@ -84,6 +86,8 @@ private:
friend class DockAreaTitleBar; friend class DockAreaTitleBar;
friend class AutoHideDockContainer; friend class AutoHideDockContainer;
friend AutoHideSideBar; friend AutoHideSideBar;
friend AutoHideTab;
friend AutoHideTabPrivate;
public: public:
using Super = DockContainerWidget; using Super = DockContainerWidget;
@@ -182,8 +186,8 @@ public:
= 0x40, ///< Close button of an auto hide container collapses the dock instead of hiding it completely = 0x40, ///< Close button of an auto hide container collapses the dock instead of hiding it completely
DefaultAutoHideConfig DefaultAutoHideConfig
= AutoHideFeatureEnabled = AutoHideFeatureEnabled | DockAreaHasAutoHideButton
| DockAreaHasAutoHideButton ///< the default configuration for left and right side bars | AutoHideCloseButtonCollapsesDock ///< the default configuration for left and right side bars
}; };
Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag) Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag)

View File

@@ -3,8 +3,12 @@
#include "dockoverlay.h" #include "dockoverlay.h"
#include "autohidesidebar.h"
#include "dockareatabbar.h"
#include "dockareatitlebar.h" #include "dockareatitlebar.h"
#include "dockareawidget.h" #include "dockareawidget.h"
#include "dockcontainerwidget.h"
#include "dockmanager.h"
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
@@ -25,6 +29,10 @@
namespace ADS { namespace ADS {
static const int g_autoHideAreaWidth = 32;
static const int g_autoHideAreaMouseZone = 8;
static const int g_invalidTabIndex = -2;
/** /**
* Private data class of DockOverlay * Private data class of DockOverlay
*/ */
@@ -39,6 +47,7 @@ public:
bool m_dropPreviewEnabled = true; bool m_dropPreviewEnabled = true;
DockOverlay::eMode m_mode = DockOverlay::ModeDockAreaOverlay; DockOverlay::eMode m_mode = DockOverlay::ModeDockAreaOverlay;
QRect m_dropAreaRect; QRect m_dropAreaRect;
int m_tabIndex = g_invalidTabIndex;
/** /**
* Private data constructor * Private data constructor
@@ -46,6 +55,16 @@ public:
DockOverlayPrivate(DockOverlay *parent) DockOverlayPrivate(DockOverlay *parent)
: q(parent) : q(parent)
{} {}
/**
* 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);
}; };
/** /**
@@ -132,7 +151,15 @@ public:
label->setObjectName("DockWidgetAreaLabel"); label->setObjectName("DockWidgetAreaLabel");
const qreal metric = dropIndicatorWidth(label); const qreal metric = dropIndicatorWidth(label);
const QSizeF size(metric, metric); 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);
}
label->setPixmap(createHighDpiDropIndicatorPixmap(size, dockWidgetArea, mode)); label->setPixmap(createHighDpiDropIndicatorPixmap(size, dockWidgetArea, mode));
label->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); label->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
@@ -159,6 +186,11 @@ public:
{ {
const QColor borderColor = iconColor(DockOverlayCross::FrameColor); const QColor borderColor = iconColor(DockOverlayCross::FrameColor);
const QColor backgroundColor = iconColor(DockOverlayCross::WindowBackgroundColor); const QColor backgroundColor = iconColor(DockOverlayCross::WindowBackgroundColor);
QColor overlayColor = iconColor(DockOverlayCross::OverlayColor);
if (overlayColor.alpha() == 255)
overlayColor.setAlpha(64);
const double devicePixelRatio = q->window()->devicePixelRatioF(); const double devicePixelRatio = q->window()->devicePixelRatioF();
const QSizeF pixmapSize = size * devicePixelRatio; const QSizeF pixmapSize = size * devicePixelRatio;
QPixmap pixmap(pixmapSize.toSize()); QPixmap pixmap(pixmapSize.toSize());
@@ -223,19 +255,18 @@ public:
} }
const QSizeF baseSize = baseRect.size(); const QSizeF baseSize = baseRect.size();
if (DockOverlay::ModeContainerOverlay == mode && dockWidgetArea != CenterDockWidgetArea) { bool isOuterContainerArea = (DockOverlay::ModeContainerOverlay == mode)
&& (dockWidgetArea != CenterDockWidgetArea)
&& !internal::isSideBarArea(dockWidgetArea);
if (isOuterContainerArea)
baseRect = areaRect; baseRect = areaRect;
}
painter.fillRect(baseRect, backgroundColor); painter.fillRect(baseRect, backgroundColor);
if (areaRect.isValid()) { if (areaRect.isValid()) {
pen = painter.pen(); pen = painter.pen();
pen.setColor(borderColor); pen.setColor(borderColor);
QColor color = iconColor(DockOverlayCross::OverlayColor); painter.setBrush(overlayColor);
if (color.alpha() == 255) {
color.setAlpha(64);
}
painter.setBrush(color);
painter.setPen(Qt::NoPen); painter.setPen(Qt::NoPen);
painter.drawRect(areaRect); painter.drawRect(areaRect);
@@ -264,7 +295,7 @@ public:
painter.restore(); painter.restore();
// Draw arrow for outer container drop indicators // Draw arrow for outer container drop indicators
if (DockOverlay::ModeContainerOverlay == mode && dockWidgetArea != CenterDockWidgetArea) { if (isOuterContainerArea) {
QRectF arrowRect; QRectF arrowRect;
arrowRect.setSize(baseSize); arrowRect.setSize(baseSize);
arrowRect.setWidth(arrowRect.width() / 4.6); arrowRect.setWidth(arrowRect.width() / 4.6);
@@ -302,6 +333,26 @@ public:
} }
}; // class DockOverlayCrossPrivate }; // class DockOverlayCrossPrivate
int DockOverlayPrivate::sideBarOverlaySize(SideBarLocation sideBarLocation)
{
auto container = qobject_cast<DockContainerWidget *>(m_targetWidget.data());
auto sideBar = container->autoHideSideBar(sideBarLocation);
if (!sideBar || !sideBar->isVisibleTo(container))
return g_autoHideAreaWidth;
else
return (sideBar->orientation() == Qt::Horizontal) ? sideBar->height() : sideBar->width();
}
int DockOverlayPrivate::sideBarMouseZone(SideBarLocation sideBarLocation)
{
auto container = qobject_cast<DockContainerWidget *>(m_targetWidget.data());
auto sideBar = container->autoHideSideBar(sideBarLocation);
if (!sideBar || !sideBar->isVisibleTo(container))
return g_autoHideAreaMouseZone;
else
return (sideBar->orientation() == Qt::Horizontal) ? sideBar->height() : sideBar->width();
}
DockOverlay::DockOverlay(QWidget *parent, eMode mode) DockOverlay::DockOverlay(QWidget *parent, eMode mode)
: QFrame(parent) : QFrame(parent)
, d(new DockOverlayPrivate(this)) , d(new DockOverlayPrivate(this))
@@ -338,6 +389,14 @@ void DockOverlay::setAllowedAreas(DockWidgetAreas areas)
d->m_cross->reset(); d->m_cross->reset();
} }
void DockOverlay::setAllowedArea(DockWidgetArea area, bool enable)
{
auto areasOld = d->m_allowedAreas;
d->m_allowedAreas.setFlag(area, enable);
if (areasOld != d->m_allowedAreas)
d->m_cross->reset();
}
DockWidgetAreas DockOverlay::allowedAreas() const DockWidgetAreas DockOverlay::allowedAreas() const
{ {
return d->m_allowedAreas; return d->m_allowedAreas;
@@ -345,21 +404,62 @@ DockWidgetAreas DockOverlay::allowedAreas() const
DockWidgetArea DockOverlay::dropAreaUnderCursor() const DockWidgetArea DockOverlay::dropAreaUnderCursor() const
{ {
d->m_tabIndex = g_invalidTabIndex;
if (!d->m_targetWidget)
return InvalidDockWidgetArea;
DockWidgetArea result = d->m_cross->cursorLocation(); DockWidgetArea result = d->m_cross->cursorLocation();
if (result != InvalidDockWidgetArea) if (result != InvalidDockWidgetArea)
return result; return result;
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(d->m_targetWidget.data()); auto cursorPos = QCursor::pos();
if (!dockArea) auto dockArea = qobject_cast<DockAreaWidget *>(d->m_targetWidget.data());
if (!dockArea
&& DockManager::autoHideConfigFlags().testFlag(DockManager::AutoHideFeatureEnabled)) {
auto rectangle = rect();
const QPoint pos = mapFromGlobal(QCursor::pos());
if ((pos.x() < d->sideBarMouseZone(SideBarLeft))
&& d->m_allowedAreas.testFlag(LeftAutoHideArea)) {
result = LeftAutoHideArea;
} else if (pos.x() > (rectangle.width() - d->sideBarMouseZone(SideBarRight))
&& d->m_allowedAreas.testFlag(RightAutoHideArea)) {
result = RightAutoHideArea;
} else if (pos.y() < d->sideBarMouseZone(SideBarTop)
&& d->m_allowedAreas.testFlag(TopAutoHideArea)) {
result = TopAutoHideArea;
} else if (pos.y() > (rectangle.height() - d->sideBarMouseZone(SideBarBottom))
&& d->m_allowedAreas.testFlag(BottomAutoHideArea)) {
result = BottomAutoHideArea;
}
auto sideBarLocation = internal::toSideBarLocation(result);
if (sideBarLocation != SideBarNone) {
auto Container = qobject_cast<DockContainerWidget *>(d->m_targetWidget.data());
auto SideBar = Container->autoHideSideBar(sideBarLocation);
if (SideBar->isVisible()) {
d->m_tabIndex = SideBar->tabInsertIndexAt(SideBar->mapFromGlobal(cursorPos));
}
}
return result; return result;
} else if (!dockArea) {
return result;
}
if (dockArea->allowedAreas().testFlag(CenterDockWidgetArea) && !dockArea->titleBar()->isHidden() 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->m_tabIndex = tabBar->tabInsertIndexAt(tabBar->mapFromGlobal(cursorPos));
return CenterDockWidgetArea; return CenterDockWidgetArea;
}
return result; return result;
} }
int DockOverlay::tabIndexUnderCursor() const
{
return d->m_tabIndex;
}
DockWidgetArea DockOverlay::visibleDropAreaUnderCursor() const DockWidgetArea DockOverlay::visibleDropAreaUnderCursor() const
{ {
if (isHidden() || !d->m_dropPreviewEnabled) if (isHidden() || !d->m_dropPreviewEnabled)
@@ -416,6 +516,7 @@ bool DockOverlay::dropPreviewEnabled() const
void DockOverlay::paintEvent(QPaintEvent *event) void DockOverlay::paintEvent(QPaintEvent *event)
{ {
Q_UNUSED(event) Q_UNUSED(event)
// Draw rect based on location // Draw rect based on location
if (!d->m_dropPreviewEnabled) { if (!d->m_dropPreviewEnabled) {
d->m_dropAreaRect = QRect(); d->m_dropAreaRect = QRect();
@@ -442,9 +543,22 @@ void DockOverlay::paintEvent(QPaintEvent *event)
case CenterDockWidgetArea: case CenterDockWidgetArea:
rectangle = rect(); rectangle = rect();
break; break;
case LeftAutoHideArea:
rectangle.setWidth(d->sideBarOverlaySize(SideBarLeft));
break;
case RightAutoHideArea:
rectangle.setX(rectangle.width() - d->sideBarOverlaySize(SideBarRight));
break;
case TopAutoHideArea:
rectangle.setHeight(d->sideBarOverlaySize(SideBarTop));
break;
case BottomAutoHideArea:
rectangle.setY(rectangle.height() - d->sideBarOverlaySize(SideBarBottom));
break;
default: default:
return; return;
} }
QPainter painter(this); QPainter painter(this);
QColor color = palette().color(QPalette::Active, QPalette::Highlight); QColor color = palette().color(QPalette::Active, QPalette::Highlight);
QPen pen = painter.pen(); QPen pen = painter.pen();

View File

@@ -52,11 +52,26 @@ public:
*/ */
DockWidgetAreas allowedAreas() const; DockWidgetAreas allowedAreas() const;
/**
* Enable / disable a certain area
*/
void setAllowedArea(DockWidgetArea area, bool enable);
/** /**
* Returns the drop area under the current cursor location * Returns the drop area under the current cursor location
*/ */
DockWidgetArea dropAreaUnderCursor() const; 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 * This function returns the same like dropAreaUnderCursor() if this
* overlay is not hidden and if drop preview is enabled and returns * overlay is not hidden and if drop preview is enabled and returns

View File

@@ -409,6 +409,11 @@ bool DockWidget::isAutoHide() const
return !d->m_sideTabWidget.isNull(); return !d->m_sideTabWidget.isNull();
} }
SideBarLocation DockWidget::autoHideLocation() const
{
return isAutoHide() ? autoHideDockContainer()->sideBarLocation() : SideBarNone;
}
bool DockWidget::isFloating() const bool DockWidget::isFloating() const
{ {
if (!isInFloatingContainer()) if (!isInFloatingContainer())
@@ -746,6 +751,9 @@ void DockWidget::setFloating()
if (isClosed()) if (isClosed())
return; return;
if (isAutoHide())
dockAreaWidget()->setFloating();
else
d->m_tabWidget->detachDockWidget(); d->m_tabWidget->detachDockWidget();
} }
@@ -764,6 +772,15 @@ void DockWidget::closeDockWidget()
closeDockWidgetInternal(true); closeDockWidgetInternal(true);
} }
void DockWidget::requestCloseDockWidget()
{
if (features().testFlag(DockWidget::DockWidgetDeleteOnClose)
|| features().testFlag(DockWidget::CustomCloseHandling))
closeDockWidgetInternal(false);
else
toggleView(false);
}
bool DockWidget::closeDockWidgetInternal(bool forceClose) bool DockWidget::closeDockWidgetInternal(bool forceClose)
{ {
if (!forceClose) if (!forceClose)
@@ -859,21 +876,24 @@ void DockWidget::raise()
} }
} }
void DockWidget::setAutoHide(bool enable, SideBarLocation location) void DockWidget::setAutoHide(bool enable, SideBarLocation location, int tabIndex)
{ {
if (!DockManager::testAutoHideConfigFlag(DockManager::AutoHideFeatureEnabled)) if (!DockManager::testAutoHideConfigFlag(DockManager::AutoHideFeatureEnabled))
return; return;
// Do nothing if nothing changes // Do nothing if nothing changes
if (enable == isAutoHide()) if (enable == isAutoHide() && location == autoHideLocation())
return; return;
auto dockArea = dockAreaWidget(); auto dockArea = dockAreaWidget();
if (!enable) { if (!enable) {
dockArea->setAutoHide(false); dockArea->setAutoHide(false);
} else if (isAutoHide()) {
autoHideDockContainer()->moveToNewSideBarLocation(location);
} else { } else {
auto area = (SideBarNone == location) ? dockArea->calculateSideTabBarArea() : location; auto area = (SideBarNone == location) ? dockArea->calculateSideTabBarArea() : location;
dockContainer()->createAndSetupAutoHideContainer(area, this); dockContainer()->createAndSetupAutoHideContainer(area, this, tabIndex);
} }
} }

View File

@@ -338,16 +338,20 @@ public:
bool isAutoHide() const; bool isAutoHide() const;
/** /**
* Returns the auto hide dock container of this dock widget * Returns the auto hide dock container of this dock widget or 0 if there is none.
* or 0 if there is none
*/ */
AutoHideDockContainer *autoHideDockContainer() const; AutoHideDockContainer *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. * This property holds whether the dock widget is floating.
* A dock widget is only floating, if it is the one and only widget inside * A dock widget is only floating, if it is the one and only widget inside of a floating
* of a floating container. If there are more than one dock widget in a * container. If there are more than one dock widget in a floating container, the all dock
* floating container, the all dock widgets are docked and not floating. * widgets are docked and not floating.
*/ */
bool isFloating() const; bool isFloating() const;
@@ -546,23 +550,28 @@ public: // reimplements QFrame
*/ */
void closeDockWidget(); void closeDockWidget();
/**
* Request closing of the dock widget.
* For DockWidget with default close handling, the function does the same like clodeDockWidget()
* but if the flag CustomCloseHandling is set, the function only emits the closeRequested() signal.
*/
void requestCloseDockWidget();
/** /**
* Shows the widget in full-screen mode. * Shows the widget in full-screen mode.
* Normally this function only affects windows. To make the interface * Normally this function only affects windows. To make the interface compatible to QDockWidget,
* compatible to QDockWidget, this function also maximizes a floating * this function also maximizes a floating dock widget.
* dock widget.
* *
* \note Full-screen mode works fine under Windows, but has certain * \note Full-screen mode works fine under Windows, but has certain problems (doe not work)
* problems (doe not work) under X (Linux). These problems are due to * under X (Linux). These problems are due to limitations of the ICCCM protocol that specifies
* limitations of the ICCCM protocol that specifies the communication * the communication between X11 clients and the window manager. ICCCM simply does not
* between X11 clients and the window manager. ICCCM simply does not
* understand the concept of non-decorated full-screen windows. * understand the concept of non-decorated full-screen windows.
*/ */
void showFullScreen(); void showFullScreen();
/** /**
* This function complements showFullScreen() to restore the widget * This function complements showFullScreen() to restore the widget after it has been in full
* after it has been in full screen mode. * screen mode.
*/ */
void showNormal(); void showNormal();
@@ -570,11 +579,10 @@ public: // reimplements QFrame
* Sets the dock widget into auto hide mode if this feature is enabled * Sets the dock widget into auto hide mode if this feature is enabled
* via CDockManager::setAutoHideFlags(CDockManager::AutoHideFeatureEnabled) * 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 * Switches the dock widget to auto hide mode or vice versa depending on its current state.
* current state.
*/ */
void toggleAutoHide(SideBarLocation location = SideBarNone); void toggleAutoHide(SideBarLocation location = SideBarNone);

View File

@@ -58,7 +58,6 @@ public:
TabButton *m_closeButton = nullptr; TabButton *m_closeButton = nullptr;
QPoint m_tabDragStartPosition; QPoint m_tabDragStartPosition;
QSize m_iconSize; QSize m_iconSize;
bool m_mousePressed = false;
/** /**
* Private data constructor * Private data constructor
@@ -340,7 +339,6 @@ void DockWidgetTab::mousePressEvent(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
event->accept(); event->accept();
d->m_mousePressed = true;
d->saveDragStartMousePosition(event->globalPosition().toPoint()); d->saveDragStartMousePosition(event->globalPosition().toPoint());
d->m_dragState = DraggingMousePressed; d->m_dragState = DraggingMousePressed;
if (DockManager::testConfigFlag(DockManager::FocusHighlighting)) { if (DockManager::testConfigFlag(DockManager::FocusHighlighting)) {
@@ -356,7 +354,6 @@ void DockWidgetTab::mousePressEvent(QMouseEvent *event)
void DockWidgetTab::mouseReleaseEvent(QMouseEvent *event) void DockWidgetTab::mouseReleaseEvent(QMouseEvent *event)
{ {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
d->m_mousePressed = false;
auto currentDragState = d->m_dragState; auto currentDragState = d->m_dragState;
d->m_globalDragStartMousePosition = QPoint(); d->m_globalDragStartMousePosition = QPoint();
d->m_dragStartMousePosition = QPoint(); d->m_dragStartMousePosition = QPoint();

View File

@@ -167,11 +167,6 @@ public:
*/ */
void setIconSize(const QSize &size); void setIconSize(const QSize &size);
/**
* Returns true, if the tab has been clicked and the mouse is currently pressed.
*/
bool mousePressed() const;
void setVisible(bool visible) override; void setVisible(bool visible) override;
signals: signals:

View File

@@ -455,6 +455,9 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
if (!overlay->dropOverlayRect().isValid()) if (!overlay->dropOverlayRect().isValid())
overlay = m_dockManager->dockAreaOverlay(); overlay = m_dockManager->dockAreaOverlay();
// 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 (!internal::isSideBarArea(overlay->dropAreaUnderCursor())) {
// Resize the floating widget to the size of the highlighted drop area rectangle // Resize the floating widget to the size of the highlighted drop area rectangle
QRect rect = overlay->dropOverlayRect(); QRect rect = overlay->dropOverlayRect();
int frameWidth = (q->frameSize().width() - q->rect().width()) / 2; int frameWidth = (q->frameSize().width() - q->rect().width()) / 2;
@@ -465,6 +468,7 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent()
q->setGeometry(QRect(topLeft, QSize(rect.width(), rect.height() - titleBarHeight))); q->setGeometry(QRect(topLeft, QSize(rect.width(), rect.height() - titleBarHeight)));
QApplication::processEvents(); QApplication::processEvents();
} }
}
m_dropContainer->dropFloatingWidget(q, QCursor::pos()); m_dropContainer->dropFloatingWidget(q, QCursor::pos());
} }
@@ -510,10 +514,23 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &globalPositi
} }
int visibleDockAreas = topContainer->visibleDockAreaCount(); int visibleDockAreas = topContainer->visibleDockAreaCount();
containerOverlay->setAllowedAreas(visibleDockAreas > 1 ? OuterDockAreas : AllDockAreas);
DockWidgetAreas allowedContainerAreas = (visibleDockAreas > 1) ? OuterDockAreas : AllDockAreas;
auto dockArea = topContainer->dockAreaAt(globalPosition);
// 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 (m_dockContainer->features().testFlag(DockWidget::DockWidgetPinnable))
allowedContainerAreas |= AutoHideDockAreas;
containerOverlay->setAllowedAreas(allowedContainerAreas);
DockWidgetArea containerArea = containerOverlay->showOverlay(topContainer); DockWidgetArea containerArea = containerOverlay->showOverlay(topContainer);
containerOverlay->enableDropPreview(containerArea != InvalidDockWidgetArea); containerOverlay->enableDropPreview(containerArea != InvalidDockWidgetArea);
auto dockArea = topContainer->dockAreaAt(globalPosition);
if (dockArea && dockArea->isVisible() && visibleDockAreas > 0) { if (dockArea && dockArea->isVisible() && visibleDockAreas > 0) {
dockAreaOverlay->enableDropPreview(true); dockAreaOverlay->enableDropPreview(true);
dockAreaOverlay->setAllowedAreas((visibleDockAreas == 1) ? NoDockWidgetArea dockAreaOverlay->setAllowedAreas((visibleDockAreas == 1) ? NoDockWidgetArea

View File

@@ -4,6 +4,7 @@
#include "floatingdragpreview.h" #include "floatingdragpreview.h"
#include "ads_globals_p.h" #include "ads_globals_p.h"
#include "ads_globals.h"
#include "autohidedockcontainer.h" #include "autohidedockcontainer.h"
#include "dockareawidget.h" #include "dockareawidget.h"
#include "dockcontainerwidget.h" #include "dockcontainerwidget.h"
@@ -31,6 +32,7 @@ class FloatingDragPreviewPrivate
public: public:
FloatingDragPreview *q; FloatingDragPreview *q;
QWidget *m_content = nullptr; QWidget *m_content = nullptr;
DockWidget::DockWidgetFeatures m_contentFeatures;
DockAreaWidget *m_contentSourceArea = nullptr; DockAreaWidget *m_contentSourceArea = nullptr;
QPoint m_dragStartMousePosition; QPoint m_dragStartMousePosition;
DockManager *m_dockManager = nullptr; DockManager *m_dockManager = nullptr;
@@ -70,19 +72,35 @@ public:
void createFloatingWidget(); void createFloatingWidget();
/** /**
* Returns true, if the content is floatable. * Returns true, if the content is floatable
*/ */
bool isContentFloatable() const bool isContentFloatable() const
{
return m_contentFeatures.testFlag(DockWidget::DockWidgetFloatable);
}
/**
* Returns true, if the content is pinnable
*/
bool isContentPinnable() const
{
return m_contentFeatures.testFlag(DockWidget::DockWidgetPinnable);
}
/**
* Returns the content features
*/
DockWidget::DockWidgetFeatures contentFeatures() const
{ {
DockWidget *dockWidget = qobject_cast<DockWidget *>(m_content); DockWidget *dockWidget = qobject_cast<DockWidget *>(m_content);
if (dockWidget && dockWidget->features().testFlag(DockWidget::DockWidgetFloatable)) if (dockWidget)
return true; return dockWidget->features();
DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(m_content); DockAreaWidget *dockArea = qobject_cast<DockAreaWidget *>(m_content);
if (dockArea && dockArea->features().testFlag(DockWidget::DockWidgetFloatable)) if (dockArea)
return true; return dockArea->features();
return false; return DockWidget::DockWidgetFeatures();
} }
}; // class FloatingDragPreviewPrivate }; // class FloatingDragPreviewPrivate
@@ -107,8 +125,6 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &globalPosition
m_dropContainer = topContainer; m_dropContainer = topContainer;
auto containerOverlay = m_dockManager->containerOverlay(); auto containerOverlay = m_dockManager->containerOverlay();
auto dockAreaOverlay = m_dockManager->dockAreaOverlay(); auto dockAreaOverlay = m_dockManager->dockAreaOverlay();
auto dockDropArea = dockAreaOverlay->dropAreaUnderCursor();
auto containerDropArea = containerOverlay->dropAreaUnderCursor();
if (!topContainer) { if (!topContainer) {
containerOverlay->hideOverlay(); containerOverlay->hideOverlay();
@@ -119,6 +135,9 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &globalPosition
return; return;
} }
auto dockDropArea = dockAreaOverlay->dropAreaUnderCursor();
auto containerDropArea = containerOverlay->dropAreaUnderCursor();
int visibleDockAreas = topContainer->visibleDockAreaCount(); int visibleDockAreas = topContainer->visibleDockAreaCount();
// Include the overlay widget we're dragging as a visible widget // Include the overlay widget we're dragging as a visible widget
@@ -126,8 +145,22 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &globalPosition
if (dockAreaWidget && dockAreaWidget->isAutoHide()) if (dockAreaWidget && dockAreaWidget->isAutoHide())
visibleDockAreas++; visibleDockAreas++;
containerOverlay->setAllowedAreas(visibleDockAreas > 1 ? OuterDockAreas : AllDockAreas); DockWidgetAreas allowedContainerAreas = (visibleDockAreas > 1) ? OuterDockAreas : AllDockAreas;
auto dockArea = topContainer->dockAreaAt(globalPosition); auto dockArea = topContainer->dockAreaAt(globalPosition);
// 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 if (dockArea && dockArea->isVisible() && visibleDockAreas >= 0
&& dockArea != m_contentSourceArea) { && dockArea != m_contentSourceArea) {
dockAreaOverlay->enableDropPreview(true); dockAreaOverlay->enableDropPreview(true);
@@ -149,10 +182,10 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &globalPosition
dockAreaOverlay->hideOverlay(); dockAreaOverlay->hideOverlay();
// If there is only one single visible dock area in a container, then it does not make // 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 // sense to show a dock overlay because the dock area would be removed and inserted at
// the same position. // the same position. Only auto hide area is allowed.
if (visibleDockAreas == 1) if (visibleDockAreas == 1)
containerOverlay->hideOverlay(); containerOverlay->setAllowedAreas(AutoHideDockAreas);
else
containerOverlay->showOverlay(topContainer); containerOverlay->showOverlay(topContainer);
if (dockArea == m_contentSourceArea && InvalidDockWidgetArea == containerDropArea) if (dockArea == m_contentSourceArea && InvalidDockWidgetArea == containerDropArea)
@@ -199,6 +232,7 @@ FloatingDragPreview::FloatingDragPreview(QWidget *content, QWidget *parent)
, d(new FloatingDragPreviewPrivate(this)) , d(new FloatingDragPreviewPrivate(this))
{ {
d->m_content = content; d->m_content = content;
d->m_contentFeatures = d->contentFeatures();
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
if (DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) { if (DockManager::testConfigFlag(DockManager::DragPreviewHasWindowFrame)) {
setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint); setWindowFlags(Qt::Window | Qt::WindowMaximizeButtonHint | Qt::WindowCloseButtonHint);
@@ -288,22 +322,25 @@ void FloatingDragPreview::finishDragging()
// Non floatable auto hide widgets should stay in its current auto hide state if they are // Non floatable auto hide widgets should stay in its current auto hide state if they are
// dragged into a floating window. // dragged into a floating window.
if (validDropArea || d->isContentFloatable()) if (validDropArea || d->isContentFloatable())
cleanupAutoHideContainerWidget(); cleanupAutoHideContainerWidget(containerDropArea);
if (!d->m_dropContainer) { if (!d->m_dropContainer) {
d->createFloatingWidget(); d->createFloatingWidget();
} else if (dockDropArea != InvalidDockWidgetArea) { } else if (dockDropArea != InvalidDockWidgetArea) {
d->m_dropContainer->dropWidget(d->m_content, d->m_dropContainer->dropWidget(d->m_content,
dockDropArea, dockDropArea,
d->m_dropContainer->dockAreaAt(QCursor::pos())); d->m_dropContainer->dockAreaAt(QCursor::pos()),
d->m_dockManager->dockAreaOverlay()->tabIndexUnderCursor());
} else if (containerDropArea != InvalidDockWidgetArea) { } else if (containerDropArea != InvalidDockWidgetArea) {
// If there is only one single dock area, and we drop into the center then we tabify the // 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. // dropped widget into the only visible dock area.
if (d->m_dropContainer->visibleDockAreaCount() <= 1 if (d->m_dropContainer->visibleDockAreaCount() <= 1
&& CenterDockWidgetArea == containerDropArea) && CenterDockWidgetArea == containerDropArea)
d->m_dropContainer->dropWidget(d->m_content, d->m_dropContainer
->dropWidget(d->m_content,
containerDropArea, containerDropArea,
d->m_dropContainer->dockAreaAt(QCursor::pos())); d->m_dropContainer->dockAreaAt(QCursor::pos()),
d->m_dockManager->containerOverlay()->tabIndexUnderCursor());
else else
d->m_dropContainer->dropWidget(d->m_content, containerDropArea, nullptr); d->m_dropContainer->dropWidget(d->m_content, containerDropArea, nullptr);
} else { } else {
@@ -315,15 +352,24 @@ void FloatingDragPreview::finishDragging()
d->m_dockManager->dockAreaOverlay()->hideOverlay(); d->m_dockManager->dockAreaOverlay()->hideOverlay();
} }
void FloatingDragPreview::cleanupAutoHideContainerWidget() void FloatingDragPreview::cleanupAutoHideContainerWidget(DockWidgetArea containerDropArea)
{ {
auto droppedDockWidget = qobject_cast<DockWidget *>(d->m_content); auto droppedDockWidget = qobject_cast<DockWidget *>(d->m_content);
if (droppedDockWidget && droppedDockWidget->autoHideDockContainer())
droppedDockWidget->autoHideDockContainer()->cleanupAndDelete();
auto droppedArea = qobject_cast<DockAreaWidget *>(d->m_content); auto droppedArea = qobject_cast<DockAreaWidget *>(d->m_content);
if (droppedArea && droppedArea->autoHideDockContainer())
droppedArea->autoHideDockContainer()->cleanupAndDelete(); auto autoHideContainer = droppedDockWidget ? droppedDockWidget->autoHideDockContainer()
: droppedArea->autoHideDockContainer();
if (!autoHideContainer)
return;
// 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 (internal::isSideBarArea(containerDropArea)
&& (d->m_dropContainer == autoHideContainer->dockContainer()))
return;
autoHideContainer->cleanupAndDelete();
} }
void FloatingDragPreview::paintEvent(QPaintEvent *event) void FloatingDragPreview::paintEvent(QPaintEvent *event)
@@ -333,6 +379,7 @@ void FloatingDragPreview::paintEvent(QPaintEvent *event)
return; return;
QPainter painter(this); QPainter painter(this);
painter.setOpacity(0.6);
if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap)) if (DockManager::testConfigFlag(DockManager::DragPreviewShowsContentPixmap))
painter.drawPixmap(QPoint(0, 0), d->m_contentPreviewPixmap); painter.drawPixmap(QPoint(0, 0), d->m_contentPreviewPixmap);

View File

@@ -89,7 +89,7 @@ public: // implements AbstractFloatingWidget
/** /**
* Cleanup auto hide container if the dragged widget has one. * Cleanup auto hide container if the dragged widget has one.
*/ */
void cleanupAutoHideContainerWidget(); void cleanupAutoHideContainerWidget(DockWidgetArea containerDropArea);
signals: signals:
/** /**