mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2025-01-12 16:20:25 +08:00
Improved support when moving widgets out of FloatingWidget
This commit is contained in:
parent
df85c8bee0
commit
fac5661280
@ -43,6 +43,8 @@
|
||||
#include "DockWidget.h"
|
||||
#include "DockWidgetTitleBar.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockManager.h"
|
||||
#include "DockOverlay.h"
|
||||
|
||||
#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
|
||||
{
|
||||
@ -113,11 +116,24 @@ protected:
|
||||
{
|
||||
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()))
|
||||
{
|
||||
std::cout << "CTabsScrollArea::startFloating" << std::endl;
|
||||
QSize Size = DockArea->size();
|
||||
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(DockArea);
|
||||
FloatingWidget->startFloating(m_DragStartMousePos, Size);
|
||||
|
||||
auto Overlay = DockArea->dockManager()->containerOverlay();
|
||||
Overlay->setAllowedAreas(OuterDockAreas);
|
||||
}
|
||||
|
||||
return;
|
||||
@ -142,6 +158,7 @@ struct DockAreaWidgetPrivate
|
||||
{
|
||||
CDockAreaWidget* _this;
|
||||
QBoxLayout* Layout;
|
||||
QFrame* TitleBar;
|
||||
QBoxLayout* TopLayout;
|
||||
QStackedLayout* ContentsLayout;
|
||||
QScrollArea* TabsScrollArea;
|
||||
@ -207,6 +224,12 @@ struct DockAreaWidgetPrivate
|
||||
* been removed
|
||||
*/
|
||||
void updateTabsMenu();
|
||||
|
||||
/**
|
||||
* Updates the tab bar visibility depending on the number of dock widgets
|
||||
* in this area
|
||||
*/
|
||||
void updateTabBar();
|
||||
};
|
||||
// struct DockAreaWidgetPrivate
|
||||
|
||||
@ -222,10 +245,12 @@ DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) :
|
||||
//============================================================================
|
||||
void DockAreaWidgetPrivate::createTabBar()
|
||||
{
|
||||
TitleBar = new QFrame(_this);
|
||||
TopLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||
TopLayout->setContentsMargins(0, 0, 0, 0);
|
||||
TopLayout->setSpacing(0);
|
||||
Layout->addLayout(TopLayout);
|
||||
TitleBar->setLayout(TopLayout);
|
||||
Layout->addWidget(TitleBar);
|
||||
|
||||
TabsScrollArea = new CTabsScrollArea(_this);
|
||||
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,
|
||||
QMenu* menu)
|
||||
@ -376,6 +421,8 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
|
||||
dockContainer()->removeDockArea(this);
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
d->updateTabBar();
|
||||
}
|
||||
|
||||
|
||||
@ -540,6 +587,14 @@ void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action)
|
||||
int Index = d->TabsMenuButton->menu()->actions().indexOf(Action);
|
||||
setCurrentIndex(Index);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::updateDockArea()
|
||||
{
|
||||
d->updateTabBar();
|
||||
}
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -134,6 +134,11 @@ public slots:
|
||||
* This sets the index position of the current tab page.
|
||||
*/
|
||||
void setCurrentIndex(int index);
|
||||
|
||||
/**
|
||||
* Updates the dock area layout and components visibility
|
||||
*/
|
||||
void updateDockArea();
|
||||
}; // class DockAreaWidget
|
||||
}
|
||||
// namespace ads
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "DockManager.h"
|
||||
#include "DockAreaWidget.h"
|
||||
#include "DockWidget.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "ads_globals.h"
|
||||
|
||||
#include <iostream>
|
||||
@ -72,6 +73,7 @@ struct DockContainerWidgetPrivate
|
||||
unsigned int zOrderIndex = 0;
|
||||
QList<CDockAreaWidget*> DockAreas;
|
||||
QGridLayout* Layout = nullptr;
|
||||
bool isFloating = false;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@ -170,6 +172,7 @@ void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockW
|
||||
}
|
||||
|
||||
DockAreas.append(NewDockArea);
|
||||
NewDockArea->updateDockArea();
|
||||
}
|
||||
|
||||
|
||||
@ -212,6 +215,8 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p
|
||||
QFrame(parent),
|
||||
d(new DockContainerWidgetPrivate(this))
|
||||
{
|
||||
d->isFloating = dynamic_cast<CFloatingDockContainer*>(parent) != 0;
|
||||
|
||||
//setStyleSheet("background: green;");
|
||||
d->DockManager = DockManager;
|
||||
if (DockManager != this)
|
||||
@ -306,6 +311,7 @@ void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget,
|
||||
//============================================================================
|
||||
void CDockContainerWidget::removeDockArea(CDockAreaWidget* area)
|
||||
{
|
||||
std::cout << "CDockContainerWidget::removeDockArea" << std::endl;
|
||||
d->DockAreas.removeAll(area);
|
||||
QSplitter* Splitter = internal::findParent<QSplitter*>(area);
|
||||
area->setParent(0);
|
||||
@ -345,6 +351,20 @@ CDockAreaWidget* CDockContainerWidget::dockAreaAt(const QPoint& GlobalPos) const
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
bool CDockContainerWidget::isFloating() const
|
||||
{
|
||||
return d->isFloating;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockContainerWidget::dockAreaCount() const
|
||||
{
|
||||
return d->DockAreas.count();
|
||||
}
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -104,6 +104,16 @@ public:
|
||||
* dock area at this position
|
||||
*/
|
||||
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
|
||||
} // namespace ads
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -77,8 +77,8 @@ CDockManager::CDockManager(QWidget *parent) :
|
||||
MainWindow->setCentralWidget(this);
|
||||
}
|
||||
|
||||
d->DockAreaOverlay = new CDockOverlay(this);
|
||||
d->ContainerOverlay = new CDockOverlay(this);
|
||||
d->DockAreaOverlay = new CDockOverlay(this, CDockOverlay::ModeDockAreaOverlay);
|
||||
d->ContainerOverlay = new CDockOverlay(this, CDockOverlay::ModeContainerOverlay);
|
||||
d->Containers.append(this);
|
||||
}
|
||||
|
||||
|
@ -17,61 +17,185 @@
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DropOverlay.cpp
|
||||
/// \author Uwe Kindler
|
||||
/// \date 01.03.2017
|
||||
/// \brief Implementation of CDropOverlay class
|
||||
//============================================================================
|
||||
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#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>
|
||||
|
||||
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
|
||||
{
|
||||
CDockOverlay* _this;
|
||||
DockWidgetAreas AllowedAreas = InvalidDockWidgetArea;
|
||||
CDockOverlayCross* Cross;
|
||||
QPointer<QWidget> TargetWidget;
|
||||
QRect TargetRect;
|
||||
DockWidgetArea LastLocation = InvalidDockWidgetArea;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
*/
|
||||
DockOverlayPrivate(CDockOverlay* _public);
|
||||
DockOverlayPrivate(CDockOverlay* _public) : _this(_public) {}
|
||||
};
|
||||
// struct DropOverlayPrivate
|
||||
|
||||
//============================================================================
|
||||
DockOverlayPrivate::DockOverlayPrivate(CDockOverlay* _public) :
|
||||
_this(_public)
|
||||
/**
|
||||
* Private data of CDockOverlayCross class
|
||||
*/
|
||||
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),
|
||||
d(new DockOverlayPrivate(this))
|
||||
{
|
||||
setStyleSheet("ads--CDockOverlay {background: palette(highlight);}");
|
||||
d->Cross = new CDockOverlayCross(this);
|
||||
setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
|
||||
setWindowOpacity(0.2);
|
||||
setWindowTitle("DockOverlay");
|
||||
//setAttribute(Qt::WA_NoSystemBackground);
|
||||
//setAttribute(Qt::WA_TranslucentBackground);
|
||||
setAttribute(Qt::WA_NoSystemBackground);
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
setWindowFlags(windowFlags() | Qt::WindowTransparentForInput);
|
||||
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
l->setSpacing(0);
|
||||
setLayout(l);
|
||||
|
||||
d->Cross->setupOverlayCross(Mode);
|
||||
d->Cross->setVisible(false);
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
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)
|
||||
{
|
||||
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());
|
||||
move(target->mapToGlobal(target->rect().topLeft()));
|
||||
this->show();
|
||||
return NoDockWidgetArea;
|
||||
show();
|
||||
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()
|
||||
{
|
||||
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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
@ -19,58 +19,139 @@
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
//============================================================================
|
||||
/// \file DockOverlay.h
|
||||
/// \author Uwe Kindler
|
||||
/// \date 01.03.2017
|
||||
/// \brief Declaration of CDockOverlay class
|
||||
//============================================================================
|
||||
|
||||
|
||||
//============================================================================
|
||||
// INCLUDES
|
||||
//============================================================================
|
||||
#include <QPointer>
|
||||
#include <QHash>
|
||||
#include <QRect>
|
||||
#include <QFrame>
|
||||
class QGridLayout;
|
||||
|
||||
#include "ads_globals.h"
|
||||
|
||||
namespace ads
|
||||
{
|
||||
struct DockOverlayPrivate;
|
||||
class CDockOverlayCross;
|
||||
|
||||
/**
|
||||
/*!
|
||||
* 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
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
DockOverlayPrivate* d; ///< private data (pimpl)
|
||||
DockOverlayPrivate* d; //< private data class
|
||||
friend class DockOverlayPrivate;
|
||||
protected:
|
||||
friend class DockOverlayCross;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Default Constructor
|
||||
*/
|
||||
CDockOverlay(QWidget* parent = 0);
|
||||
enum eMode
|
||||
{
|
||||
ModeDockAreaOverlay,
|
||||
ModeContainerOverlay
|
||||
};
|
||||
|
||||
/**
|
||||
* Virtual Destructor
|
||||
* Creates a dock overlay
|
||||
*/
|
||||
CDockOverlay(QWidget* parent, eMode Mode = ModeDockAreaOverlay);
|
||||
|
||||
/**
|
||||
* Virtual destructor
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}; // class DockOverlay
|
||||
}
|
||||
// namespace ads
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
protected:
|
||||
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
|
||||
|
@ -43,6 +43,8 @@
|
||||
#include "DockWidget.h"
|
||||
#include "DockAreaWidget.h"
|
||||
#include "FloatingDockContainer.h"
|
||||
#include "DockOverlay.h"
|
||||
#include "DockManager.h"
|
||||
|
||||
namespace ads
|
||||
{
|
||||
@ -107,8 +109,10 @@ struct DockWidgetTitleBarPrivate
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@ -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;
|
||||
DragState = DraggingFloatingWidget;
|
||||
QSize Size = DockArea->size();
|
||||
@ -166,6 +183,7 @@ void DockWidgetTitleBarPrivate::startFloating(const QPoint& GlobalPos)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "DockWidgetTitleBarPrivate::startFloating DockArea" << std::endl;
|
||||
// If section widget has only one content widget, we can move the complete
|
||||
// section widget into floating widget
|
||||
auto splitter = internal::findParent<QSplitter*>(DockArea);
|
||||
@ -173,13 +191,9 @@ void DockWidgetTitleBarPrivate::startFloating(const QPoint& GlobalPos)
|
||||
}
|
||||
|
||||
FloatingWidget->startFloating(DragStartMousePosition, Size);
|
||||
|
||||
/*
|
||||
* DropOverlay* ContainerDropOverlay = cw->dropOverlay();
|
||||
ContainerDropOverlay->setAllowedAreas(OuterAreas);
|
||||
ContainerDropOverlay->showDropOverlay(this);
|
||||
ContainerDropOverlay->raise();
|
||||
*/
|
||||
auto Overlay = DockWidget->dockManager()->containerOverlay();
|
||||
Overlay->setAllowedAreas(OuterDockAreas);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -188,6 +202,7 @@ CDockWidgetTitleBar::CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget *paren
|
||||
QFrame(parent),
|
||||
d(new DockWidgetTitleBarPrivate(this))
|
||||
{
|
||||
setAttribute(Qt::WA_NoMousePropagation, true);
|
||||
d->DockWidget = DockWidget;
|
||||
d->createLayout();
|
||||
}
|
||||
@ -271,9 +286,12 @@ void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
|
||||
if (!MouseInsideTitleArea)
|
||||
{
|
||||
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;
|
||||
return;
|
||||
|
@ -84,16 +84,16 @@ FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContaine
|
||||
void FloatingDockContainerPrivate::titleMouseReleaseEvent()
|
||||
{
|
||||
setDraggingActive(false);
|
||||
/*if (!m_DropContainer)
|
||||
if (!DropContainer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "Dropped" << std::endl;
|
||||
CMainContainerWidget* MainContainerWidget = mainContainerWidget();
|
||||
m_DropContainer->dropFloatingWidget(this, QCursor::pos());
|
||||
MainContainerWidget->dropOverlay()->hideDropOverlay();
|
||||
MainContainerWidget->sectionDropOverlay()->hideDropOverlay();*/
|
||||
/*CMainContainerWidget* MainContainerWidget = mainContainerWidget();
|
||||
m_DropContainer->dropFloatingWidget(this, QCursor::pos());*/
|
||||
DockManager->containerOverlay()->hideOverlay();
|
||||
DockManager->dockAreaOverlay()->hideOverlay();
|
||||
}
|
||||
|
||||
|
||||
@ -123,7 +123,6 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
|
||||
QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos);
|
||||
if (ContainerWidget->rect().contains(MappedPos))
|
||||
{
|
||||
std::cout << "Container " << ContainerWidget << " contains mousepos" << std::endl;
|
||||
if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer))
|
||||
{
|
||||
TopContainer = ContainerWidget;
|
||||
@ -148,7 +147,7 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
|
||||
auto DockArea = TopContainer->dockAreaAt(GlobalPos);
|
||||
if (DockArea)
|
||||
{
|
||||
//SectionOverlay->setAllowedAreas(AllAreas);
|
||||
DockAreaOverlay->setAllowedAreas(AllDockAreas);
|
||||
DockAreaOverlay->showOverlay(DockArea);
|
||||
}
|
||||
else
|
||||
@ -172,22 +171,7 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos)
|
||||
//============================================================================
|
||||
void FloatingDockContainerPrivate::setDraggingActive(bool Active)
|
||||
{
|
||||
if (DraggingActive == Active)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
l->addWidget(d->DockContainer);
|
||||
DockManager->registerFloatingWidget(this);
|
||||
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -45,6 +45,7 @@ enum DockWidgetArea
|
||||
BottomDockWidgetArea = 0x08,
|
||||
CenterDockWidgetArea = 0x10,
|
||||
|
||||
InvalidDockWidgetArea = NoDockWidgetArea,
|
||||
OuterDockAreas = TopDockWidgetArea | LeftDockWidgetArea | RightDockWidgetArea | BottomDockWidgetArea,
|
||||
AllDockAreas = OuterDockAreas | CenterDockWidgetArea
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user