##// END OF EJS Templates
Fix the close button on the graphs and multi selection in the same graph
Fix the close button on the graphs and multi selection in the same graph

File last commit:

r1047:d404ba4b75e5
r1054:f391b1d9fb19
Show More
VisualizationDragDropContainer.cpp
499 lines | 17.8 KiB | text/x-c | CppLexer
/ gui / src / Visualization / VisualizationDragDropContainer.cpp
New visualization classes for the drag&drop
r838 #include "Visualization/VisualizationDragDropContainer.h"
Moves the DragDropHelper file
r884 #include "DragAndDrop/DragDropHelper.h"
Format changes
r844 #include "SqpApplication.h"
#include "Visualization/VisualizationDragWidget.h"
New visualization classes for the drag&drop
r838
Move the GRAPH_MINIMUM_HEIGHT constant in a place accessible everywhere and use it in the drag&drop
r851 #include "Common/VisualizationDef.h"
New visualization classes for the drag&drop
r838 #include <QDrag>
#include <QDragEnterEvent>
Format changes
r844 #include <QVBoxLayout>
New visualization classes for the drag&drop
r838
MR for linux compilation
r845 #include <cmath>
New visualization classes for the drag&drop
r838 #include <memory>
drop of variables in the visualization
r850 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
Displays the miniature of the graph of the zone during a drag
r934 auto DRAGGED_MINIATURE_WIDTH = 200; // in pixels
New visualization classes for the drag&drop
r838 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
Format changes
r844 QVBoxLayout *m_Layout;
Drag of the time widget on a graph
r879 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
Add an empty area at the bottom of the tab where a new zone can be created from a drop. Differentiate graph and zone placeHolders.
r881 QString m_PlaceHolderText;
Implements cursor mode
r960 DragDropHelper::PlaceHolderType m_PlaceHolderType;
Drag of the time widget on a graph
r879
drop of variables in the visualization
r850 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
= [](auto mimeData) { return true; };
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023 VisualizationDragDropContainer::AcceptDragWidgetFunction m_AcceptDragWidgetFun
= [](auto dragWidget, auto mimeData) { return true; };
Drag of the time widget on a graph
r879
Improves visual effect of dropping a variable in a graph
r873 int m_MinContainerHeight = 0;
New visualization classes for the drag&drop
r838
Format changes
r844 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
Implements cursor mode
r960 : m_PlaceHolderType(DragDropHelper::PlaceHolderType::Graph)
New visualization classes for the drag&drop
r838 {
Format changes
r844 m_Layout = new QVBoxLayout(widget);
m_Layout->setContentsMargins(0, 0, 0, 0);
New visualization classes for the drag&drop
r838 }
Format changes
r844 bool acceptMimeData(const QMimeData *data) const
New visualization classes for the drag&drop
r838 {
drop of zone on the time widget
r936 auto accepted = false;
for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
++it) {
const auto &type = it.key();
const auto &behavior = it.value();
if (data->hasFormat(type)) {
if (behavior != DropBehavior::Forbidden) {
accepted = true;
}
else {
accepted = false;
break;
}
Format changes
r844 }
New visualization classes for the drag&drop
r838 }
drop of zone on the time widget
r936 if (accepted) {
accepted = m_AcceptMimeDataFun(data);
}
return accepted;
New visualization classes for the drag&drop
r838 }
Drag of the time widget on a graph
r879 bool allowMergeForMimeData(const QMimeData *data) const
New visualization classes for the drag&drop
r838 {
code improvements
r939 auto result = false;
Drag of the time widget on a graph
r879 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
++it) {
if (data->hasFormat(it.key())
&& (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
|| it.value()
== VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
result = true;
}
else if (data->hasFormat(it.key())
&& it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
// Merge is forbidden if the mime data contain an acceptable type which cannot be
// merged
result = false;
break;
}
}
return result;
}
bool allowInsertForMimeData(const QMimeData *data) const
{
for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
++it) {
if (data->hasFormat(it.key())
&& (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
|| it.value()
== VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
New visualization classes for the drag&drop
r838 return true;
Format changes
r844 }
New visualization classes for the drag&drop
r838 }
return false;
}
bool hasPlaceHolder() const
{
Format changes
r844 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
New visualization classes for the drag&drop
r838 }
Improves visual effect of dropping a variable in a graph
r873 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
New visualization classes for the drag&drop
r838 {
Format changes
r844 VisualizationDragWidget *dragWidget = nullptr;
for (auto child : parent->children()) {
auto widget = qobject_cast<VisualizationDragWidget *>(child);
if (widget && widget->isVisible()) {
if (widget->frameGeometry().contains(pos)) {
New visualization classes for the drag&drop
r838 dragWidget = widget;
break;
}
}
}
return dragWidget;
}
Format changes
r844 bool cursorIsInContainer(QWidget *container) const
New visualization classes for the drag&drop
r838 {
fix some wrong drag&drop behavior appearing on mac
r938 auto widgetUnderMouse = sqpApp->widgetAt(QCursor::pos());
return container->isAncestorOf(widgetUnderMouse) && widgetUnderMouse != container
&& sqpApp->dragDropHelper().placeHolder().isAncestorOf(widgetUnderMouse);
New visualization classes for the drag&drop
r838 }
Improves visual effect of dropping a variable in a graph
r873
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
Improves visual effect of dropping a variable in a graph
r873 {
auto nbGraph = 0;
for (auto child : parent->children()) {
if (qobject_cast<VisualizationDragWidget *>(child)) {
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
nbGraph += 1;
}
Improves visual effect of dropping a variable in a graph
r873 }
}
return nbGraph;
}
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023 bool findPlaceHolderPosition(const QPoint &pos, const QMimeData *mimeData, bool canInsert,
bool canMerge, const VisualizationDragDropContainer *container);
New visualization classes for the drag&drop
r838 };
VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 : QFrame{parent},
Format changes
r844 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
New visualization classes for the drag&drop
r838 {
setAcceptDrops(true);
}
void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
{
Format changes
r844 impl->m_Layout->addWidget(dragWidget);
New visualization classes for the drag&drop
r838 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
Format changes
r844 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
&VisualizationDragDropContainer::startDrag);
New visualization classes for the drag&drop
r838 }
Format changes
r844 void VisualizationDragDropContainer::insertDragWidget(int index,
VisualizationDragWidget *dragWidget)
New visualization classes for the drag&drop
r838 {
Format changes
r844 impl->m_Layout->insertWidget(index, dragWidget);
New visualization classes for the drag&drop
r838 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
Format changes
r844 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
&VisualizationDragDropContainer::startDrag);
New visualization classes for the drag&drop
r838 }
drop of zone on the time widget
r936 void VisualizationDragDropContainer::setMimeType(
Drag of the time widget on a graph
r879 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
New visualization classes for the drag&drop
r838 {
Drag of the time widget on a graph
r879 impl->m_AcceptedMimeTypes[mimeType] = behavior;
New visualization classes for the drag&drop
r838 }
int VisualizationDragDropContainer::countDragWidget() const
{
Improves visual effect of dropping a variable in a graph
r873 return impl->countDragWidget(this);
New visualization classes for the drag&drop
r838 }
drop of variables in the visualization
r850 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
VisualizationDragDropContainer::AcceptMimeDataFunction fun)
{
impl->m_AcceptMimeDataFun = fun;
}
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023 void VisualizationDragDropContainer::setAcceptDragWidgetFunction(
VisualizationDragDropContainer::AcceptDragWidgetFunction fun)
{
impl->m_AcceptDragWidgetFun = fun;
}
Add an empty area at the bottom of the tab where a new zone can be created from a drop. Differentiate graph and zone placeHolders.
r881 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
const QString &placeHolderText)
{
impl->m_PlaceHolderType = type;
impl->m_PlaceHolderText = placeHolderText;
}
Format changes
r844 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
const QPoint &dragPosition)
New visualization classes for the drag&drop
r838 {
Format changes
r844 auto &helper = sqpApp->dragDropHelper();
drop of variables in the visualization
r850 helper.resetDragAndDrop();
New visualization classes for the drag&drop
r838
Format changes
r844 // Note: The management of the drag object is done by Qt
Fixes for review
r846 auto drag = new QDrag{dragWidget};
New visualization classes for the drag&drop
r838
drag of selection zones
r1047 auto mimeData = dragWidget->mimeData(dragPosition);
New visualization classes for the drag&drop
r838 drag->setMimeData(mimeData);
drag of selection zones
r1047 auto pixmap = dragWidget->customDragPixmap(dragPosition);
if (pixmap.isNull()) {
pixmap = QPixmap{dragWidget->size()};
dragWidget->render(&pixmap);
}
Displays the miniature of the graph of the zone during a drag
r934 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
Qt::KeepAspectRatio, Qt::SmoothTransformation));
New visualization classes for the drag&drop
r838
auto image = pixmap.toImage();
mimeData->setImageData(image);
mimeData->setUrls({helper.imageTemporaryUrl(image)});
Format changes
r844 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
New visualization classes for the drag&drop
r838
drag of selection zones
r1047 if (impl->acceptMimeData(mimeData) && impl->allowInsertForMimeData(mimeData)) {
helper.setCurrentDragWidget(dragWidget);
if (impl->cursorIsInContainer(this)) {
auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
impl->m_PlaceHolderText);
dragWidget->setVisible(false);
}
else {
// The drag starts directly outside the drop zone
// do not add the placeHolder
}
Improves reliability
r874 }
New visualization classes for the drag&drop
r838
Thibaud Rabillard
Fix for D&D bug on mac
r911 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
helper.doCloseWidgets();
drop of variables in the visualization
r850 }
else {
qCWarning(LOG_VisualizationDragDropContainer())
<< tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
"VisualizationDragWidget is not found in this container.");
}
New visualization classes for the drag&drop
r838 }
void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
{
Format changes
r844 if (impl->acceptMimeData(event->mimeData())) {
New visualization classes for the drag&drop
r838 event->acceptProposedAction();
Format changes
r844 auto &helper = sqpApp->dragDropHelper();
New visualization classes for the drag&drop
r838
Format changes
r844 if (!impl->hasPlaceHolder()) {
New visualization classes for the drag&drop
r838 auto dragWidget = helper.getCurrentDragWidget();
drop of variables in the visualization
r850
if (dragWidget) {
// If the drag&drop is internal to the visualization, entering the container hide
Improves visual effect of dropping a variable in a graph
r873 // the dragWidget which was made visible by the dragLeaveEvent
drop of variables in the visualization
r850 auto parentWidget
= qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
if (parentWidget) {
dragWidget->setVisible(false);
}
New visualization classes for the drag&drop
r838 }
Drag of the time widget on a graph
r879 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
auto canInsert = impl->allowInsertForMimeData(event->mimeData());
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023 if (!impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge,
this)) {
event->ignore();
}
New visualization classes for the drag&drop
r838 }
drop of variables in the visualization
r850 else {
// do nothing
}
New visualization classes for the drag&drop
r838 }
Fixes for review
r846 else {
New visualization classes for the drag&drop
r838 event->ignore();
Fixes for review
r846 }
New visualization classes for the drag&drop
r838
QWidget::dragEnterEvent(event);
}
void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
{
Q_UNUSED(event);
Format changes
r844 auto &helper = sqpApp->dragDropHelper();
New visualization classes for the drag&drop
r838
Format changes
r844 if (!impl->cursorIsInContainer(this)) {
New visualization classes for the drag&drop
r838 helper.removePlaceHolder();
Improves visual effect of dropping a variable in a graph
r873 helper.setHightlightedDragWidget(nullptr);
impl->m_MinContainerHeight = 0;
New visualization classes for the drag&drop
r838
drop of variables in the visualization
r850 auto dragWidget = helper.getCurrentDragWidget();
if (dragWidget) {
// dragWidget has a value only if the drag is started from the visualization
// In that case, shows the drag widget at its original place
Format changes
r844 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
// drop zone (It is not possible to catch a drop event outside of the application)
New visualization classes for the drag&drop
r838
Format changes
r844 if (dragWidget) {
New visualization classes for the drag&drop
r838 dragWidget->setVisible(true);
}
}
}
drop of variables in the visualization
r850 else {
// Leave event probably received for a child widget.
// Do nothing.
// Note: The DragLeave event, doesn't have any mean to determine who sent it.
}
New visualization classes for the drag&drop
r838
QWidget::dragLeaveEvent(event);
}
void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
{
Format changes
r844 if (impl->acceptMimeData(event->mimeData())) {
Drag of the time widget on a graph
r879 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
auto canInsert = impl->allowInsertForMimeData(event->mimeData());
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023 impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge, this);
New visualization classes for the drag&drop
r838 }
Fixes for review
r846 else {
New visualization classes for the drag&drop
r838 event->ignore();
Fixes for review
r846 }
New visualization classes for the drag&drop
r838
QWidget::dragMoveEvent(event);
}
void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
{
drop of variable inside an existing graph
r875 auto &helper = sqpApp->dragDropHelper();
Format changes
r844 if (impl->acceptMimeData(event->mimeData())) {
drop of variable inside an existing graph
r875 auto dragWidget = helper.getCurrentDragWidget();
drop of variables in the visualization
r850 if (impl->hasPlaceHolder()) {
drop of variable inside an existing graph
r875 // drop where the placeHolder is located
New visualization classes for the drag&drop
r838
Drag of the time widget on a graph
r879 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
if (canInsert) {
auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
New visualization classes for the drag&drop
r838
Drag of the time widget on a graph
r879 if (dragWidget) {
auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
// 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)
droppedIndex -= 1;
}
New visualization classes for the drag&drop
r838
Drag of the time widget on a graph
r879 dragWidget->setVisible(true);
}
New visualization classes for the drag&drop
r838
Drag of the time widget on a graph
r879 event->acceptProposedAction();
New visualization classes for the drag&drop
r838
Drag of the time widget on a graph
r879 helper.removePlaceHolder();
New visualization classes for the drag&drop
r838
Drag of the time widget on a graph
r879 emit dropOccuredInContainer(droppedIndex, event->mimeData());
}
else {
qCWarning(LOG_VisualizationDragDropContainer()) << tr(
"VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
"the insertion is forbidden.");
Q_ASSERT(false);
}
New visualization classes for the drag&drop
r838 }
drop of variable inside an existing graph
r875 else if (helper.getHightlightedDragWidget()) {
// drop on the highlighted widget
Drag of the time widget on a graph
r879 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
drop of variable inside an existing graph
r875 if (canMerge) {
event->acceptProposedAction();
emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
}
else {
qCWarning(LOG_VisualizationDragDropContainer())
<< tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
"the merge is forbidden.");
Q_ASSERT(false);
}
drop of variables in the visualization
r850 }
New visualization classes for the drag&drop
r838 }
Fixes for review
r846 else {
New visualization classes for the drag&drop
r838 event->ignore();
Fixes for review
r846 }
New visualization classes for the drag&drop
r838
Improves visual effect of dropping a variable in a graph
r873 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
impl->m_MinContainerHeight = 0;
New visualization classes for the drag&drop
r838 QWidget::dropEvent(event);
}
Improves visual effect of dropping a variable in a graph
r873
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023 bool VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
const QPoint &pos, const QMimeData *mimeData, bool canInsert, bool canMerge,
Drag of the time widget on a graph
r879 const VisualizationDragDropContainer *container)
Improves visual effect of dropping a variable in a graph
r873 {
auto &helper = sqpApp->dragDropHelper();
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 auto absPos = container->mapToGlobal(pos);
fix some wrong drag&drop behavior appearing on mac
r938 auto isOnPlaceHolder = helper.placeHolder().isAncestorOf(sqpApp->widgetAt(absPos));
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880
if (countDragWidget(container, true) == 0) {
// Drop on an empty container, just add the placeHolder at the top
Add an empty area at the bottom of the tab where a new zone can be created from a drop. Differentiate graph and zone placeHolders.
r881 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 }
else if (!isOnPlaceHolder) {
Improves visual effect of dropping a variable in a graph
r873 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()));
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
Drag of the time widget on a graph
r879 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
Improves visual effect of dropping a variable in a graph
r873 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) {
Add an empty area at the bottom of the tab where a new zone can be created from a drop. Differentiate graph and zone placeHolders.
r881 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
m_PlaceHolderText);
Improves visual effect of dropping a variable in a graph
r873 }
helper.setHightlightedDragWidget(nullptr);
}
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 else if (canMerge && dragWidgetHovered) {
Improves visual effect of dropping a variable in a graph
r873 // drop on the middle -> merge
if (hasPlaceHolder()) {
helper.removePlaceHolder();
}
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023 if (m_AcceptDragWidgetFun(dragWidgetHovered, mimeData)) {
helper.setHightlightedDragWidget(dragWidgetHovered);
return true;
}
else {
return false;
}
Improves visual effect of dropping a variable in a graph
r873 }
Drag of the time widget on a graph
r879 else {
Add an empty area at the bottom of the tab where a new zone can be created from a drop. Differentiate graph and zone placeHolders.
r881 qCWarning(LOG_VisualizationDragDropContainer())
<< tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
"action.");
Drag of the time widget on a graph
r879 }
Improves visual effect of dropping a variable in a graph
r873 }
else {
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 qCWarning(LOG_VisualizationDragDropContainer())
Add an empty area at the bottom of the tab where a new zone can be created from a drop. Differentiate graph and zone placeHolders.
r881 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
"found in the "
"container");
Improves visual effect of dropping a variable in a graph
r873 }
}
else {
Fix some glitches which occurred when dragging in the visualization something from the sides.
r880 // the mouse is hover the placeHolder
Improves visual effect of dropping a variable in a graph
r873 // Do nothing
}
Alexandre Leroux
Handle the previous prohibition for drag and drop
r1023
return true;
Improves visual effect of dropping a variable in a graph
r873 }