mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-11-15 13:15:43 +08:00
Adds function to generate context menu with available contents.
Refactors some auto-keywords to its real class names. Paints drop location based on cursors drop area indicator. Waits a few pixel before moving tab from SectionWidget.
This commit is contained in:
parent
1336118e09
commit
19b5f57610
@ -216,9 +216,8 @@ void ContainerWidget::splitSections(SectionWidget* s1, SectionWidget* s2, Qt::Or
|
||||
{
|
||||
addSection(s1);
|
||||
addSection(s2);
|
||||
//_sections.append(s2);
|
||||
|
||||
auto currentSplitter = findParentSplitter(s1);
|
||||
QSplitter* currentSplitter = findParentSplitter(s1);
|
||||
if (currentSplitter)
|
||||
{
|
||||
const int index = currentSplitter->indexOf(s1);
|
||||
@ -229,14 +228,11 @@ void ContainerWidget::splitSections(SectionWidget* s1, SectionWidget* s2, Qt::Or
|
||||
splitter->addWidget(s2);
|
||||
currentSplitter->insertWidget(index, splitter);
|
||||
}
|
||||
// _mainLayout->replaceWidget(section1, splitter);
|
||||
// splitter->addWidget(section1);
|
||||
// splitter->addWidget(section2);
|
||||
}
|
||||
|
||||
SectionWidget* ContainerWidget::sectionAt(const QPoint& pos) const
|
||||
{
|
||||
auto gpos = mapToGlobal(pos);
|
||||
const QPoint gpos = mapToGlobal(pos);
|
||||
for (int i = 0; i < _sections.size(); ++i)
|
||||
{
|
||||
auto sw = _sections[i];
|
||||
@ -297,34 +293,35 @@ bool ContainerWidget::restoreGeometry(const QByteArray& data)
|
||||
return false;
|
||||
}
|
||||
|
||||
void ContainerWidget::paintEvent(QPaintEvent* e)
|
||||
QMenu* ContainerWidget::createContextMenu() const
|
||||
{
|
||||
QFrame::paintEvent(e);
|
||||
QMenu* m = new QMenu(const_cast<ContainerWidget*>(this));
|
||||
|
||||
// QPainter p(this);
|
||||
// p.fillRect(outerTopDropRect(), QBrush(QColor(Qt::red)));
|
||||
// p.fillRect(outerRightDropRect(), QBrush(QColor(Qt::green)));
|
||||
// p.fillRect(outerBottomDropRect(), QBrush(QColor(Qt::blue)));
|
||||
// p.fillRect(outerLeftDropRect(), QBrush(QColor(Qt::yellow)));
|
||||
// Contents of SectionWidgets
|
||||
for (int i = 0; i < _sections.size(); ++i)
|
||||
{
|
||||
SectionWidget* sw = _sections.at(i);
|
||||
QList<SectionContent::RefPtr> contents = sw->contents();
|
||||
foreach (const SectionContent::RefPtr& c, contents)
|
||||
{
|
||||
m->addAction(QIcon(), QString("Content %1").arg(c->uid()));
|
||||
}
|
||||
}
|
||||
|
||||
void ContainerWidget::contextMenuEvent(QContextMenuEvent*)
|
||||
// Contents of FloatingWidgets
|
||||
if (_floatingWidgets.size())
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
// if (_contents.size() <= 0)
|
||||
// {
|
||||
// QFrame::contextMenuEvent(e);
|
||||
// return;
|
||||
// }
|
||||
if (m->actions().size())
|
||||
m->addSeparator();
|
||||
for (int i = 0; i < _floatingWidgets.size(); ++i)
|
||||
{
|
||||
FloatingWidget* fw = _floatingWidgets.at(i);
|
||||
SectionContent::RefPtr c = fw->content();
|
||||
m->addAction(QIcon(), QString("Floating %1").arg(c->uid()));
|
||||
}
|
||||
}
|
||||
|
||||
// // Menu with all available contents.
|
||||
// QMenu m;
|
||||
// for (int i = 0; i < _contents.size(); ++i)
|
||||
// {
|
||||
// auto c = _contents[i];
|
||||
// m.addAction(QIcon(), QString("Content %1").arg(c->uid()));
|
||||
// }
|
||||
// m.exec();
|
||||
return m;
|
||||
}
|
||||
|
||||
ADS_NAMESPACE_END
|
@ -6,6 +6,7 @@
|
||||
#include <QPoint>
|
||||
#include <QList>
|
||||
class QSplitter;
|
||||
class QMenu;
|
||||
|
||||
#include "ads.h"
|
||||
#include "section_content.h"
|
||||
@ -22,6 +23,7 @@ class ContainerWidget : public QFrame
|
||||
Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged)
|
||||
|
||||
friend class SectionWidget;
|
||||
friend class FloatingWidget;
|
||||
|
||||
public:
|
||||
explicit ContainerWidget(QWidget *parent = NULL);
|
||||
@ -45,9 +47,7 @@ public:
|
||||
QByteArray saveGeometry() const;
|
||||
bool restoreGeometry(const QByteArray& data);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent*);
|
||||
virtual void contextMenuEvent(QContextMenuEvent*);
|
||||
QMenu* createContextMenu() const;
|
||||
|
||||
private: // Make private!
|
||||
|
||||
|
@ -29,12 +29,12 @@ DropOverlay::DropOverlay(QWidget *parent) :
|
||||
QFrame(parent),
|
||||
_splitAreas(NULL)
|
||||
{
|
||||
setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
//setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||
setWindowFlags(windowFlags() | Qt::Tool);
|
||||
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||
setWindowOpacity(0.2);
|
||||
|
||||
auto l = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
l->setContentsMargins(0, 0, 0, 0);
|
||||
l->setSpacing(0);
|
||||
setLayout(l);
|
||||
@ -68,16 +68,46 @@ void DropOverlay::paintEvent(QPaintEvent*)
|
||||
{
|
||||
QPainter p(this);
|
||||
|
||||
// Draw rect over the entire size + border.
|
||||
auto r = rect();
|
||||
r.setWidth(r.width() - 1);
|
||||
r.setHeight(r.height() - 1);
|
||||
|
||||
// Draw rect based on location
|
||||
QRect r = rect();
|
||||
const DropArea da = cursorLocation();
|
||||
switch (da)
|
||||
{
|
||||
case DropArea::TopDropArea:
|
||||
r.setHeight(r.height() / 2);
|
||||
break;
|
||||
case DropArea::RightDropArea:
|
||||
r.setX(r.width() / 2);
|
||||
break;
|
||||
case DropArea::BottomDropArea:
|
||||
r.setY(r.height() / 2);
|
||||
break;
|
||||
case DropArea::LeftDropArea:
|
||||
r.setWidth(r.width() / 2);
|
||||
break;
|
||||
case DropArea::CenterDropArea:
|
||||
r = rect();
|
||||
break;
|
||||
default:
|
||||
r = QRect();
|
||||
}
|
||||
if (!r.isNull())
|
||||
{
|
||||
p.fillRect(r, QBrush(QColor(0, 100, 255), Qt::Dense4Pattern));
|
||||
p.setBrush(QBrush(QColor(0, 100, 255)));
|
||||
p.drawRect(r);
|
||||
}
|
||||
|
||||
// Draw rect over the entire size + border.
|
||||
// auto r = rect();
|
||||
// r.setWidth(r.width() - 1);
|
||||
// r.setHeight(r.height() - 1);
|
||||
|
||||
// p.fillRect(r, QBrush(QColor(0, 100, 255), Qt::Dense4Pattern));
|
||||
// p.setBrush(QBrush(QColor(0, 100, 255)));
|
||||
// p.drawRect(r);
|
||||
}
|
||||
|
||||
void DropOverlay::resizeEvent(QResizeEvent* e)
|
||||
{
|
||||
// Keep it in center of DropOverlay
|
||||
@ -169,6 +199,7 @@ DropArea DropSplitAreas::cursorLocation() const
|
||||
static QPointer<DropOverlay> MyOverlay;
|
||||
static QPointer<QWidget> MyOverlayParent;
|
||||
static QRect MyOverlayParentRect;
|
||||
static DropArea MyOverlayLastLocation = InvalidDropArea;
|
||||
|
||||
DropArea showDropOverlay(QWidget* parent)
|
||||
{
|
||||
@ -177,7 +208,13 @@ DropArea showDropOverlay(QWidget* parent)
|
||||
if (MyOverlayParent == parent)
|
||||
{
|
||||
// Hint: We could update geometry of overlay here.
|
||||
return MyOverlay->cursorLocation();
|
||||
DropArea da = MyOverlay->cursorLocation();
|
||||
if (da != MyOverlayLastLocation)
|
||||
{
|
||||
MyOverlay->repaint();
|
||||
MyOverlayLastLocation = da;
|
||||
}
|
||||
return da;
|
||||
}
|
||||
hideDropOverlay();
|
||||
}
|
||||
@ -220,6 +257,7 @@ void hideDropOverlay()
|
||||
delete MyOverlay;
|
||||
MyOverlayParent.clear();
|
||||
MyOverlayParentRect = QRect();
|
||||
MyOverlayLastLocation = InvalidDropArea;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,13 +7,15 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QStyle>
|
||||
|
||||
#include "container_widget.h"
|
||||
#include "section_title_widget.h"
|
||||
#include "section_content_widget.h"
|
||||
|
||||
ADS_NAMESPACE_BEGIN
|
||||
|
||||
FloatingWidget::FloatingWidget(SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, SectionContentWidget* contentWidget, QWidget* parent) :
|
||||
FloatingWidget::FloatingWidget(ContainerWidget* container, SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, SectionContentWidget* contentWidget, QWidget* parent) :
|
||||
QWidget(parent, Qt::CustomizeWindowHint | Qt::Tool),
|
||||
_container(container),
|
||||
_content(sc),
|
||||
_titleWidget(titleWidget),
|
||||
_contentWidget(contentWidget)
|
||||
@ -47,6 +49,14 @@ FloatingWidget::FloatingWidget(SectionContent::RefPtr sc, SectionTitleWidget* ti
|
||||
// Content
|
||||
l->addWidget(contentWidget, 1);
|
||||
contentWidget->show();
|
||||
|
||||
_container->_floatingWidgets.append(this);
|
||||
}
|
||||
|
||||
FloatingWidget::~FloatingWidget()
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO;
|
||||
_container->_floatingWidgets.removeAll(this);
|
||||
}
|
||||
|
||||
InternalContentData FloatingWidget::takeContent()
|
||||
|
@ -11,6 +11,7 @@ class QBoxLayout;
|
||||
|
||||
ADS_NAMESPACE_BEGIN
|
||||
|
||||
class ContainerWidget;
|
||||
class SectionTitleWidget;
|
||||
class SectionContentWidget;
|
||||
|
||||
@ -21,13 +22,17 @@ class FloatingWidget : public QWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FloatingWidget(SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, SectionContentWidget* contentWidget, QWidget* parent = nullptr);
|
||||
FloatingWidget(ContainerWidget* container, SectionContent::RefPtr sc, SectionTitleWidget* titleWidget, SectionContentWidget* contentWidget, QWidget* parent = nullptr);
|
||||
virtual ~FloatingWidget();
|
||||
|
||||
InternalContentData takeContent();
|
||||
SectionContent::RefPtr content() const { return _content; }
|
||||
|
||||
protected:
|
||||
virtual void closeEvent(QCloseEvent* e);
|
||||
|
||||
private:
|
||||
ContainerWidget* _container;
|
||||
SectionContent::RefPtr _content;
|
||||
SectionTitleWidget* _titleWidget;
|
||||
SectionContentWidget* _contentWidget;
|
||||
|
@ -226,14 +226,13 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
|
||||
}
|
||||
// Begin to drag/float the SectionContent.
|
||||
else if (!_fw && !_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
|
||||
//&& (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()
|
||||
&& (section = findParentSectionWidget(this)) != NULL
|
||||
&& !section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
|
||||
{
|
||||
// Create floating widget.
|
||||
auto data = section->take(_content->uid(), false);
|
||||
|
||||
_fw = new FloatingWidget(data.content, data.titleWidget, data.contentWidget, cw);
|
||||
_fw = new FloatingWidget(cw, data.content, data.titleWidget, data.contentWidget, cw);
|
||||
_fw->resize(section->size());
|
||||
setActiveTab(false);
|
||||
|
||||
@ -267,6 +266,7 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
|
||||
}
|
||||
// Begin to drag title inside the title area to switch its position inside the SectionWidget.
|
||||
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
|
||||
&& (ev->pos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance() // Wait a few pixels before start moving
|
||||
&& (section = findParentSectionWidget(this)) != NULL
|
||||
&& section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
|
||||
{
|
||||
|
@ -13,17 +13,21 @@ IconTitleWidget::IconTitleWidget(const QIcon& icon, const QString& title, QWidge
|
||||
l->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(l);
|
||||
|
||||
auto titleIcon = new QLabel();
|
||||
// Icon label
|
||||
if (icon.isNull())
|
||||
{
|
||||
titleIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(16, 16));
|
||||
// auto titleIcon = new QLabel();
|
||||
// titleIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(16, 16));
|
||||
// l->addWidget(titleIcon);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto titleIcon = new QLabel();
|
||||
titleIcon->setPixmap(icon.pixmap(16, 16));
|
||||
}
|
||||
l->addWidget(titleIcon);
|
||||
}
|
||||
|
||||
// Title label
|
||||
auto titleText = new QLabel(title);
|
||||
auto titleFont = titleText->font();
|
||||
titleFont.setBold(true);
|
||||
|
@ -57,6 +57,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->mainToolBar->hide();
|
||||
ui->statusBar->hide();
|
||||
QObject::connect(ui->actionAddSectionContent, &QAction::triggered, this, &MainWindow::onActionAddSectionContentTriggered);
|
||||
|
||||
// CREATE SOME TESTING DOCKS
|
||||
|
17
README.md
17
README.md
@ -9,12 +9,15 @@
|
||||
- PerCent: Resize in proportion to other widgets.
|
||||
- Fixed: Width or height are fixed (based on orientation).
|
||||
|
||||
## TODO / Issues
|
||||
List of tasks sorted by priority.
|
||||
- [] Serialize state/size/positions of dockings #FEATURE
|
||||
- [] Deserialize state/size/positions of dockings #FEATURE
|
||||
- [] Drop indicator images should be fully visible over the DropOverlay rectangle #FEATURE
|
||||
- [DONE] Clean up of unused e.g. count()<=1 QSplitters doesn't work well #BUG
|
||||
## TODOs
|
||||
- [] Serialize state/size/positions of dockings
|
||||
- [] Deserialize state/size/positions of dockings
|
||||
- [] Drop indicator images should be fully visible over the DropOverlay rectangle
|
||||
|
||||
## Bugs
|
||||
- Working with outer-edge-drops sometimes leaves empty splitters
|
||||
- [DONE] Clean up of unused e.g. count()<=1 QSplitters doesn't work well
|
||||
|
||||
## License notes
|
||||
- Copied drop images from http://www.codeproject.com/Articles/140209/Building-a-Docking-Window-Management-Solution-in-W
|
||||
- Copied drop images from
|
||||
http://www.codeproject.com/Articles/140209/Building-a-Docking-Window-Management-Solution-in-W
|
||||
|
Loading…
Reference in New Issue
Block a user