From 5662e2f354c4acee9594fcd2656ed51d0b83df57 2017-11-03 16:33:27 From: Thibaud Rabillard Date: 2017-11-03 16:33:27 Subject: [PATCH] Improves visual effect of dropping a variable in a graph --- diff --git a/gui/include/DragDropHelper.h b/gui/include/DragDropHelper.h index 871b84d..17103c4 100644 --- a/gui/include/DragDropHelper.h +++ b/gui/include/DragDropHelper.h @@ -53,6 +53,8 @@ public: QUrl imageTemporaryUrl(const QImage &image) const; + void setHightlightedDragWidget(VisualizationDragWidget *dragWidget); + private: class DragDropHelperPrivate; spimpl::unique_impl_ptr impl; diff --git a/gui/include/Visualization/VisualizationDragWidget.h b/gui/include/Visualization/VisualizationDragWidget.h index 3552cef..15924d3 100644 --- a/gui/include/Visualization/VisualizationDragWidget.h +++ b/gui/include/Visualization/VisualizationDragWidget.h @@ -13,6 +13,7 @@ public: virtual QMimeData *mimeData() const = 0; virtual bool isDragAllowed() const = 0; + virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); }; protected: virtual void mousePressEvent(QMouseEvent *event) override; diff --git a/gui/include/Visualization/VisualizationGraphWidget.h b/gui/include/Visualization/VisualizationGraphWidget.h index b0e85c7..a012cb7 100644 --- a/gui/include/Visualization/VisualizationGraphWidget.h +++ b/gui/include/Visualization/VisualizationGraphWidget.h @@ -59,6 +59,7 @@ public: // VisualisationDragWidget QMimeData *mimeData() const override; bool isDragAllowed() const override; + void highlightForMerge(bool highlighted) override; signals: void synchronize(const SqpRange &range, const SqpRange &oldRange); diff --git a/gui/src/DragDropHelper.cpp b/gui/src/DragDropHelper.cpp index a98ab82..4bc8951 100644 --- a/gui/src/DragDropHelper.cpp +++ b/gui/src/DragDropHelper.cpp @@ -29,7 +29,6 @@ struct DragDropScroller::DragDropScrollerPrivate { QScrollArea *m_CurrentScrollArea = nullptr; std::unique_ptr m_Timer = nullptr; - enum class ScrollDirection { up, down, unknown }; ScrollDirection m_Direction = ScrollDirection::unknown; @@ -148,6 +147,8 @@ struct DragDropHelper::DragDropHelperPrivate { QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using // QTemporaryFile to have a name which is not generated. + VisualizationDragWidget *m_HighlightedDragWidget = nullptr; + explicit DragDropHelperPrivate() : m_PlaceHolder{std::make_unique()}, m_DragDropScroller{std::make_unique()} @@ -188,6 +189,7 @@ DragDropHelper::~DragDropHelper() void DragDropHelper::resetDragAndDrop() { setCurrentDragWidget(nullptr); + impl->m_HighlightedDragWidget = nullptr; } void DragDropHelper::setCurrentDragWidget(VisualizationDragWidget *dragWidget) @@ -245,6 +247,18 @@ QUrl DragDropHelper::imageTemporaryUrl(const QImage &image) const return QUrl::fromLocalFile(impl->m_ImageTempUrl); } +void DragDropHelper::setHightlightedDragWidget(VisualizationDragWidget *dragWidget) +{ + if (impl->m_HighlightedDragWidget) { + impl->m_HighlightedDragWidget->highlightForMerge(false); + } + + if (dragWidget) { + impl->m_HighlightedDragWidget = dragWidget; + impl->m_HighlightedDragWidget->highlightForMerge(true); + } +} + bool DragDropHelper::checkMimeDataForVisualization(const QMimeData *mimeData, VisualizationDragDropContainer *dropContainer) { diff --git a/gui/src/Visualization/VisualizationDragDropContainer.cpp b/gui/src/Visualization/VisualizationDragDropContainer.cpp index e957a28..005611b 100644 --- a/gui/src/Visualization/VisualizationDragDropContainer.cpp +++ b/gui/src/Visualization/VisualizationDragDropContainer.cpp @@ -21,6 +21,7 @@ struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate { QStringList m_MergeAllowedMimeTypes; VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun = [](auto mimeData) { return true; }; + int m_MinContainerHeight = 0; explicit VisualizationDragDropContainerPrivate(QWidget *widget) { @@ -55,7 +56,7 @@ struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate { return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget(); } - VisualizationDragWidget *getChildDragWidgetAt(QWidget *parent, const QPoint &pos) const + VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const { VisualizationDragWidget *dragWidget = nullptr; @@ -79,6 +80,21 @@ struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate { .adjusted(adustNum, adustNum, -adustNum, -adustNum); return containerRect.contains(container->mapFromGlobal(QCursor::pos())); } + + int countDragWidget(const QWidget *parent) const + { + auto nbGraph = 0; + for (auto child : parent->children()) { + if (qobject_cast(child)) { + nbGraph += 1; + } + } + + return nbGraph; + } + + void findPlaceHolderPosition(const QPoint &pos, bool canMerge, + const VisualizationDragDropContainer *container); }; VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent) @@ -117,14 +133,7 @@ void VisualizationDragDropContainer::setMergeAllowedMimeTypes(const QStringList int VisualizationDragDropContainer::countDragWidget() const { - auto nbGraph = 0; - for (auto child : children()) { - if (qobject_cast(child)) { - nbGraph += 1; - } - } - - return nbGraph; + return impl->countDragWidget(this); } void VisualizationDragDropContainer::setAcceptMimeDataFunction( @@ -185,7 +194,7 @@ void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event) if (dragWidget) { // If the drag&drop is internal to the visualization, entering the container hide - // the dragWidget which was hidden by the dragLeaveEvent + // the dragWidget which was made visible by the dragLeaveEvent auto parentWidget = qobject_cast(dragWidget->parentWidget()); if (parentWidget) { @@ -193,26 +202,8 @@ void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event) } } - auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos()); - - if (dragWidgetHovered) { - auto hoveredWidgetIndex = impl->m_Layout->indexOf(dragWidgetHovered); - - if (dragWidget) { - auto dragWidgetIndex = impl->m_Layout->indexOf(helper.getCurrentDragWidget()); - if (dragWidgetIndex >= 0 && dragWidgetIndex <= hoveredWidgetIndex) { - // Correction of the index if the drop occurs in the same container - // and if the drag is started from the visualization (in that case, the - // dragWidget is hidden) - hoveredWidgetIndex += 1; - } - } - - helper.insertPlaceHolder(impl->m_Layout, hoveredWidgetIndex); - } - else { - helper.insertPlaceHolder(impl->m_Layout, 0); - } + auto canMerge = impl->allowMergeMimeData(event->mimeData()); + impl->findPlaceHolderPosition(event->pos(), canMerge, this); } else { // do nothing @@ -233,6 +224,8 @@ void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event) if (!impl->cursorIsInContainer(this)) { helper.removePlaceHolder(); + helper.setHightlightedDragWidget(nullptr); + impl->m_MinContainerHeight = 0; auto dragWidget = helper.getCurrentDragWidget(); if (dragWidget) { @@ -258,60 +251,8 @@ void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event) void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event) { if (impl->acceptMimeData(event->mimeData())) { - auto dragWidgetHovered = impl->getChildDragWidgetAt(this, event->pos()); - if (dragWidgetHovered) { - auto canMerge = impl->allowMergeMimeData(event->mimeData()); - - auto nbDragWidget = countDragWidget(); - if (nbDragWidget > 0) { - auto graphHeight = qMax(size().height() / nbDragWidget, GRAPH_MINIMUM_HEIGHT); - - auto dropIndex = floor(event->pos().y() / graphHeight); - auto zoneSize = qMin(graphHeight / 3.0, 150.0); - - auto isOnTop = event->pos().y() < dropIndex * graphHeight + zoneSize; - auto isOnBottom = event->pos().y() > (dropIndex + 1) * graphHeight - zoneSize; - - auto &helper = sqpApp->dragDropHelper(); - auto placeHolderIndex = impl->m_Layout->indexOf(&(helper.placeHolder())); - - if (isOnTop || isOnBottom) { - if (isOnBottom) { - dropIndex += 1; - } - - if (helper.getCurrentDragWidget()) { - auto dragWidgetIndex - = impl->m_Layout->indexOf(helper.getCurrentDragWidget()); - if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) { - // Correction of the index if the drop occurs in the same container - // and if the drag is started from the visualization (in that case, the - // dragWidget is hidden) - dropIndex += 1; - } - } - - if (dropIndex != placeHolderIndex) { - helper.insertPlaceHolder(impl->m_Layout, dropIndex); - } - } - else if (canMerge) { - // drop on the middle -> merge - if (impl->hasPlaceHolder()) { - helper.removePlaceHolder(); - } - } - } - else { - qCWarning(LOG_VisualizationDragDropContainer()) - << tr("VisualizationDragDropContainer::dragMoveEvent, no widget found in the " - "container"); - } - } - else { - // No hovered drag widget, the mouse is probably hover the placeHolder - // Do nothing - } + auto canMerge = impl->allowMergeMimeData(event->mimeData()); + impl->findPlaceHolderPosition(event->pos(), canMerge, this); } else { event->ignore(); @@ -351,12 +292,89 @@ void VisualizationDragDropContainer::dropEvent(QDropEvent *event) qCWarning(LOG_VisualizationDragDropContainer()) << tr("VisualizationDragDropContainer::dropEvent, couldn't drop because the " "placeHolder is not found."); - Q_ASSERT(false); + // Q_ASSERT(false); } } else { event->ignore(); } + sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr); + impl->m_MinContainerHeight = 0; + QWidget::dropEvent(event); } + + +void VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition( + const QPoint &pos, bool canMerge, const VisualizationDragDropContainer *container) +{ + auto &helper = sqpApp->dragDropHelper(); + + auto dragWidgetHovered = getChildDragWidgetAt(container, pos); + if (dragWidgetHovered) { + auto nbDragWidget = countDragWidget(container); + if (nbDragWidget > 0) { + + if (m_MinContainerHeight == 0) { + m_MinContainerHeight = container->size().height(); + } + + m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height()); + auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT); + + auto posY = pos.y(); + auto dropIndex = floor(posY / graphHeight); + auto zoneSize = qMin(graphHeight / 4.0, 75.0); + + + auto isOnTop = posY < dropIndex * graphHeight + zoneSize; + auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize; + + auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder())); + + if (isOnTop || isOnBottom || !canMerge) { + if (isOnBottom) { + dropIndex += 1; + } + + if (helper.getCurrentDragWidget()) { + auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget()); + if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) { + // Correction of the index if the drop occurs in the same container + // and if the drag is started from the visualization (in that case, the + // dragWidget is hidden) + dropIndex += 1; + } + } + + if (dropIndex != placeHolderIndex) { + helper.insertPlaceHolder(m_Layout, dropIndex); + } + + helper.setHightlightedDragWidget(nullptr); + } + else if (canMerge) { + // drop on the middle -> merge + if (hasPlaceHolder()) { + helper.removePlaceHolder(); + } + + helper.setHightlightedDragWidget(dragWidgetHovered); + } + } + else { + qCWarning(LOG_VisualizationDragDropContainer()) + << tr("VisualizationDragDropContainer::dragMoveEvent, no widget found in the " + "container"); + } + } + else if (!hasPlaceHolder()) { + // Drop on an empty container, just add the placeHolder at the top + helper.insertPlaceHolder(m_Layout, 0); + } + else { + // No hovered drag widget, the mouse is probably hover the placeHolder + // Do nothing + } +} diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index 14dfe20..10d251b 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -243,6 +243,18 @@ bool VisualizationGraphWidget::isDragAllowed() const return true; } +void VisualizationGraphWidget::highlightForMerge(bool highlighted) +{ + if (highlighted) { + plot().setBackground(QBrush(QColor("#BBD5EE"))); + } + else { + plot().setBackground(QBrush(Qt::white)); + } + + plot().update(); +} + void VisualizationGraphWidget::closeEvent(QCloseEvent *event) { Q_UNUSED(event); diff --git a/gui/src/Visualization/VisualizationZoneWidget.cpp b/gui/src/Visualization/VisualizationZoneWidget.cpp index 171e6c2..2f1642e 100644 --- a/gui/src/Visualization/VisualizationZoneWidget.cpp +++ b/gui/src/Visualization/VisualizationZoneWidget.cpp @@ -86,6 +86,7 @@ VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *p ui->zoneNameLabel->setText(name); ui->dragDropContainer->setAcceptedMimeTypes({MIME_TYPE_GRAPH, MIME_TYPE_VARIABLE_LIST}); + ui->dragDropContainer->setMergeAllowedMimeTypes({MIME_TYPE_VARIABLE_LIST}); ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) { return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData, ui->dragDropContainer);