diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp index b5aee4f6f3..e5f69e7bee 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.cpp @@ -48,6 +48,7 @@ RimGridCrossPlot::RimGridCrossPlot() { CAF_PDM_InitObject("Grid Cross Plot", ":/SummaryXPlotLight16x16.png", "", ""); + CAF_PDM_InitField(&m_showInfoBox, "ShowInfoBox", true, "Show Info Box", "", "", ""); CAF_PDM_InitField(&m_showLegend, "ShowLegend", true, "Show Legend", "", "", ""); CAF_PDM_InitField(&m_legendFontSize, "LegendFontSize", 10, "Legend Font Size", "", "", ""); CAF_PDM_InitFieldNoDefault(&m_nameConfig, "NameConfig", "Name Config", "", "", ""); @@ -94,13 +95,18 @@ RimGridCrossPlotCurveSet* RimGridCrossPlot::createCurveSet() //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -int RimGridCrossPlot::indexOfCurveSet(const RimGridCrossPlotCurveSet* curveSet) const +int RimGridCrossPlot::indexOfCurveSet(const RimGridCrossPlotCurveSet* curveSetToCheck) const { - for (size_t i = 0; i < m_crossPlotCurveSets.size(); ++i) + int index = 0; + for (auto curveSet : m_crossPlotCurveSets()) { - if (curveSet == m_crossPlotCurveSets[i]) + if (curveSet == curveSetToCheck) { - return static_cast(i); + return index; + } + if (curveSet->isChecked() && curveSet->visibleCurveCount() > 0u) + { + index++; } } return -1; @@ -247,6 +253,14 @@ QString RimGridCrossPlot::createAutoName() const return autoName.join(" "); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +bool RimGridCrossPlot::showInfoBox() const +{ + return m_showInfoBox(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -399,6 +413,7 @@ void RimGridCrossPlot::onLoadDataAndUpdate() //-------------------------------------------------------------------------------------------------- void RimGridCrossPlot::defineUiOrdering(QString uiConfigName, caf::PdmUiOrdering& uiOrdering) { + uiOrdering.add(&m_showInfoBox); uiOrdering.add(&m_showLegend); if (m_showLegend()) diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h index 39558d13a9..77d637d7ff 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlot.h @@ -66,6 +66,7 @@ public: void reattachCurvesToQwtAndReplot(); QString createAutoName() const override; + bool showInfoBox() const; caf::PdmFieldHandle* userDescriptionField() override; void detachAllCurves(); void performAutoNameUpdate() override; @@ -112,6 +113,7 @@ protected: RimGridCrossPlotNameConfig* nameConfig(); private: + caf::PdmField m_showInfoBox; caf::PdmField m_showLegend; caf::PdmField m_legendFontSize; caf::PdmChildField m_nameConfig; diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.cpp index b0856b1aab..443a900f24 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.cpp @@ -92,6 +92,14 @@ int RimGridCrossPlotCurve::groupIndex() const return m_groupIndex; } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimGridCrossPlotCurve::sampleCount() const +{ + return m_qwtPlotCurve->dataSize(); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h index c774a8aa9f..de3aebee3d 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurve.h @@ -43,9 +43,9 @@ public: void setGroupingInformation(int curveSetIndex, int groupIndex); void setSamples(const std::vector& xValues, const std::vector& yValues); - void setCurveAutoAppearance(); - int groupIndex() const; - + void setCurveAutoAppearance(); + int groupIndex() const; + size_t sampleCount() const; protected: void determineSymbol(); diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp index 86f2493a3d..52af6eab23 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.cpp @@ -198,6 +198,36 @@ QString RimGridCrossPlotCurveSet::yAxisName() const return m_yAxisProperty->resultVariableUiShortName(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QString RimGridCrossPlotCurveSet::infoText() const +{ + if (!m_case()) return ""; + + if (visibleCurveCount() == 0u) return ""; + + QStringList textLines; + textLines += QString("Case: %1").arg(m_case()->caseUserDescription()); + textLines += QString("Parameters:: %1 x %2") + .arg(m_xAxisProperty->resultVariableUiShortName()) + .arg(m_yAxisProperty->resultVariableUiShortName()); + if (m_timeStep != -1) + { + textLines += QString("Time step: %1").arg(timeStepString()); + } + if (m_grouping != NO_GROUPING) + { + textLines += QString("Grouped By: %1").arg(groupParameter()); + } + if (m_cellFilterView()) + { + textLines += QString("Filter view: %1").arg(m_cellFilterView->name()); + } + textLines += QString("Sample Count: %1").arg(sampleCount()); + return textLines.join("
\n"); +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- @@ -606,6 +636,32 @@ void RimGridCrossPlotCurveSet::destroyCurves() m_crossPlotCurves.deleteAllChildObjects(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimGridCrossPlotCurveSet::visibleCurveCount() const +{ + size_t visibleCurves = 0; + for (auto curve : m_crossPlotCurves) + { + if (curve->isCurveVisible()) visibleCurves++; + } + return visibleCurves; +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +size_t RimGridCrossPlotCurveSet::sampleCount() const +{ + size_t sampleCount = 0; + for (auto curve : m_crossPlotCurves) + { + if (curve->isCurveVisible()) sampleCount += curve->sampleCount(); + } + return sampleCount; +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h index ad017888e6..518d61acc0 100644 --- a/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h +++ b/ApplicationCode/ProjectDataModel/GridCrossPlots/RimGridCrossPlotCurveSet.h @@ -97,6 +97,7 @@ public: void setParentQwtPlotNoReplot(QwtPlot* parent); QString xAxisName() const; QString yAxisName() const; + QString infoText() const; int indexInPlot() const; QString createAutoName() const override; @@ -131,6 +132,8 @@ public: void setCustomColor(const cvf::Color3f color); void destroyCurves(); + size_t visibleCurveCount() const; + size_t sampleCount() const; protected: void initAfterRead() override; void onLoadDataAndUpdate(bool updateParentPlot); @@ -175,5 +178,5 @@ private: caf::PdmField m_useCustomColor; caf::PdmField m_customColor; caf::PdmChildField m_plotCellFilterCollection;; - + }; diff --git a/ApplicationCode/UserInterface/CMakeLists_files.cmake b/ApplicationCode/UserInterface/CMakeLists_files.cmake index 03ac8f0c88..3c0e6aba91 100644 --- a/ApplicationCode/UserInterface/CMakeLists_files.cmake +++ b/ApplicationCode/UserInterface/CMakeLists_files.cmake @@ -80,6 +80,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotItemGroup.h ${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotTools.h ${CMAKE_CURRENT_LIST_DIR}/RiuWellPathComponentPlotItem.h ${CMAKE_CURRENT_LIST_DIR}/RiuMeasurementViewEventFilter.h +${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.h ) set (SOURCE_GROUP_SOURCE_FILES @@ -159,6 +160,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuDockWidgetTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotItemGroup.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuQwtPlotTools.cpp ${CMAKE_CURRENT_LIST_DIR}/RiuWellPathComponentPlotItem.cpp +${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.cpp ) list(APPEND CODE_HEADER_FILES @@ -205,6 +207,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RiuMessagePanel.h ${CMAKE_CURRENT_LIST_DIR}/RiuExpressionContextMenuManager.h ${CMAKE_CURRENT_LIST_DIR}/RiuCalculationsContextMenuManager.h ${CMAKE_CURRENT_LIST_DIR}/RiuMohrsCirclePlot.h +${CMAKE_CURRENT_LIST_DIR}/RiuDraggableOverlayFrame.h ) list(APPEND QT_UI_FILES diff --git a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp index dcfbb4b38e..2d2f2407dd 100644 --- a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp +++ b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.cpp @@ -41,16 +41,11 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuCvfOverlayItemWidget::RiuCvfOverlayItemWidget(QWidget* parent/*=0*/) -: QWidget(parent) +RiuCvfOverlayItemWidget::RiuCvfOverlayItemWidget(QWidget* parent/*=0*/, QWidget* widgetToSnapTo) +: RiuDraggableOverlayFrame(parent, widgetToSnapTo) { - auto hblayout = new QHBoxLayout(this); - hblayout->setMargin(0); - hblayout->setSpacing(0); - - this->setLayout(hblayout); - m_overlayItemLabel = new QLabel(this); - this->layout()->addWidget(m_overlayItemLabel); + this->layout()->setMargin(0); + this->layout()->setSpacing(0); } //-------------------------------------------------------------------------------------------------- @@ -126,7 +121,7 @@ void RiuCvfOverlayItemWidget::updateFromOverlayItem( cvf::OverlayItem * item) QPixmap pixmap = QPixmap::fromImage(image); delete viewer; - + m_overlayItemLabel->setPixmap(pixmap); this->setMinimumSize(QSize(width, height)); this->resize(QSize(width, height)); diff --git a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h index 237b09bcba..f635f95e56 100644 --- a/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h +++ b/ApplicationCode/UserInterface/RiuCvfOverlayItemWidget.h @@ -18,6 +18,8 @@ #pragma once +#include "RiuDraggableOverlayFrame.h" + #include class QLabel; @@ -31,18 +33,15 @@ namespace cvf // // //================================================================================================== -class RiuCvfOverlayItemWidget : public QWidget +class RiuCvfOverlayItemWidget : public RiuDraggableOverlayFrame { Q_OBJECT public: - explicit RiuCvfOverlayItemWidget(QWidget* parent = nullptr); + explicit RiuCvfOverlayItemWidget(QWidget* parent = nullptr, QWidget* widgetToSnapTo = nullptr); ~RiuCvfOverlayItemWidget() override; void updateFromOverlayItem( cvf::OverlayItem * item); // virtual QSize sizeHint() const override; // virtual QSize minimumSizeHint() const override; - -protected: - QLabel* m_overlayItemLabel; }; diff --git a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp new file mode 100644 index 0000000000..84fccaf442 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.cpp @@ -0,0 +1,61 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#include "RiuDraggableOverlayFrame.h" +#include "RiuWidgetDragger.h" + +#include +#include +#include + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +RiuDraggableOverlayFrame::RiuDraggableOverlayFrame(QWidget* parent, QWidget* widgetToSnapTo, const QColor& backgroundColor) + : QFrame(parent) +{ + RiuWidgetDragger* dragger = new RiuWidgetDragger(this, widgetToSnapTo); + + QPalette pal = this->palette(); + pal.setColor(QPalette::Background, backgroundColor); + setAutoFillBackground(true); + setPalette(pal); + setFrameShape(QFrame::Box); + QGraphicsDropShadowEffect* dropShadowEffect = new QGraphicsDropShadowEffect(this); + dropShadowEffect->setOffset(1.0, 1.0); + dropShadowEffect->setBlurRadius(3.0); + dropShadowEffect->setColor(QColor(100, 100, 100, 100)); + setGraphicsEffect(dropShadowEffect); + + auto hblayout = new QVBoxLayout(this); + this->setLayout(hblayout); + + m_overlayItemLabel = new QLabel(this); + hblayout->addWidget(m_overlayItemLabel); + m_overlayItemLabel->setObjectName("OverlayFrameLabel"); + m_overlayItemLabel->setGraphicsEffect(nullptr); + m_overlayItemLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); + dragger->addWidget(m_overlayItemLabel); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +QLabel* RiuDraggableOverlayFrame::label() +{ + return m_overlayItemLabel; +} diff --git a/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h new file mode 100644 index 0000000000..cb735d3f81 --- /dev/null +++ b/ApplicationCode/UserInterface/RiuDraggableOverlayFrame.h @@ -0,0 +1,35 @@ +///////////////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2019- Equinor ASA +// +// ResInsight is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. +// +// See the GNU General Public License at +// for more details. +// +///////////////////////////////////////////////////////////////////////////////// +#pragma once + +#include +#include + +class QColor; +class QLabel; + +class RiuDraggableOverlayFrame : public QFrame +{ + Q_OBJECT +public: + RiuDraggableOverlayFrame(QWidget* parent, QWidget* widgetToSnapTo = nullptr, const QColor& backgroundColor = QColor(255, 255, 255, 100)); + QLabel* label(); + +protected: + QPointer m_overlayItemLabel; +}; diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp index 643897b2b1..74b70df65b 100644 --- a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.cpp @@ -32,8 +32,10 @@ #include "RimPlotAxisProperties.h" #include "RiuPlotAnnotationTool.h" +#include #include #include +#include //-------------------------------------------------------------------------------------------------- /// @@ -42,6 +44,7 @@ RiuGridCrossQwtPlot::RiuGridCrossQwtPlot(RimViewWindow* ownerViewWindow, QWidget : RiuQwtPlot(ownerViewWindow, parent) { m_annotationTool = std::unique_ptr(new RiuPlotAnnotationTool()); + m_infoBox = new RiuDraggableOverlayFrame(this, canvas()); } //-------------------------------------------------------------------------------------------------- @@ -54,10 +57,7 @@ void RiuGridCrossQwtPlot::addOrUpdateCurveSetLegend(RimGridCrossPlotCurveSet* cu auto it = m_legendWidgets.find(curveSet); if (it == m_legendWidgets.end() || it->second == nullptr) { - overlayWidget = new RiuCvfOverlayItemWidget(this); - - new RiuWidgetDragger(overlayWidget); - + overlayWidget = new RiuCvfOverlayItemWidget(this, canvas()); m_legendWidgets[curveSet] = overlayWidget; } else @@ -144,9 +144,66 @@ void RiuGridCrossQwtPlot::updateAnnotationObjects(RimPlotAxisProperties* axisPro void RiuGridCrossQwtPlot::updateLayout() { QwtPlot::updateLayout(); + updateInfoBoxLayout(); updateLegendLayout(); } +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuGridCrossQwtPlot::updateInfoBoxLayout() +{ + RimGridCrossPlot* crossPlot = dynamic_cast(ownerPlotDefinition()); + if (!crossPlot) return; + + bool showInfo = false; + if (crossPlot->showInfoBox()) + { + QStringList curveInfoTexts; + for (auto curveSet : crossPlot->curveSets()) + { + QString curveInfoText = curveSet->infoText(); + if (curveSet->isChecked() && !curveInfoText.isEmpty()) + { + curveInfoTexts += curveInfoText; + } + } + QStringList infoText; + if (curveInfoTexts.size() > 1) + { + infoText += QString("
    "); + for (QString curveInfoText : curveInfoTexts) + { + infoText += QString("
  1. %1
  2. ").arg(curveInfoText); + } + infoText += QString("
"); + } + else if (curveInfoTexts.size() > 0) + { + infoText += curveInfoTexts.front(); + } + if (!infoText.empty()) + { + m_infoBox->label()->setText(infoText.join("\n")); + m_infoBox->adjustSize(); + QRect infoRect = m_infoBox->frameGeometry(); + QRect canvasRect = canvas()->frameGeometry(); + infoRect.moveTop(canvasRect.top() + 4); + infoRect.moveRight(canvasRect.right() - 4); + m_infoBox->move(infoRect.topLeft()); + showInfo = true; + } + } + if (showInfo) + { + m_infoBox->show(); + } + else + { + m_infoBox->hide(); + } +} + //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- diff --git a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h index c9b071691a..bb5664c181 100644 --- a/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h +++ b/ApplicationCode/UserInterface/RiuGridCrossQwtPlot.h @@ -29,6 +29,7 @@ class RimGridCrossPlotCurveSet; class RiuCvfOverlayItemWidget; +class RiuDraggableOverlayFrame; class RiuPlotAnnotationTool; class RimPlotAxisProperties; @@ -55,12 +56,18 @@ public: protected: void updateLayout() override; + void updateInfoBoxLayout(); void updateLegendLayout(); void resizeEvent(QResizeEvent* e) override; bool resizeOverlayItemToFitPlot(caf::TitledOverlayFrame* overlayItem); void contextMenuEvent(QContextMenuEvent*) override; private: - std::map, QPointer> m_legendWidgets; - std::unique_ptr m_annotationTool; + typedef caf::PdmPointer CurveSetPtr; + typedef QPointer LegendPtr; + typedef QPointer InfoBoxPtr; + + InfoBoxPtr m_infoBox; + std::map m_legendWidgets; + std::unique_ptr m_annotationTool; }; diff --git a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp index 8ed53aaff7..53939532e8 100644 --- a/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp +++ b/ApplicationCode/UserInterface/RiuSummaryQwtPlot.cpp @@ -123,10 +123,7 @@ void RiuSummaryQwtPlot::addOrUpdateEnsembleCurveSetLegend(RimEnsembleCurveSet* c auto it = m_ensembleLegendWidgets.find(curveSetToShowLegendFor); if (it == m_ensembleLegendWidgets.end() || it->second == nullptr) { - overlayWidget = new RiuCvfOverlayItemWidget(this); - - new RiuWidgetDragger(overlayWidget); - + overlayWidget = new RiuCvfOverlayItemWidget(this, canvas()); m_ensembleLegendWidgets[curveSetToShowLegendFor] = overlayWidget; } else diff --git a/ApplicationCode/UserInterface/RiuWidgetDragger.cpp b/ApplicationCode/UserInterface/RiuWidgetDragger.cpp index c622ca2ab0..6f7036b047 100644 --- a/ApplicationCode/UserInterface/RiuWidgetDragger.cpp +++ b/ApplicationCode/UserInterface/RiuWidgetDragger.cpp @@ -24,12 +24,22 @@ //-------------------------------------------------------------------------------------------------- /// //-------------------------------------------------------------------------------------------------- -RiuWidgetDragger::RiuWidgetDragger(QWidget* widgetToMove) +RiuWidgetDragger::RiuWidgetDragger(QWidget* widgetToMove, QWidget* widgetToSnapTo /*= nullptr*/, int snapMargins /*= 5*/) : QObject(widgetToMove) , m_widgetToMove(widgetToMove) + , m_widgetToSnapTo(widgetToSnapTo) + , m_snapMargins(snapMargins) , m_startPos(0,0) { - m_widgetToMove->installEventFilter(this); + addWidget(m_widgetToMove); +} + +//-------------------------------------------------------------------------------------------------- +/// +//-------------------------------------------------------------------------------------------------- +void RiuWidgetDragger::addWidget(QWidget* widget) +{ + widget->installEventFilter(this); } //-------------------------------------------------------------------------------------------------- @@ -42,13 +52,75 @@ bool RiuWidgetDragger::eventFilter(QObject * watched, QEvent * event) QMouseEvent* mMoveEv = static_cast(event); if (mMoveEv->buttons() & Qt::LeftButton) { - m_widgetToMove->move( m_widgetToMove->mapToParent(mMoveEv->pos() - m_startPos)); + QPoint relativeMove = mMoveEv->pos() - m_startPos; + QRect newFrameRect = m_widgetToMove->frameGeometry().translated(relativeMove); + + if (m_widgetToSnapTo) + { + QRect snapToRect = m_widgetToSnapTo->frameGeometry(); + { + QPoint snapToTopLeft = snapToRect.topLeft(); + QPoint widgetTopLeft = newFrameRect.topLeft(); + QPoint diff = snapToTopLeft - widgetTopLeft; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveLeft(snapToTopLeft.x() + m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveTop(snapToTopLeft.y() + m_snapMargins); + } + } + { + QPoint snapToBottomLeft = snapToRect.bottomLeft(); + QPoint widgetBottomLeft = newFrameRect.bottomLeft(); + QPoint diff = snapToBottomLeft - widgetBottomLeft; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveLeft(snapToBottomLeft.x() + m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveBottom(snapToBottomLeft.y() - m_snapMargins); + } + } + { + QPoint snapToTopRight = snapToRect.topRight(); + QPoint widgetTopRight = newFrameRect.topRight(); + QPoint diff = snapToTopRight - widgetTopRight; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveRight(snapToTopRight.x() - m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveTop(snapToTopRight.y() + m_snapMargins); + } + } + { + QPoint snapToBottomRight = snapToRect.bottomRight(); + QPoint widgetBottomRight = newFrameRect.bottomRight(); + QPoint diff = snapToBottomRight - widgetBottomRight; + if (std::abs(diff.x()) < 4 * m_snapMargins) + { + newFrameRect.moveRight(snapToBottomRight.x() - m_snapMargins); + } + if (std::abs(diff.y()) < 4 * m_snapMargins) + { + newFrameRect.moveBottom(snapToBottomRight.y() - m_snapMargins); + } + } + + } + m_widgetToMove->move(newFrameRect.topLeft()); + return true; } } else if (event->type() == QEvent::MouseButtonPress) { QMouseEvent* mEv = static_cast(event); m_startPos = mEv->pos(); + return true; } return false; diff --git a/ApplicationCode/UserInterface/RiuWidgetDragger.h b/ApplicationCode/UserInterface/RiuWidgetDragger.h index 016fb3b9cc..f3b6aadc8c 100644 --- a/ApplicationCode/UserInterface/RiuWidgetDragger.h +++ b/ApplicationCode/UserInterface/RiuWidgetDragger.h @@ -28,13 +28,16 @@ class RiuWidgetDragger : public QObject { Q_OBJECT public: - RiuWidgetDragger(QWidget* widgetToMove); + RiuWidgetDragger(QWidget* widgetToMove, QWidget* widgetToSnapTo = nullptr, int snapMargins = 5); + void addWidget(QWidget* widget); bool eventFilter(QObject * watched, QEvent * event) override; private: QPointer m_widgetToMove; - QPoint m_startPos; + QPointer m_widgetToSnapTo; + int m_snapMargins; + QPoint m_startPos; };