Improved support when moving widgets out of FloatingWidget

This commit is contained in:
Uwe Kindler 2017-03-02 11:43:48 +01:00
parent df85c8bee0
commit fac5661280
10 changed files with 710 additions and 88 deletions

View File

@ -43,6 +43,8 @@
#include "DockWidget.h" #include "DockWidget.h"
#include "DockWidgetTitleBar.h" #include "DockWidgetTitleBar.h"
#include "FloatingDockContainer.h" #include "FloatingDockContainer.h"
#include "DockManager.h"
#include "DockOverlay.h"
#include <iostream> #include <iostream>
@ -104,7 +106,8 @@ protected:
} }
/** /**
* Starts floating the complete docking area including all dock widgets * Starts floating the complete docking area including all dock widgets,
* if it is not the last dock area in a floating widget
*/ */
virtual void mouseMoveEvent(QMouseEvent* ev) override virtual void mouseMoveEvent(QMouseEvent* ev) override
{ {
@ -113,11 +116,24 @@ protected:
{ {
return; return;
} }
// 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
if (DockArea->dockContainer()->isFloating() && DockArea->dockContainer()->dockAreaCount() == 1)
{
return;
}
if (!this->geometry().contains(ev->pos())) if (!this->geometry().contains(ev->pos()))
{ {
std::cout << "CTabsScrollArea::startFloating" << std::endl;
QSize Size = DockArea->size(); QSize Size = DockArea->size();
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(DockArea); CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(DockArea);
FloatingWidget->startFloating(m_DragStartMousePos, Size); FloatingWidget->startFloating(m_DragStartMousePos, Size);
auto Overlay = DockArea->dockManager()->containerOverlay();
Overlay->setAllowedAreas(OuterDockAreas);
} }
return; return;
@ -142,6 +158,7 @@ struct DockAreaWidgetPrivate
{ {
CDockAreaWidget* _this; CDockAreaWidget* _this;
QBoxLayout* Layout; QBoxLayout* Layout;
QFrame* TitleBar;
QBoxLayout* TopLayout; QBoxLayout* TopLayout;
QStackedLayout* ContentsLayout; QStackedLayout* ContentsLayout;
QScrollArea* TabsScrollArea; QScrollArea* TabsScrollArea;
@ -207,6 +224,12 @@ struct DockAreaWidgetPrivate
* been removed * been removed
*/ */
void updateTabsMenu(); void updateTabsMenu();
/**
* Updates the tab bar visibility depending on the number of dock widgets
* in this area
*/
void updateTabBar();
}; };
// struct DockAreaWidgetPrivate // struct DockAreaWidgetPrivate
@ -222,10 +245,12 @@ DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) :
//============================================================================ //============================================================================
void DockAreaWidgetPrivate::createTabBar() void DockAreaWidgetPrivate::createTabBar()
{ {
TitleBar = new QFrame(_this);
TopLayout = new QBoxLayout(QBoxLayout::LeftToRight); TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
TopLayout->setContentsMargins(0, 0, 0, 0); TopLayout->setContentsMargins(0, 0, 0, 0);
TopLayout->setSpacing(0); TopLayout->setSpacing(0);
Layout->addLayout(TopLayout); TitleBar->setLayout(TopLayout);
Layout->addWidget(TitleBar);
TabsScrollArea = new CTabsScrollArea(_this); TabsScrollArea = new CTabsScrollArea(_this);
TopLayout->addWidget(TabsScrollArea, 1); TopLayout->addWidget(TabsScrollArea, 1);
@ -263,6 +288,26 @@ void DockAreaWidgetPrivate::createTabBar()
} }
//============================================================================
void DockAreaWidgetPrivate::updateTabBar()
{
CDockContainerWidget* Container = _this->dockContainer();
if (!Container)
{
return;
}
if (Container->isFloating() && (Container->dockAreaCount() == 1) && (_this->count() == 1))
{
TitleBar->setVisible(false);
}
else
{
TitleBar->setVisible(true);
}
}
//============================================================================ //============================================================================
void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget, void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget,
QMenu* menu) QMenu* menu)
@ -376,6 +421,8 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
dockContainer()->removeDockArea(this); dockContainer()->removeDockArea(this);
this->deleteLater(); this->deleteLater();
} }
d->updateTabBar();
} }
@ -540,6 +587,14 @@ void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action)
int Index = d->TabsMenuButton->menu()->actions().indexOf(Action); int Index = d->TabsMenuButton->menu()->actions().indexOf(Action);
setCurrentIndex(Index); setCurrentIndex(Index);
} }
//============================================================================
void CDockAreaWidget::updateDockArea()
{
d->updateTabBar();
}
} // namespace ads } // namespace ads
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -134,6 +134,11 @@ public slots:
* This sets the index position of the current tab page. * This sets the index position of the current tab page.
*/ */
void setCurrentIndex(int index); void setCurrentIndex(int index);
/**
* Updates the dock area layout and components visibility
*/
void updateDockArea();
}; // class DockAreaWidget }; // class DockAreaWidget
} }
// namespace ads // namespace ads

View File

@ -39,6 +39,7 @@
#include "DockManager.h" #include "DockManager.h"
#include "DockAreaWidget.h" #include "DockAreaWidget.h"
#include "DockWidget.h" #include "DockWidget.h"
#include "FloatingDockContainer.h"
#include "ads_globals.h" #include "ads_globals.h"
#include <iostream> #include <iostream>
@ -72,6 +73,7 @@ struct DockContainerWidgetPrivate
unsigned int zOrderIndex = 0; unsigned int zOrderIndex = 0;
QList<CDockAreaWidget*> DockAreas; QList<CDockAreaWidget*> DockAreas;
QGridLayout* Layout = nullptr; QGridLayout* Layout = nullptr;
bool isFloating = false;
/** /**
* Private data constructor * Private data constructor
@ -170,6 +172,7 @@ void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockW
} }
DockAreas.append(NewDockArea); DockAreas.append(NewDockArea);
NewDockArea->updateDockArea();
} }
@ -212,6 +215,8 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p
QFrame(parent), QFrame(parent),
d(new DockContainerWidgetPrivate(this)) d(new DockContainerWidgetPrivate(this))
{ {
d->isFloating = dynamic_cast<CFloatingDockContainer*>(parent) != 0;
//setStyleSheet("background: green;"); //setStyleSheet("background: green;");
d->DockManager = DockManager; d->DockManager = DockManager;
if (DockManager != this) if (DockManager != this)
@ -306,6 +311,7 @@ void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget,
//============================================================================ //============================================================================
void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
{ {
std::cout << "CDockContainerWidget::removeDockArea" << std::endl;
d->DockAreas.removeAll(area); d->DockAreas.removeAll(area);
QSplitter* Splitter = internal::findParent<QSplitter*>(area); QSplitter* Splitter = internal::findParent<QSplitter*>(area);
area->setParent(0); area->setParent(0);
@ -345,6 +351,20 @@ CDockAreaWidget* CDockContainerWidget::dockAreaAt(const QPoint& GlobalPos) const
return 0; return 0;
} }
//============================================================================
bool CDockContainerWidget::isFloating() const
{
return d->isFloating;
}
//============================================================================
int CDockContainerWidget::dockAreaCount() const
{
return d->DockAreas.count();
}
} // namespace ads } // namespace ads
//--------------------------------------------------------------------------- //---------------------------------------------------------------------------

View File

@ -104,6 +104,16 @@ public:
* dock area at this position * dock area at this position
*/ */
CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const; CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const;
/**
* Returns the number of dock areas in this container
*/
int dockAreaCount() const;
/**
* This function returns true, if this container is in a floating widget
*/
bool isFloating() const;
}; // class DockContainerWidget }; // class DockContainerWidget
} // namespace ads } // namespace ads
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

View File

@ -77,8 +77,8 @@ CDockManager::CDockManager(QWidget *parent) :
MainWindow->setCentralWidget(this); MainWindow->setCentralWidget(this);
} }
d->DockAreaOverlay = new CDockOverlay(this); d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay);
d->ContainerOverlay = new CDockOverlay(this); d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
d->Containers.append(this); d->Containers.append(this);
} }

View File

@ -17,61 +17,185 @@
******************************************************************************/ ******************************************************************************/
//============================================================================
/// \file DropOverlay.cpp
/// \author Uwe Kindler
/// \date 01.03.2017
/// \brief Implementation of CDropOverlay class
//============================================================================
//============================================================================ //============================================================================
// INCLUDES // INCLUDES
//============================================================================ //============================================================================
#include "DockOverlay.h" #include "DockOverlay.h"
#include <QPointer>
#include <QPaintEvent>
#include <QResizeEvent>
#include <QMoveEvent>
#include <QPainter>
#include <QGridLayout>
#include <QCursor>
#include <QIcon>
#include <QLabel>
#include <QtGlobal>
#include <QDebug>
#include <iostream> #include <iostream>
namespace ads namespace ads
{ {
//============================================================================
static QPixmap createDropIndicatorPixmap(const QPalette& pal, const QSizeF& size, DockWidgetArea DockWidgetArea)
{
const QColor borderColor = pal.color(QPalette::Active, QPalette::Highlight);
const QColor backgroundColor = pal.color(QPalette::Active, QPalette::Base);
const QColor areaBackgroundColor = pal.color(QPalette::Active, QPalette::Highlight).lighter(150);
QPixmap pm(size.width(), size.height());
pm.fill(QColor(0, 0, 0, 0));
QPainter p(&pm);
QPen pen = p.pen();
QRectF baseRect(pm.rect());
// Fill
p.fillRect(baseRect, backgroundColor);
// Drop area rect.
p.save();
QRectF areaRect;
QLineF areaLine;
QLinearGradient gradient;
switch (DockWidgetArea)
{
case TopDockWidgetArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.bottomLeft(), areaRect.bottomRight());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.bottomLeft());
break;
case RightDockWidgetArea:
areaRect = QRectF(baseRect.width() * .5f, baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topLeft(), areaRect.bottomLeft());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.topRight());
break;
case BottomDockWidgetArea:
areaRect = QRectF(baseRect.x(), baseRect.height() * .5f, baseRect.width(), baseRect.height() * .5f);
areaLine = QLineF(areaRect.topLeft(), areaRect.topRight());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.bottomLeft());
break;
case LeftDockWidgetArea:
areaRect = QRectF(baseRect.x(), baseRect.y(), baseRect.width() * .5f, baseRect.height());
areaLine = QLineF(areaRect.topRight(), areaRect.bottomRight());
gradient.setStart(areaRect.topLeft());
gradient.setFinalStop(areaRect.topRight());
break;
default:
break;
}
if (areaRect.isValid())
{
gradient.setColorAt(0.f, areaBackgroundColor);
gradient.setColorAt(1.f, areaBackgroundColor.lighter(120));
p.fillRect(areaRect, gradient);
pen = p.pen();
pen.setColor(borderColor);
pen.setStyle(Qt::DashLine);
p.setPen(pen);
p.drawLine(areaLine);
}
p.restore();
p.save();
pen = p.pen();
pen.setColor(borderColor);
pen.setWidth(1);
p.setPen(pen);
p.drawRect(baseRect.adjusted(0, 0, -pen.width(), -pen.width()));
p.restore();
return pm;
}
//============================================================================
QWidget* createDropIndicatorWidget(DockWidgetArea DockWidgetArea)
{
QLabel* l = new QLabel();
l->setObjectName("DockWidgetAreaLabel");
const qreal metric = static_cast<qreal>(l->fontMetrics().height()) * 2.f;
const QSizeF size(metric, metric);
l->setPixmap(createDropIndicatorPixmap(l->palette(), size, DockWidgetArea));
l->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
l->setAttribute(Qt::WA_TranslucentBackground);
return l;
}
/** /**
* Private data class of CDropOverlay class (pimpl) * Private data class of CDockOverlay
*/ */
struct DockOverlayPrivate struct DockOverlayPrivate
{ {
CDockOverlay* _this; CDockOverlay* _this;
DockWidgetAreas AllowedAreas = InvalidDockWidgetArea;
CDockOverlayCross* Cross;
QPointer<QWidget> TargetWidget;
QRect TargetRect;
DockWidgetArea LastLocation = InvalidDockWidgetArea;
/** /**
* Private data constructor * Private data constructor
*/ */
DockOverlayPrivate(CDockOverlay* _public); DockOverlayPrivate(CDockOverlay* _public) : _this(_public) {}
}; };
// struct DropOverlayPrivate
//============================================================================ /**
DockOverlayPrivate::DockOverlayPrivate(CDockOverlay* _public) : * Private data of CDockOverlayCross class
_this(_public) */
struct DockOverlayCrossPrivate
{ {
CDockOverlayCross* _this;
CDockOverlay::eMode Mode = CDockOverlay::ModeDockAreaOverlay;
CDockOverlay* DockOverlay;
QHash<DockWidgetArea, QWidget*> DropIndicatorWidgets;
QGridLayout* GridLayout;
/**
* Private data constructor
*/
DockOverlayCrossPrivate(CDockOverlayCross* _public) : _this(_public) {}
/**
*
* @param area
* @return
*/
QPoint areaGridPosition(const DockWidgetArea area);
};
}
//============================================================================ //============================================================================
CDockOverlay::CDockOverlay(QWidget *parent) : CDockOverlay::CDockOverlay(QWidget* parent, eMode Mode) :
QFrame(parent), QFrame(parent),
d(new DockOverlayPrivate(this)) d(new DockOverlayPrivate(this))
{ {
setStyleSheet("ads--CDockOverlay {background: palette(highlight);}"); d->Cross = new CDockOverlayCross(this);
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setWindowOpacity(0.2); setWindowOpacity(0.2);
setWindowTitle("DockOverlay"); setWindowTitle("DockOverlay");
//setAttribute(Qt::WA_NoSystemBackground); setAttribute(Qt::WA_NoSystemBackground);
//setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_TranslucentBackground);
setAttribute(Qt::WA_TransparentForMouseEvents); QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
setWindowFlags(windowFlags() | Qt::WindowTransparentForInput); l->setSpacing(0);
setLayout(l);
d->Cross->setupOverlayCross(Mode);
d->Cross->setVisible(false);
setVisible(false); setVisible(false);
} }
//============================================================================ //============================================================================
CDockOverlay::~CDockOverlay() CDockOverlay::~CDockOverlay()
{ {
@ -79,22 +203,344 @@ CDockOverlay::~CDockOverlay()
} }
//============================================================================
void CDockOverlay::setAllowedAreas(DockWidgetAreas areas)
{
if (areas == d->AllowedAreas)
return;
d->AllowedAreas = areas;
d->Cross->reset();
}
//============================================================================
DockWidgetAreas CDockOverlay::allowedAreas() const
{
return d->AllowedAreas;
}
//============================================================================
DockWidgetArea CDockOverlay::dropAreaUnderCursor() const
{
return d->Cross->cursorLocation();
}
//============================================================================ //============================================================================
DockWidgetArea CDockOverlay::showOverlay(QWidget* target) DockWidgetArea CDockOverlay::showOverlay(QWidget* target)
{ {
std::cout << "CDockOverlay::showOverlay" << std::endl; //std::cout << "CDockOverlay::showDockOverlay(QWidget* target)" << std::endl;
if (d->TargetWidget == target)
{
qInfo() << "_target == target";
// Hint: We could update geometry of overlay here.
DockWidgetArea da = dropAreaUnderCursor();
if (da != d->LastLocation)
{
qInfo() << "repaint()";
repaint();
d->LastLocation = da;
}
return da;
}
d->TargetWidget = target;
d->TargetRect = QRect();
d->LastLocation = InvalidDockWidgetArea;
// Move it over the target.
resize(target->size()); resize(target->size());
move(target->mapToGlobal(target->rect().topLeft())); move(target->mapToGlobal(target->rect().topLeft()));
this->show(); show();
return NoDockWidgetArea; return dropAreaUnderCursor();
} }
//============================================================================
void CDockOverlay::showOverlay(QWidget* target, const QRect& targetAreaRect)
{
qInfo() << "CDockOverlay::showDockOverlay(QWidget* target, const QRect& targetAreaRect)";
if (d->TargetWidget == target && d->TargetRect == targetAreaRect)
{
return;
}
//hideDockOverlay();
d->TargetWidget = target;
d->TargetRect = targetAreaRect;
d->LastLocation = InvalidDockWidgetArea;
// Move it over the target's area.
resize(targetAreaRect.size());
move(target->mapToGlobal(QPoint(targetAreaRect.x(), targetAreaRect.y())));
show();
return;
}
//============================================================================ //============================================================================
void CDockOverlay::hideOverlay() void CDockOverlay::hideOverlay()
{ {
this->hide(); qInfo() << "hideDockOverlay() _fullAreaDrop = false";
hide();
d->TargetWidget.clear();
d->TargetRect = QRect();
d->LastLocation = InvalidDockWidgetArea;
} }
} // namespace ads
//---------------------------------------------------------------------------
// EOF DropOverlay.cpp //============================================================================
void CDockOverlay::paintEvent(QPaintEvent*)
{
// Draw rect based on location
QRect r = rect();
const DockWidgetArea da = dropAreaUnderCursor();
std::cout << "CursorLocation: " << dropAreaUnderCursor() << std::endl;
switch (da)
{
case TopDockWidgetArea: r.setHeight(r.height() / 2); break;
case RightDockWidgetArea: r.setX(r.width() / 2); break;
case BottomDockWidgetArea: r.setY(r.height() / 2); break;
case LeftDockWidgetArea: r.setWidth(r.width() / 2); break;
case CenterDockWidgetArea: r = rect();break;
default: return;
}
QPainter painter(this);
QColor Color = palette().color(QPalette::Active, QPalette::Highlight);
painter.fillRect(r, QBrush(Color, Qt::Dense4Pattern));
painter.setBrush(QBrush(Color));
painter.drawRect(r);
}
//============================================================================
void CDockOverlay::showEvent(QShowEvent*)
{
d->Cross->show();
QWidget* w = parentWidget() ? parentWidget() : d->TargetWidget.data();
QRect WidgetRect = w->rect();
QPoint Pos(WidgetRect.left(), WidgetRect.center().y());
}
//============================================================================
void CDockOverlay::hideEvent(QHideEvent*)
{
d->Cross->hide();
}
//============================================================================
void CDockOverlay::resizeEvent(QResizeEvent* e)
{
qInfo() << "CDockOverlay::resizeEvent" << e->size();
d->Cross->resize(e->size());
}
//============================================================================
void CDockOverlay::moveEvent(QMoveEvent* e)
{
qInfo() << "CDockOverlay::moveEvent" << e->pos();
d->Cross->move(e->pos());
}
//============================================================================
static int areaAlignment(const DockWidgetArea area)
{
switch (area)
{
case TopDockWidgetArea: return (int) Qt::AlignHCenter | Qt::AlignBottom;
case RightDockWidgetArea: return (int) Qt::AlignLeft | Qt::AlignVCenter;
case BottomDockWidgetArea: return (int) Qt::AlignHCenter | Qt::AlignTop;
case LeftDockWidgetArea: return (int) Qt::AlignRight | Qt::AlignVCenter;
case CenterDockWidgetArea: return (int) Qt::AlignCenter;
default: return Qt::AlignCenter;
}
}
//============================================================================
// DockOverlayCrossPrivate
//============================================================================
QPoint DockOverlayCrossPrivate::areaGridPosition(const DockWidgetArea area)
{
if (CDockOverlay::ModeDockAreaOverlay == Mode)
{
switch (area)
{
case TopDockWidgetArea: return QPoint(1, 2);
case RightDockWidgetArea: return QPoint(2, 3);
case BottomDockWidgetArea: return QPoint(3, 2);
case LeftDockWidgetArea: return QPoint(2, 1);
case CenterDockWidgetArea: return QPoint(2, 2);
default: return QPoint();
}
}
else
{
switch (area)
{
case TopDockWidgetArea: return QPoint(0, 2);
case RightDockWidgetArea: return QPoint(2, 4);
case BottomDockWidgetArea: return QPoint(4, 2);
case LeftDockWidgetArea: return QPoint(2, 0);
case CenterDockWidgetArea: return QPoint(2, 2);
default: return QPoint();
}
}
}
//============================================================================
CDockOverlayCross::CDockOverlayCross(CDockOverlay* overlay) :
QWidget(overlay->parentWidget()),
d(new DockOverlayCrossPrivate(this))
{
d->DockOverlay = overlay;
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
setWindowTitle("DockOverlayCross");
setAttribute(Qt::WA_TranslucentBackground);
d->GridLayout = new QGridLayout();
d->GridLayout->setSpacing(6);
setLayout(d->GridLayout);
}
//============================================================================
CDockOverlayCross::~CDockOverlayCross()
{
delete d;
}
//============================================================================
void CDockOverlayCross::setupOverlayCross(CDockOverlay::eMode Mode)
{
d->Mode = Mode;
QHash<DockWidgetArea, QWidget*> areaWidgets;
areaWidgets.insert(TopDockWidgetArea, createDropIndicatorWidget(TopDockWidgetArea));
areaWidgets.insert(RightDockWidgetArea, createDropIndicatorWidget(RightDockWidgetArea));
areaWidgets.insert(BottomDockWidgetArea, createDropIndicatorWidget(BottomDockWidgetArea));
areaWidgets.insert(LeftDockWidgetArea, createDropIndicatorWidget(LeftDockWidgetArea));
areaWidgets.insert(CenterDockWidgetArea, createDropIndicatorWidget(CenterDockWidgetArea));
setAreaWidgets(areaWidgets);
}
//============================================================================
void CDockOverlayCross::setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets)
{
// Delete old widgets.
QMutableHashIterator<DockWidgetArea, QWidget*> i(d->DropIndicatorWidgets);
while (i.hasNext())
{
i.next();
QWidget* widget = i.value();
d->GridLayout->removeWidget(widget);
delete widget;
i.remove();
}
// Insert new widgets into grid.
d->DropIndicatorWidgets = widgets;
QHashIterator<DockWidgetArea, QWidget*> i2(d->DropIndicatorWidgets);
while (i2.hasNext())
{
i2.next();
const DockWidgetArea area = i2.key();
QWidget* widget = i2.value();
QPoint p = d->areaGridPosition(area);
d->GridLayout->addWidget(widget, p.x(), p.y(), (Qt::Alignment) areaAlignment(area));
}
if (CDockOverlay::ModeDockAreaOverlay == d->Mode)
{
d->GridLayout->setContentsMargins(0, 0, 0, 0);
d->GridLayout->setRowStretch(0, 1);
d->GridLayout->setRowStretch(1, 0);
d->GridLayout->setRowStretch(2, 0);
d->GridLayout->setRowStretch(3, 0);
d->GridLayout->setRowStretch(4, 1);
d->GridLayout->setColumnStretch(0, 1);
d->GridLayout->setColumnStretch(1, 0);
d->GridLayout->setColumnStretch(2, 0);
d->GridLayout->setColumnStretch(3, 0);
d->GridLayout->setColumnStretch(4, 1);
}
else
{
d->GridLayout->setContentsMargins(4, 4, 4, 4);
d->GridLayout->setRowStretch(0, 0);
d->GridLayout->setRowStretch(1, 1);
d->GridLayout->setRowStretch(2, 1);
d->GridLayout->setRowStretch(3, 1);
d->GridLayout->setRowStretch(4, 0);
d->GridLayout->setColumnStretch(0, 0);
d->GridLayout->setColumnStretch(1, 1);
d->GridLayout->setColumnStretch(2, 1);
d->GridLayout->setColumnStretch(3, 1);
d->GridLayout->setColumnStretch(4, 0);
}
reset();
}
//============================================================================
DockWidgetArea CDockOverlayCross::cursorLocation() const
{
const QPoint pos = mapFromGlobal(QCursor::pos());
QHashIterator<DockWidgetArea, QWidget*> i(d->DropIndicatorWidgets);
while (i.hasNext())
{
i.next();
if (d->DockOverlay->allowedAreas().testFlag(i.key())
&& i.value()
&& i.value()->isVisible()
&& i.value()->geometry().contains(pos))
{
return i.key();
}
}
return InvalidDockWidgetArea;
}
//============================================================================
void CDockOverlayCross::showEvent(QShowEvent*)
{
resize(d->DockOverlay->size());
move(d->DockOverlay->pos());
}
//============================================================================
void CDockOverlayCross::reset()
{
QList<DockWidgetArea> allAreas;
allAreas << TopDockWidgetArea << RightDockWidgetArea
<< BottomDockWidgetArea << LeftDockWidgetArea << CenterDockWidgetArea;
const DockWidgetAreas allowedAreas = d->DockOverlay->allowedAreas();
// Update visibility of area widgets based on allowedAreas.
for (int i = 0; i < allAreas.count(); ++i)
{
QPoint p = d->areaGridPosition(allAreas.at(i));
QLayoutItem* item = d->GridLayout->itemAtPosition(p.x(), p.y());
QWidget* w = nullptr;
if (item && (w = item->widget()) != nullptr)
{
w->setVisible(allowedAreas.testFlag(allAreas.at(i)));
}
}
}
} // namespace ads
//----------------------------------------------------------------------------

View File

@ -19,58 +19,139 @@
******************************************************************************/ ******************************************************************************/
//============================================================================
/// \file DockOverlay.h
/// \author Uwe Kindler
/// \date 01.03.2017
/// \brief Declaration of CDockOverlay class
//============================================================================
//============================================================================ //============================================================================
// INCLUDES // INCLUDES
//============================================================================ //============================================================================
#include <QPointer>
#include <QHash>
#include <QRect>
#include <QFrame> #include <QFrame>
class QGridLayout;
#include "ads_globals.h" #include "ads_globals.h"
namespace ads namespace ads
{ {
struct DockOverlayPrivate; struct DockOverlayPrivate;
class CDockOverlayCross;
/** /*!
* DockOverlay paints a translucent rectangle over another widget. The geometry * DockOverlay paints a translucent rectangle over another widget. The geometry
* of the rectangle is based on drop area at the mouse location. * of the rectangle is based on the mouse location.
*/ */
class CDockOverlay : public QFrame class CDockOverlay : public QFrame
{ {
Q_OBJECT Q_OBJECT
private: private:
DockOverlayPrivate* d; ///< private data (pimpl) DockOverlayPrivate* d; //< private data class
friend class DockOverlayPrivate; friend class DockOverlayPrivate;
protected: friend class DockOverlayCross;
public: public:
/** enum eMode
* Default Constructor {
*/ ModeDockAreaOverlay,
CDockOverlay(QWidget* parent = 0); ModeContainerOverlay
};
/** /**
* Virtual Destructor * Creates a dock overlay
*/
CDockOverlay(QWidget* parent, eMode Mode = ModeDockAreaOverlay);
/**
* Virtual destructor
*/ */
virtual ~CDockOverlay(); virtual ~CDockOverlay();
/** /**
* Shows the dock overlay for the given target widget * Configures the areas that are allowed for docking
*/
void setAllowedAreas(DockWidgetAreas areas);
/**
* Returns flags with all allowed drop areas
*/
DockWidgetAreas allowedAreas() const;
/**
* Returns the drop area under the current cursor location
*/
DockWidgetArea dropAreaUnderCursor() const;
/**
* Show the drop overly for the given target widget
*/ */
DockWidgetArea showOverlay(QWidget* target); DockWidgetArea showOverlay(QWidget* target);
/** /**
* Hides this verlay * Show drop overlay for the given target widget and the given rectangle
*/
void showOverlay(QWidget* target, const QRect& targetAreaRect);
/**
* Hides the overlay
*/ */
void hideOverlay(); void hideOverlay();
}; // class DockOverlay
} protected:
// namespace ads virtual void paintEvent(QPaintEvent *e) override;
//----------------------------------------------------------------------------- virtual void showEvent(QShowEvent* e) override;
virtual void hideEvent(QHideEvent* e) override;
virtual void resizeEvent(QResizeEvent* e) override;
virtual void moveEvent(QMoveEvent* e) override;
};
struct DockOverlayCrossPrivate;
/*!
* DockOverlayCross shows a cross with 5 different drop area possibilities.
* I could have handled everything inside DockOverlay, but because of some
* styling issues it's better to have a separate class for the cross.
*/
class CDockOverlayCross : public QWidget
{
Q_OBJECT
private:
DockOverlayCrossPrivate* d;
friend class DockOverlayCrossPrivate;
friend class CDockOverlay;
public:
/**
* Creates an overlay corss for the given overlay
*/
CDockOverlayCross(CDockOverlay* overlay);
/**
* Virtual destructor
*/
virtual ~CDockOverlayCross();
/**
* Returns the dock widget area depending on the current cursor location.
* The function checks, if the mouse cursor is inside of any drop indicator
* widget and returns the corresponding DockWidgetArea.
*/
DockWidgetArea cursorLocation() const;
/**
* Sets up the overlay cross for the given overlay mode
*/
void setupOverlayCross(CDockOverlay::eMode Mode);
/**
* Resets and updates the
*/
void reset();
protected:
virtual void showEvent(QShowEvent* e) override;
void setAreaWidgets(const QHash<DockWidgetArea, QWidget*>& widgets);
private:
}; // CDockOverlayCross
} // namespace ads
#endif // DockOverlayH #endif // DockOverlayH

View File

@ -43,6 +43,8 @@
#include "DockWidget.h" #include "DockWidget.h"
#include "DockAreaWidget.h" #include "DockAreaWidget.h"
#include "FloatingDockContainer.h" #include "FloatingDockContainer.h"
#include "DockOverlay.h"
#include "DockManager.h"
namespace ads namespace ads
{ {
@ -107,8 +109,10 @@ struct DockWidgetTitleBarPrivate
/** /**
* Starts floating of the dock widget that belongs to this title bar * 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
*/ */
void startFloating(const QPoint& GlobalPos); bool startFloating(const QPoint& GlobalPos);
}; };
// struct DockWidgetTitleBarPrivate // struct DockWidgetTitleBarPrivate
@ -153,8 +157,21 @@ void DockWidgetTitleBarPrivate::moveTab(QMouseEvent* ev)
//============================================================================ //============================================================================
void DockWidgetTitleBarPrivate::startFloating(const QPoint& GlobalPos) bool DockWidgetTitleBarPrivate::startFloating(const QPoint& GlobalPos)
{ {
std::cout << "isFloating " << DockWidget->dockContainer()->isFloating() << std::endl;
std::cout << "areaCount " << DockWidget->dockContainer()->dockAreaCount() << std::endl;
std::cout << "widgetCount " << DockWidget->dockAreaWidget()->count() << std::endl;
// if this is the last dock widget inside of this floating widget,
// then it does not make any sense, to make if floating because
// it is already floating
if (DockWidget->dockContainer()->isFloating()
&& (DockWidget->dockContainer()->dockAreaCount() == 1)
&& (DockWidget->dockAreaWidget()->count() == 1))
{
return false;
}
std::cout << "startFloating" << std::endl; std::cout << "startFloating" << std::endl;
DragState = DraggingFloatingWidget; DragState = DraggingFloatingWidget;
QSize Size = DockArea->size(); QSize Size = DockArea->size();
@ -166,6 +183,7 @@ void DockWidgetTitleBarPrivate::startFloating(const QPoint& GlobalPos)
} }
else else
{ {
std::cout << "DockWidgetTitleBarPrivate::startFloating DockArea" << std::endl;
// If section widget has only one content widget, we can move the complete // If section widget has only one content widget, we can move the complete
// section widget into floating widget // section widget into floating widget
auto splitter = internal::findParent<QSplitter*>(DockArea); auto splitter = internal::findParent<QSplitter*>(DockArea);
@ -173,13 +191,9 @@ void DockWidgetTitleBarPrivate::startFloating(const QPoint& GlobalPos)
} }
FloatingWidget->startFloating(DragStartMousePosition, Size); FloatingWidget->startFloating(DragStartMousePosition, Size);
auto Overlay = DockWidget->dockManager()->containerOverlay();
/* Overlay->setAllowedAreas(OuterDockAreas);
* DropOverlay* ContainerDropOverlay = cw->dropOverlay(); return true;
ContainerDropOverlay->setAllowedAreas(OuterAreas);
ContainerDropOverlay->showDropOverlay(this);
ContainerDropOverlay->raise();
*/
} }
@ -188,6 +202,7 @@ CDockWidgetTitleBar::CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget *paren
QFrame(parent), QFrame(parent),
d(new DockWidgetTitleBarPrivate(this)) d(new DockWidgetTitleBarPrivate(this))
{ {
setAttribute(Qt::WA_NoMousePropagation, true);
d->DockWidget = DockWidget; d->DockWidget = DockWidget;
d->createLayout(); d->createLayout();
} }
@ -271,9 +286,12 @@ void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
if (!MouseInsideTitleArea) if (!MouseInsideTitleArea)
{ {
d->startFloating(ev->globalPos()); d->startFloating(ev->globalPos());
return; // do not delegate handling of mouse move event base class to prevent
// move events for the title area
return;
} }
else if ((ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving else if (d->DockArea->count() > 1
&& (ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving
{ {
d->DragState = DraggingTab; d->DragState = DraggingTab;
return; return;

View File

@ -84,16 +84,16 @@ FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContaine
void FloatingDockContainerPrivate::titleMouseReleaseEvent() void FloatingDockContainerPrivate::titleMouseReleaseEvent()
{ {
setDraggingActive(false); setDraggingActive(false);
/*if (!m_DropContainer) if (!DropContainer)
{ {
return; return;
} }
std::cout << "Dropped" << std::endl; std::cout << "Dropped" << std::endl;
CMainContainerWidget* MainContainerWidget = mainContainerWidget(); /*CMainContainerWidget* MainContainerWidget = mainContainerWidget();
m_DropContainer->dropFloatingWidget(this, QCursor::pos()); m_DropContainer->dropFloatingWidget(this, QCursor::pos());*/
MainContainerWidget->dropOverlay()->hideDropOverlay(); DockManager->containerOverlay()->hideOverlay();
MainContainerWidget->sectionDropOverlay()->hideDropOverlay();*/ DockManager->dockAreaOverlay()->hideOverlay();
} }
@ -123,7 +123,6 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos); QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
if (ContainerWidget->rect().contains(MappedPos)) if (ContainerWidget->rect().contains(MappedPos))
{ {
std::cout << "Container " << ContainerWidget << " contains mousepos" << std::endl;
if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer)) if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer))
{ {
TopContainer = ContainerWidget; TopContainer = ContainerWidget;
@ -148,7 +147,7 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
auto DockArea = TopContainer->dockAreaAt(GlobalPos); auto DockArea = TopContainer->dockAreaAt(GlobalPos);
if (DockArea) if (DockArea)
{ {
//SectionOverlay->setAllowedAreas(AllAreas); DockAreaOverlay->setAllowedAreas(AllDockAreas);
DockAreaOverlay->showOverlay(DockArea); DockAreaOverlay->showOverlay(DockArea);
} }
else else
@ -172,22 +171,7 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
//============================================================================ //============================================================================
void FloatingDockContainerPrivate::setDraggingActive(bool Active) void FloatingDockContainerPrivate::setDraggingActive(bool Active)
{ {
if (DraggingActive == Active)
{
return;
}
DraggingActive = Active; DraggingActive = Active;
if (Active)
{
std::cout << "FloatingWidget:: InstallEventFilter" << std::endl;
qApp->installEventFilter(_this);
}
else
{
std::cout << "FloatingWidget:: RemoveEventFilter" << std::endl;
qApp->removeEventFilter(_this);
}
} }
@ -205,6 +189,8 @@ CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) :
d->DockContainer = new CDockContainerWidget(DockManager, this); d->DockContainer = new CDockContainerWidget(DockManager, this);
l->addWidget(d->DockContainer); l->addWidget(d->DockContainer);
DockManager->registerFloatingWidget(this); DockManager->registerFloatingWidget(this);
qApp->installEventFilter(this);
} }

View File

@ -45,6 +45,7 @@ enum DockWidgetArea
BottomDockWidgetArea = 0x08, BottomDockWidgetArea = 0x08,
CenterDockWidgetArea = 0x10, CenterDockWidgetArea = 0x10,
InvalidDockWidgetArea = NoDockWidgetArea,
OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea | BottomDockWidgetArea, OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea | BottomDockWidgetArea,
AllDockAreas = OuterDockAreas | CenterDockWidgetArea AllDockAreas = OuterDockAreas | CenterDockWidgetArea
}; };