From 19b5f57610d20e0ab83d3d83e6816d8f67a8ae1d Mon Sep 17 00:00:00 2001 From: mfreiholz Date: Tue, 2 Feb 2016 13:49:10 +0100 Subject: [PATCH] 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. --- .../src/ads/container_widget.cpp | 57 +++++++++--------- .../src/ads/container_widget.h | 6 +- .../src/ads/drop_overlay.cpp | 58 +++++++++++++++---- .../src/ads/floating_widget.cpp | 12 +++- .../src/ads/floating_widget.h | 7 ++- .../src/ads/section_title_widget.cpp | 4 +- .../src/icontitlewidget.cpp | 10 +++- AdvancedDockingSystemDemo/src/mainwindow.cpp | 1 + README.md | 21 ++++--- 9 files changed, 117 insertions(+), 59 deletions(-) diff --git a/AdvancedDockingSystem/src/ads/container_widget.cpp b/AdvancedDockingSystem/src/ads/container_widget.cpp index fb2b91f..0fd8a3a 100644 --- a/AdvancedDockingSystem/src/ads/container_widget.cpp +++ b/AdvancedDockingSystem/src/ads/container_widget.cpp @@ -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(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 contents = sw->contents(); + foreach (const SectionContent::RefPtr& c, contents) + { + m->addAction(QIcon(), QString("Content %1").arg(c->uid())); + } + } -void ContainerWidget::contextMenuEvent(QContextMenuEvent*) -{ - qDebug() << Q_FUNC_INFO; -// if (_contents.size() <= 0) -// { -// QFrame::contextMenuEvent(e); -// return; -// } + // Contents of FloatingWidgets + if (_floatingWidgets.size()) + { + 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 \ No newline at end of file diff --git a/AdvancedDockingSystem/src/ads/container_widget.h b/AdvancedDockingSystem/src/ads/container_widget.h index 4123c49..aad84e6 100644 --- a/AdvancedDockingSystem/src/ads/container_widget.h +++ b/AdvancedDockingSystem/src/ads/container_widget.h @@ -6,6 +6,7 @@ #include #include 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! diff --git a/AdvancedDockingSystem/src/ads/drop_overlay.cpp b/AdvancedDockingSystem/src/ads/drop_overlay.cpp index afa2154..51fd1ee 100644 --- a/AdvancedDockingSystem/src/ads/drop_overlay.cpp +++ b/AdvancedDockingSystem/src/ads/drop_overlay.cpp @@ -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,14 +68,44 @@ 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); + } - 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) @@ -169,6 +199,7 @@ DropArea DropSplitAreas::cursorLocation() const static QPointer MyOverlay; static QPointer 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; } } diff --git a/AdvancedDockingSystem/src/ads/floating_widget.cpp b/AdvancedDockingSystem/src/ads/floating_widget.cpp index 293b1d6..cc35494 100644 --- a/AdvancedDockingSystem/src/ads/floating_widget.cpp +++ b/AdvancedDockingSystem/src/ads/floating_widget.cpp @@ -7,13 +7,15 @@ #include #include +#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() diff --git a/AdvancedDockingSystem/src/ads/floating_widget.h b/AdvancedDockingSystem/src/ads/floating_widget.h index 773f922..46a91d6 100644 --- a/AdvancedDockingSystem/src/ads/floating_widget.h +++ b/AdvancedDockingSystem/src/ads/floating_widget.h @@ -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; diff --git a/AdvancedDockingSystem/src/ads/section_title_widget.cpp b/AdvancedDockingSystem/src/ads/section_title_widget.cpp index 98fb3f7..240e80e 100644 --- a/AdvancedDockingSystem/src/ads/section_title_widget.cpp +++ b/AdvancedDockingSystem/src/ads/section_title_widget.cpp @@ -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()))) { diff --git a/AdvancedDockingSystemDemo/src/icontitlewidget.cpp b/AdvancedDockingSystemDemo/src/icontitlewidget.cpp index 986c2fb..5bd77f2 100644 --- a/AdvancedDockingSystemDemo/src/icontitlewidget.cpp +++ b/AdvancedDockingSystemDemo/src/icontitlewidget.cpp @@ -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); } - l->addWidget(titleIcon); + // Title label auto titleText = new QLabel(title); auto titleFont = titleText->font(); titleFont.setBold(true); diff --git a/AdvancedDockingSystemDemo/src/mainwindow.cpp b/AdvancedDockingSystemDemo/src/mainwindow.cpp index 31ac019..065f67a 100644 --- a/AdvancedDockingSystemDemo/src/mainwindow.cpp +++ b/AdvancedDockingSystemDemo/src/mainwindow.cpp @@ -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 diff --git a/README.md b/README.md index cf98634..95491f0 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,18 @@ ## Notes - SectionContent may safe a "size-type" property, which defines how the size of the widget should be handled. - - PerCent: Resize in proportion to other widgets. - - Fixed: Width or height are fixed (based on orientation). + - 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