##// END OF EJS Templates
drag of selection zones
trabillard -
r1087:d404ba4b75e5
parent child
Show More
@@ -1,19 +1,20
1 #ifndef SCIQLOP_MIMETYPESDEF_H
1 #ifndef SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
2 #define SCIQLOP_MIMETYPESDEF_H
3
3
4 #include "CoreGlobal.h"
4 #include "CoreGlobal.h"
5
5
6 #include <QString>
6 #include <QString>
7
7
8 // ////////////////// //
8 // ////////////////// //
9 // SciQlop Mime Types //
9 // SciQlop Mime Types //
10 // ////////////////// //
10 // ////////////////// //
11
11
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
12 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_GRAPH;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
13 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_ZONE;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
14 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_VARIABLE_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
15 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_PRODUCT_LIST;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
16 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_TIME_RANGE;
17 extern SCIQLOP_CORE_EXPORT const QString MIME_TYPE_SELECTION_ZONE;
17
18
18
19
19 #endif // SCIQLOP_MIMETYPESDEF_H
20 #endif // SCIQLOP_MIMETYPESDEF_H
@@ -1,7 +1,8
1 #include "Common/MimeTypesDef.h"
1 #include "Common/MimeTypesDef.h"
2
2
3 const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph");
3 const QString MIME_TYPE_GRAPH = QStringLiteral("sciqlop/graph");
4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
4 const QString MIME_TYPE_ZONE = QStringLiteral("sciqlop/zone");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
5 const QString MIME_TYPE_VARIABLE_LIST = QStringLiteral("sciqlop/var-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
6 const QString MIME_TYPE_PRODUCT_LIST = QStringLiteral("sciqlop/product-list");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
7 const QString MIME_TYPE_TIME_RANGE = QStringLiteral("sciqlop/time-range");
8 const QString MIME_TYPE_SELECTION_ZONE = QStringLiteral("sciqlop/selection-zone");
@@ -1,30 +1,34
1 #ifndef SCIQLOP_VISUALIZATIONDRAGWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONDRAGWIDGET_H
2 #define SCIQLOP_VISUALIZATIONDRAGWIDGET_H
2 #define SCIQLOP_VISUALIZATIONDRAGWIDGET_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <QMimeData>
5 #include <QMimeData>
6 #include <QWidget>
6 #include <QWidget>
7
7
8 class VisualizationDragWidget : public QWidget {
8 class VisualizationDragWidget : public QWidget {
9 Q_OBJECT
9 Q_OBJECT
10
10
11 public:
11 public:
12 VisualizationDragWidget(QWidget *parent = nullptr);
12 VisualizationDragWidget(QWidget *parent = nullptr);
13
13
14 virtual QMimeData *mimeData() const = 0;
14 virtual QMimeData *mimeData(const QPoint &position) const = 0;
15 virtual bool isDragAllowed() const = 0;
15 virtual bool isDragAllowed() const = 0;
16 virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); };
16 virtual void highlightForMerge(bool highlighted) { Q_UNUSED(highlighted); }
17
18 /// Custom pixmap to display during a drag operation.
19 /// If the provided pixmap is null, a pixmap of the entire widget is used.
20 virtual QPixmap customDragPixmap(const QPoint &dragPosition);
17
21
18 protected:
22 protected:
19 virtual void mousePressEvent(QMouseEvent *event) override;
23 virtual void mousePressEvent(QMouseEvent *event) override;
20 virtual void mouseMoveEvent(QMouseEvent *event) override;
24 virtual void mouseMoveEvent(QMouseEvent *event) override;
21
25
22 private:
26 private:
23 class VisualizationDragWidgetPrivate;
27 class VisualizationDragWidgetPrivate;
24 spimpl::unique_impl_ptr<VisualizationDragWidgetPrivate> impl;
28 spimpl::unique_impl_ptr<VisualizationDragWidgetPrivate> impl;
25
29
26 signals:
30 signals:
27 void dragDetected(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
31 void dragDetected(VisualizationDragWidget *dragWidget, const QPoint &dragPosition);
28 };
32 };
29
33
30 #endif // SCIQLOP_VISUALIZATIONDRAGWIDGET_H
34 #endif // SCIQLOP_VISUALIZATIONDRAGWIDGET_H
@@ -1,126 +1,127
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15
15
16 class QCPRange;
16 class QCPRange;
17 class QCustomPlot;
17 class QCustomPlot;
18 class SqpRange;
18 class SqpRange;
19 class Variable;
19 class Variable;
20 class VisualizationZoneWidget;
20 class VisualizationZoneWidget;
21
21
22 namespace Ui {
22 namespace Ui {
23 class VisualizationGraphWidget;
23 class VisualizationGraphWidget;
24 } // namespace Ui
24 } // namespace Ui
25
25
26 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
26 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
27 Q_OBJECT
27 Q_OBJECT
28
28
29 friend class QCustomPlotSynchronizer;
29 friend class QCustomPlotSynchronizer;
30 friend class VisualizationGraphRenderingDelegate;
30 friend class VisualizationGraphRenderingDelegate;
31
31
32 public:
32 public:
33 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
33 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
34 virtual ~VisualizationGraphWidget();
34 virtual ~VisualizationGraphWidget();
35
35
36 VisualizationZoneWidget *parentZoneWidget() const noexcept;
36 VisualizationZoneWidget *parentZoneWidget() const noexcept;
37
37
38 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
38 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
39 void enableAcquisition(bool enable);
39 void enableAcquisition(bool enable);
40
40
41 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
41 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
42
42
43 /// Removes a variable from the graph
43 /// Removes a variable from the graph
44 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
44 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
45
45
46 /// Returns the list of all variables used in the graph
46 /// Returns the list of all variables used in the graph
47 QList<std::shared_ptr<Variable> > variables() const;
47 QList<std::shared_ptr<Variable> > variables() const;
48
48
49 /// Sets the y-axis range based on the data of a variable
49 /// Sets the y-axis range based on the data of a variable
50 void setYRange(std::shared_ptr<Variable> variable);
50 void setYRange(std::shared_ptr<Variable> variable);
51 SqpRange graphRange() const noexcept;
51 SqpRange graphRange() const noexcept;
52 void setGraphRange(const SqpRange &range);
52 void setGraphRange(const SqpRange &range);
53
53
54 /// Undo the last zoom done with a zoom box
54 /// Undo the last zoom done with a zoom box
55 void undoZoom();
55 void undoZoom();
56
56
57 // IVisualizationWidget interface
57 // IVisualizationWidget interface
58 void accept(IVisualizationWidgetVisitor *visitor) override;
58 void accept(IVisualizationWidgetVisitor *visitor) override;
59 bool canDrop(const Variable &variable) const override;
59 bool canDrop(const Variable &variable) const override;
60 bool contains(const Variable &variable) const override;
60 bool contains(const Variable &variable) const override;
61 QString name() const override;
61 QString name() const override;
62
62
63 // VisualisationDragWidget
63 // VisualisationDragWidget
64 QMimeData *mimeData() const override;
64 QMimeData *mimeData(const QPoint &position) const override;
65 QPixmap customDragPixmap(const QPoint &dragPosition) override;
65 bool isDragAllowed() const override;
66 bool isDragAllowed() const override;
66 void highlightForMerge(bool highlighted) override;
67 void highlightForMerge(bool highlighted) override;
67
68
68 // Cursors
69 // Cursors
69 /// Adds or moves the vertical cursor at the specified value on the x-axis
70 /// Adds or moves the vertical cursor at the specified value on the x-axis
70 void addVerticalCursor(double time);
71 void addVerticalCursor(double time);
71 /// Adds or moves the vertical cursor at the specified value on the x-axis
72 /// Adds or moves the vertical cursor at the specified value on the x-axis
72 void addVerticalCursorAtViewportPosition(double position);
73 void addVerticalCursorAtViewportPosition(double position);
73 void removeVerticalCursor();
74 void removeVerticalCursor();
74 /// Adds or moves the vertical cursor at the specified value on the y-axis
75 /// Adds or moves the vertical cursor at the specified value on the y-axis
75 void addHorizontalCursor(double value);
76 void addHorizontalCursor(double value);
76 /// Adds or moves the vertical cursor at the specified value on the y-axis
77 /// Adds or moves the vertical cursor at the specified value on the y-axis
77 void addHorizontalCursorAtViewportPosition(double position);
78 void addHorizontalCursorAtViewportPosition(double position);
78 void removeHorizontalCursor();
79 void removeHorizontalCursor();
79
80
80 signals:
81 signals:
81 void synchronize(const SqpRange &range, const SqpRange &oldRange);
82 void synchronize(const SqpRange &range, const SqpRange &oldRange);
82 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
83 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
83 bool synchronise);
84 bool synchronise);
84
85
85 /// Signal emitted when the variable is about to be removed from the graph
86 /// Signal emitted when the variable is about to be removed from the graph
86 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
87 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
87 /// Signal emitted when the variable has been added to the graph
88 /// Signal emitted when the variable has been added to the graph
88 void variableAdded(std::shared_ptr<Variable> var);
89 void variableAdded(std::shared_ptr<Variable> var);
89
90
90 protected:
91 protected:
91 void closeEvent(QCloseEvent *event) override;
92 void closeEvent(QCloseEvent *event) override;
92 void enterEvent(QEvent *event) override;
93 void enterEvent(QEvent *event) override;
93 void leaveEvent(QEvent *event) override;
94 void leaveEvent(QEvent *event) override;
94
95
95 QCustomPlot &plot() noexcept;
96 QCustomPlot &plot() const noexcept;
96
97
97 private:
98 private:
98 Ui::VisualizationGraphWidget *ui;
99 Ui::VisualizationGraphWidget *ui;
99
100
100 class VisualizationGraphWidgetPrivate;
101 class VisualizationGraphWidgetPrivate;
101 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
102 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
102
103
103 private slots:
104 private slots:
104 /// Slot called when right clicking on the graph (displays a menu)
105 /// Slot called when right clicking on the graph (displays a menu)
105 void onGraphMenuRequested(const QPoint &pos) noexcept;
106 void onGraphMenuRequested(const QPoint &pos) noexcept;
106
107
107 /// Rescale the X axe to range parameter
108 /// Rescale the X axe to range parameter
108 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
109 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
109
110
110 /// Slot called when a mouse double click was made
111 /// Slot called when a mouse double click was made
111 void onMouseDoubleClick(QMouseEvent *event) noexcept;
112 void onMouseDoubleClick(QMouseEvent *event) noexcept;
112 /// Slot called when a mouse move was made
113 /// Slot called when a mouse move was made
113 void onMouseMove(QMouseEvent *event) noexcept;
114 void onMouseMove(QMouseEvent *event) noexcept;
114 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
115 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
115 void onMouseWheel(QWheelEvent *event) noexcept;
116 void onMouseWheel(QWheelEvent *event) noexcept;
116 /// Slot called when a mouse press was made, to activate the calibration of a graph
117 /// Slot called when a mouse press was made, to activate the calibration of a graph
117 void onMousePress(QMouseEvent *event) noexcept;
118 void onMousePress(QMouseEvent *event) noexcept;
118 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
119 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
119 void onMouseRelease(QMouseEvent *event) noexcept;
120 void onMouseRelease(QMouseEvent *event) noexcept;
120
121
121 void onDataCacheVariableUpdated();
122 void onDataCacheVariableUpdated();
122
123
123 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
124 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
124 };
125 };
125
126
126 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
127 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,95 +1,95
1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
2 #define SCIQLOP_VISUALIZATIONZONEWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
5 #include "Visualization/VisualizationDragWidget.h"
6
6
7 #include <QLoggingCategory>
7 #include <QLoggingCategory>
8 #include <QWidget>
8 #include <QWidget>
9
9
10 #include <memory>
10 #include <memory>
11
11
12 #include <Common/spimpl.h>
12 #include <Common/spimpl.h>
13
13
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
14 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationZoneWidget)
15
15
16 namespace Ui {
16 namespace Ui {
17 class VisualizationZoneWidget;
17 class VisualizationZoneWidget;
18 } // namespace Ui
18 } // namespace Ui
19
19
20 class Variable;
20 class Variable;
21 class VisualizationGraphWidget;
21 class VisualizationGraphWidget;
22
22
23 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
23 class VisualizationZoneWidget : public VisualizationDragWidget, public IVisualizationWidget {
24 Q_OBJECT
24 Q_OBJECT
25
25
26 public:
26 public:
27 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
27 explicit VisualizationZoneWidget(const QString &name = {}, QWidget *parent = 0);
28 virtual ~VisualizationZoneWidget();
28 virtual ~VisualizationZoneWidget();
29
29
30 /// Adds a graph widget
30 /// Adds a graph widget
31 void addGraph(VisualizationGraphWidget *graphWidget);
31 void addGraph(VisualizationGraphWidget *graphWidget);
32
32
33 /// Inserts a graph widget
33 /// Inserts a graph widget
34 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
34 void insertGraph(int index, VisualizationGraphWidget *graphWidget);
35
35
36 /**
36 /**
37 * Creates a graph using a variable. The variable will be displayed in the new graph.
37 * Creates a graph using a variable. The variable will be displayed in the new graph.
38 * The graph is added at the end.
38 * The graph is added at the end.
39 * @param variable the variable for which to create the graph
39 * @param variable the variable for which to create the graph
40 * @return the pointer to the created graph
40 * @return the pointer to the created graph
41 */
41 */
42 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
42 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable);
43
43
44 /**
44 /**
45 * Creates a graph using a variable. The variable will be displayed in the new graph.
45 * Creates a graph using a variable. The variable will be displayed in the new graph.
46 * The graph is inserted at the specified index.
46 * The graph is inserted at the specified index.
47 * @param variable the variable for which to create the graph
47 * @param variable the variable for which to create the graph
48 * @param index The index where the graph should be inserted in the layout
48 * @param index The index where the graph should be inserted in the layout
49 * @return the pointer to the created graph
49 * @return the pointer to the created graph
50 */
50 */
51 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
51 VisualizationGraphWidget *createGraph(std::shared_ptr<Variable> variable, int index);
52
52
53 /**
53 /**
54 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
54 * Creates a graph using a list of variables. The variables will be displayed in the new graph.
55 * The graph is inserted at the specified index.
55 * The graph is inserted at the specified index.
56 * @param variables List of variables to be added to the graph
56 * @param variables List of variables to be added to the graph
57 * @param index The index where the graph should be inserted in the layout
57 * @param index The index where the graph should be inserted in the layout
58 * @return the pointer to the created graph
58 * @return the pointer to the created graph
59 */
59 */
60 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
60 VisualizationGraphWidget *createGraph(const QList<std::shared_ptr<Variable> > variables,
61 int index);
61 int index);
62
62
63 // IVisualizationWidget interface
63 // IVisualizationWidget interface
64 void accept(IVisualizationWidgetVisitor *visitor) override;
64 void accept(IVisualizationWidgetVisitor *visitor) override;
65 bool canDrop(const Variable &variable) const override;
65 bool canDrop(const Variable &variable) const override;
66 bool contains(const Variable &variable) const override;
66 bool contains(const Variable &variable) const override;
67 QString name() const override;
67 QString name() const override;
68
68
69 // VisualisationDragWidget
69 // VisualisationDragWidget
70 QMimeData *mimeData() const override;
70 QMimeData *mimeData(const QPoint &position) const override;
71 bool isDragAllowed() const override;
71 bool isDragAllowed() const override;
72
72
73 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
73 void notifyMouseMoveInGraph(const QPointF &graphPosition, const QPointF &plotPosition,
74 VisualizationGraphWidget *graphWidget);
74 VisualizationGraphWidget *graphWidget);
75 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
75 void notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget);
76
76
77 protected:
77 protected:
78 void closeEvent(QCloseEvent *event) override;
78 void closeEvent(QCloseEvent *event) override;
79
79
80 private:
80 private:
81 Ui::VisualizationZoneWidget *ui;
81 Ui::VisualizationZoneWidget *ui;
82
82
83 class VisualizationZoneWidgetPrivate;
83 class VisualizationZoneWidgetPrivate;
84 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
84 spimpl::unique_impl_ptr<VisualizationZoneWidgetPrivate> impl;
85
85
86 private slots:
86 private slots:
87 void onVariableAdded(std::shared_ptr<Variable> variable);
87 void onVariableAdded(std::shared_ptr<Variable> variable);
88 /// Slot called when a variable is about to be removed from a graph contained in the zone
88 /// Slot called when a variable is about to be removed from a graph contained in the zone
89 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
89 void onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable);
90
90
91 void dropMimeData(int index, const QMimeData *mimeData);
91 void dropMimeData(int index, const QMimeData *mimeData);
92 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
92 void dropMimeDataOnGraph(VisualizationDragWidget *dragWidget, const QMimeData *mimeData);
93 };
93 };
94
94
95 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
95 #endif // SCIQLOP_VISUALIZATIONZONEWIDGET_H
@@ -1,492 +1,499
1 #include "Visualization/VisualizationDragDropContainer.h"
1 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "DragAndDrop/DragDropHelper.h"
2 #include "DragAndDrop/DragDropHelper.h"
3 #include "SqpApplication.h"
3 #include "SqpApplication.h"
4 #include "Visualization/VisualizationDragWidget.h"
4 #include "Visualization/VisualizationDragWidget.h"
5
5
6 #include "Common/VisualizationDef.h"
6 #include "Common/VisualizationDef.h"
7
7
8 #include <QDrag>
8 #include <QDrag>
9 #include <QDragEnterEvent>
9 #include <QDragEnterEvent>
10 #include <QVBoxLayout>
10 #include <QVBoxLayout>
11
11
12 #include <cmath>
12 #include <cmath>
13 #include <memory>
13 #include <memory>
14
14
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
15 Q_LOGGING_CATEGORY(LOG_VisualizationDragDropContainer, "VisualizationDragDropContainer")
16
16
17 auto DRAGGED_MINIATURE_WIDTH = 200; // in pixels
17 auto DRAGGED_MINIATURE_WIDTH = 200; // in pixels
18
18
19 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
19 struct VisualizationDragDropContainer::VisualizationDragDropContainerPrivate {
20
20
21 QVBoxLayout *m_Layout;
21 QVBoxLayout *m_Layout;
22 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
22 QHash<QString, VisualizationDragDropContainer::DropBehavior> m_AcceptedMimeTypes;
23 QString m_PlaceHolderText;
23 QString m_PlaceHolderText;
24 DragDropHelper::PlaceHolderType m_PlaceHolderType;
24 DragDropHelper::PlaceHolderType m_PlaceHolderType;
25
25
26 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
26 VisualizationDragDropContainer::AcceptMimeDataFunction m_AcceptMimeDataFun
27 = [](auto mimeData) { return true; };
27 = [](auto mimeData) { return true; };
28 VisualizationDragDropContainer::AcceptDragWidgetFunction m_AcceptDragWidgetFun
28 VisualizationDragDropContainer::AcceptDragWidgetFunction m_AcceptDragWidgetFun
29 = [](auto dragWidget, auto mimeData) { return true; };
29 = [](auto dragWidget, auto mimeData) { return true; };
30
30
31 int m_MinContainerHeight = 0;
31 int m_MinContainerHeight = 0;
32
32
33 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
33 explicit VisualizationDragDropContainerPrivate(QWidget *widget)
34 : m_PlaceHolderType(DragDropHelper::PlaceHolderType::Graph)
34 : m_PlaceHolderType(DragDropHelper::PlaceHolderType::Graph)
35 {
35 {
36 m_Layout = new QVBoxLayout(widget);
36 m_Layout = new QVBoxLayout(widget);
37 m_Layout->setContentsMargins(0, 0, 0, 0);
37 m_Layout->setContentsMargins(0, 0, 0, 0);
38 }
38 }
39
39
40 bool acceptMimeData(const QMimeData *data) const
40 bool acceptMimeData(const QMimeData *data) const
41 {
41 {
42 auto accepted = false;
42 auto accepted = false;
43 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
43 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
44 ++it) {
44 ++it) {
45 const auto &type = it.key();
45 const auto &type = it.key();
46 const auto &behavior = it.value();
46 const auto &behavior = it.value();
47
47
48 if (data->hasFormat(type)) {
48 if (data->hasFormat(type)) {
49 if (behavior != DropBehavior::Forbidden) {
49 if (behavior != DropBehavior::Forbidden) {
50 accepted = true;
50 accepted = true;
51 }
51 }
52 else {
52 else {
53 accepted = false;
53 accepted = false;
54 break;
54 break;
55 }
55 }
56 }
56 }
57 }
57 }
58
58
59 if (accepted) {
59 if (accepted) {
60 accepted = m_AcceptMimeDataFun(data);
60 accepted = m_AcceptMimeDataFun(data);
61 }
61 }
62
62
63 return accepted;
63 return accepted;
64 }
64 }
65
65
66 bool allowMergeForMimeData(const QMimeData *data) const
66 bool allowMergeForMimeData(const QMimeData *data) const
67 {
67 {
68 auto result = false;
68 auto result = false;
69 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
69 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
70 ++it) {
70 ++it) {
71
71
72 if (data->hasFormat(it.key())
72 if (data->hasFormat(it.key())
73 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
73 && (it.value() == VisualizationDragDropContainer::DropBehavior::Merged
74 || it.value()
74 || it.value()
75 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
75 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
76 result = true;
76 result = true;
77 }
77 }
78 else if (data->hasFormat(it.key())
78 else if (data->hasFormat(it.key())
79 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
79 && it.value() == VisualizationDragDropContainer::DropBehavior::Inserted) {
80 // Merge is forbidden if the mime data contain an acceptable type which cannot be
80 // Merge is forbidden if the mime data contain an acceptable type which cannot be
81 // merged
81 // merged
82 result = false;
82 result = false;
83 break;
83 break;
84 }
84 }
85 }
85 }
86
86
87 return result;
87 return result;
88 }
88 }
89
89
90 bool allowInsertForMimeData(const QMimeData *data) const
90 bool allowInsertForMimeData(const QMimeData *data) const
91 {
91 {
92 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
92 for (auto it = m_AcceptedMimeTypes.constBegin(); it != m_AcceptedMimeTypes.constEnd();
93 ++it) {
93 ++it) {
94 if (data->hasFormat(it.key())
94 if (data->hasFormat(it.key())
95 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
95 && (it.value() == VisualizationDragDropContainer::DropBehavior::Inserted
96 || it.value()
96 || it.value()
97 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
97 == VisualizationDragDropContainer::DropBehavior::InsertedAndMerged)) {
98 return true;
98 return true;
99 }
99 }
100 }
100 }
101
101
102 return false;
102 return false;
103 }
103 }
104
104
105 bool hasPlaceHolder() const
105 bool hasPlaceHolder() const
106 {
106 {
107 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
107 return sqpApp->dragDropHelper().placeHolder().parentWidget() == m_Layout->parentWidget();
108 }
108 }
109
109
110 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
110 VisualizationDragWidget *getChildDragWidgetAt(const QWidget *parent, const QPoint &pos) const
111 {
111 {
112 VisualizationDragWidget *dragWidget = nullptr;
112 VisualizationDragWidget *dragWidget = nullptr;
113
113
114 for (auto child : parent->children()) {
114 for (auto child : parent->children()) {
115 auto widget = qobject_cast<VisualizationDragWidget *>(child);
115 auto widget = qobject_cast<VisualizationDragWidget *>(child);
116 if (widget && widget->isVisible()) {
116 if (widget && widget->isVisible()) {
117 if (widget->frameGeometry().contains(pos)) {
117 if (widget->frameGeometry().contains(pos)) {
118 dragWidget = widget;
118 dragWidget = widget;
119 break;
119 break;
120 }
120 }
121 }
121 }
122 }
122 }
123
123
124 return dragWidget;
124 return dragWidget;
125 }
125 }
126
126
127 bool cursorIsInContainer(QWidget *container) const
127 bool cursorIsInContainer(QWidget *container) const
128 {
128 {
129 auto widgetUnderMouse = sqpApp->widgetAt(QCursor::pos());
129 auto widgetUnderMouse = sqpApp->widgetAt(QCursor::pos());
130 return container->isAncestorOf(widgetUnderMouse) && widgetUnderMouse != container
130 return container->isAncestorOf(widgetUnderMouse) && widgetUnderMouse != container
131 && sqpApp->dragDropHelper().placeHolder().isAncestorOf(widgetUnderMouse);
131 && sqpApp->dragDropHelper().placeHolder().isAncestorOf(widgetUnderMouse);
132 }
132 }
133
133
134 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
134 int countDragWidget(const QWidget *parent, bool onlyVisible = false) const
135 {
135 {
136 auto nbGraph = 0;
136 auto nbGraph = 0;
137 for (auto child : parent->children()) {
137 for (auto child : parent->children()) {
138 if (qobject_cast<VisualizationDragWidget *>(child)) {
138 if (qobject_cast<VisualizationDragWidget *>(child)) {
139 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
139 if (!onlyVisible || qobject_cast<VisualizationDragWidget *>(child)->isVisible()) {
140 nbGraph += 1;
140 nbGraph += 1;
141 }
141 }
142 }
142 }
143 }
143 }
144
144
145 return nbGraph;
145 return nbGraph;
146 }
146 }
147
147
148 bool findPlaceHolderPosition(const QPoint &pos, const QMimeData *mimeData, bool canInsert,
148 bool findPlaceHolderPosition(const QPoint &pos, const QMimeData *mimeData, bool canInsert,
149 bool canMerge, const VisualizationDragDropContainer *container);
149 bool canMerge, const VisualizationDragDropContainer *container);
150 };
150 };
151
151
152 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
152 VisualizationDragDropContainer::VisualizationDragDropContainer(QWidget *parent)
153 : QFrame{parent},
153 : QFrame{parent},
154 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
154 impl{spimpl::make_unique_impl<VisualizationDragDropContainerPrivate>(this)}
155 {
155 {
156 setAcceptDrops(true);
156 setAcceptDrops(true);
157 }
157 }
158
158
159 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
159 void VisualizationDragDropContainer::addDragWidget(VisualizationDragWidget *dragWidget)
160 {
160 {
161 impl->m_Layout->addWidget(dragWidget);
161 impl->m_Layout->addWidget(dragWidget);
162 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
162 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
163 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
163 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
164 &VisualizationDragDropContainer::startDrag);
164 &VisualizationDragDropContainer::startDrag);
165 }
165 }
166
166
167 void VisualizationDragDropContainer::insertDragWidget(int index,
167 void VisualizationDragDropContainer::insertDragWidget(int index,
168 VisualizationDragWidget *dragWidget)
168 VisualizationDragWidget *dragWidget)
169 {
169 {
170 impl->m_Layout->insertWidget(index, dragWidget);
170 impl->m_Layout->insertWidget(index, dragWidget);
171 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
171 disconnect(dragWidget, &VisualizationDragWidget::dragDetected, nullptr, nullptr);
172 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
172 connect(dragWidget, &VisualizationDragWidget::dragDetected, this,
173 &VisualizationDragDropContainer::startDrag);
173 &VisualizationDragDropContainer::startDrag);
174 }
174 }
175
175
176 void VisualizationDragDropContainer::setMimeType(
176 void VisualizationDragDropContainer::setMimeType(
177 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
177 const QString &mimeType, VisualizationDragDropContainer::DropBehavior behavior)
178 {
178 {
179 impl->m_AcceptedMimeTypes[mimeType] = behavior;
179 impl->m_AcceptedMimeTypes[mimeType] = behavior;
180 }
180 }
181
181
182 int VisualizationDragDropContainer::countDragWidget() const
182 int VisualizationDragDropContainer::countDragWidget() const
183 {
183 {
184 return impl->countDragWidget(this);
184 return impl->countDragWidget(this);
185 }
185 }
186
186
187 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
187 void VisualizationDragDropContainer::setAcceptMimeDataFunction(
188 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
188 VisualizationDragDropContainer::AcceptMimeDataFunction fun)
189 {
189 {
190 impl->m_AcceptMimeDataFun = fun;
190 impl->m_AcceptMimeDataFun = fun;
191 }
191 }
192
192
193 void VisualizationDragDropContainer::setAcceptDragWidgetFunction(
193 void VisualizationDragDropContainer::setAcceptDragWidgetFunction(
194 VisualizationDragDropContainer::AcceptDragWidgetFunction fun)
194 VisualizationDragDropContainer::AcceptDragWidgetFunction fun)
195 {
195 {
196 impl->m_AcceptDragWidgetFun = fun;
196 impl->m_AcceptDragWidgetFun = fun;
197 }
197 }
198
198
199 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
199 void VisualizationDragDropContainer::setPlaceHolderType(DragDropHelper::PlaceHolderType type,
200 const QString &placeHolderText)
200 const QString &placeHolderText)
201 {
201 {
202 impl->m_PlaceHolderType = type;
202 impl->m_PlaceHolderType = type;
203 impl->m_PlaceHolderText = placeHolderText;
203 impl->m_PlaceHolderText = placeHolderText;
204 }
204 }
205
205
206 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
206 void VisualizationDragDropContainer::startDrag(VisualizationDragWidget *dragWidget,
207 const QPoint &dragPosition)
207 const QPoint &dragPosition)
208 {
208 {
209 auto &helper = sqpApp->dragDropHelper();
209 auto &helper = sqpApp->dragDropHelper();
210 helper.resetDragAndDrop();
210 helper.resetDragAndDrop();
211
211
212 // Note: The management of the drag object is done by Qt
212 // Note: The management of the drag object is done by Qt
213 auto drag = new QDrag{dragWidget};
213 auto drag = new QDrag{dragWidget};
214
214
215 auto mimeData = dragWidget->mimeData();
215 auto mimeData = dragWidget->mimeData(dragPosition);
216 drag->setMimeData(mimeData);
216 drag->setMimeData(mimeData);
217
217
218 auto pixmap = QPixmap(dragWidget->size());
218 auto pixmap = dragWidget->customDragPixmap(dragPosition);
219 if (pixmap.isNull()) {
220 pixmap = QPixmap{dragWidget->size()};
219 dragWidget->render(&pixmap);
221 dragWidget->render(&pixmap);
222 }
223
220 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
224 drag->setPixmap(pixmap.scaled(DRAGGED_MINIATURE_WIDTH, DRAGGED_MINIATURE_WIDTH,
221 Qt::KeepAspectRatio, Qt::SmoothTransformation));
225 Qt::KeepAspectRatio, Qt::SmoothTransformation));
222
226
223 auto image = pixmap.toImage();
227 auto image = pixmap.toImage();
224 mimeData->setImageData(image);
228 mimeData->setImageData(image);
225 mimeData->setUrls({helper.imageTemporaryUrl(image)});
229 mimeData->setUrls({helper.imageTemporaryUrl(image)});
226
230
227 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
231 if (impl->m_Layout->indexOf(dragWidget) >= 0) {
232
233 if (impl->acceptMimeData(mimeData) && impl->allowInsertForMimeData(mimeData)) {
228 helper.setCurrentDragWidget(dragWidget);
234 helper.setCurrentDragWidget(dragWidget);
229
235
230 if (impl->cursorIsInContainer(this)) {
236 if (impl->cursorIsInContainer(this)) {
231 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
237 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
232 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
238 helper.insertPlaceHolder(impl->m_Layout, dragWidgetIndex, impl->m_PlaceHolderType,
233 impl->m_PlaceHolderText);
239 impl->m_PlaceHolderText);
234 dragWidget->setVisible(false);
240 dragWidget->setVisible(false);
235 }
241 }
236 else {
242 else {
237 // The drag starts directly outside the drop zone
243 // The drag starts directly outside the drop zone
238 // do not add the placeHolder
244 // do not add the placeHolder
239 }
245 }
246 }
240
247
241 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
248 drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::MoveAction);
242
249
243 helper.doCloseWidgets();
250 helper.doCloseWidgets();
244 }
251 }
245 else {
252 else {
246 qCWarning(LOG_VisualizationDragDropContainer())
253 qCWarning(LOG_VisualizationDragDropContainer())
247 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
254 << tr("VisualizationDragDropContainer::startDrag, drag aborted, the specified "
248 "VisualizationDragWidget is not found in this container.");
255 "VisualizationDragWidget is not found in this container.");
249 }
256 }
250 }
257 }
251
258
252 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
259 void VisualizationDragDropContainer::dragEnterEvent(QDragEnterEvent *event)
253 {
260 {
254 if (impl->acceptMimeData(event->mimeData())) {
261 if (impl->acceptMimeData(event->mimeData())) {
255 event->acceptProposedAction();
262 event->acceptProposedAction();
256
263
257 auto &helper = sqpApp->dragDropHelper();
264 auto &helper = sqpApp->dragDropHelper();
258
265
259 if (!impl->hasPlaceHolder()) {
266 if (!impl->hasPlaceHolder()) {
260 auto dragWidget = helper.getCurrentDragWidget();
267 auto dragWidget = helper.getCurrentDragWidget();
261
268
262 if (dragWidget) {
269 if (dragWidget) {
263 // If the drag&drop is internal to the visualization, entering the container hide
270 // If the drag&drop is internal to the visualization, entering the container hide
264 // the dragWidget which was made visible by the dragLeaveEvent
271 // the dragWidget which was made visible by the dragLeaveEvent
265 auto parentWidget
272 auto parentWidget
266 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
273 = qobject_cast<VisualizationDragDropContainer *>(dragWidget->parentWidget());
267 if (parentWidget) {
274 if (parentWidget) {
268 dragWidget->setVisible(false);
275 dragWidget->setVisible(false);
269 }
276 }
270 }
277 }
271
278
272 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
279 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
273 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
280 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
274 if (!impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge,
281 if (!impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge,
275 this)) {
282 this)) {
276 event->ignore();
283 event->ignore();
277 }
284 }
278 }
285 }
279 else {
286 else {
280 // do nothing
287 // do nothing
281 }
288 }
282 }
289 }
283 else {
290 else {
284 event->ignore();
291 event->ignore();
285 }
292 }
286
293
287 QWidget::dragEnterEvent(event);
294 QWidget::dragEnterEvent(event);
288 }
295 }
289
296
290 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
297 void VisualizationDragDropContainer::dragLeaveEvent(QDragLeaveEvent *event)
291 {
298 {
292 Q_UNUSED(event);
299 Q_UNUSED(event);
293
300
294 auto &helper = sqpApp->dragDropHelper();
301 auto &helper = sqpApp->dragDropHelper();
295
302
296 if (!impl->cursorIsInContainer(this)) {
303 if (!impl->cursorIsInContainer(this)) {
297 helper.removePlaceHolder();
304 helper.removePlaceHolder();
298 helper.setHightlightedDragWidget(nullptr);
305 helper.setHightlightedDragWidget(nullptr);
299 impl->m_MinContainerHeight = 0;
306 impl->m_MinContainerHeight = 0;
300
307
301 auto dragWidget = helper.getCurrentDragWidget();
308 auto dragWidget = helper.getCurrentDragWidget();
302 if (dragWidget) {
309 if (dragWidget) {
303 // dragWidget has a value only if the drag is started from the visualization
310 // dragWidget has a value only if the drag is started from the visualization
304 // In that case, shows the drag widget at its original place
311 // In that case, shows the drag widget at its original place
305 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
312 // So the drag widget doesn't stay hidden if the drop occurs outside the visualization
306 // drop zone (It is not possible to catch a drop event outside of the application)
313 // drop zone (It is not possible to catch a drop event outside of the application)
307
314
308 if (dragWidget) {
315 if (dragWidget) {
309 dragWidget->setVisible(true);
316 dragWidget->setVisible(true);
310 }
317 }
311 }
318 }
312 }
319 }
313 else {
320 else {
314 // Leave event probably received for a child widget.
321 // Leave event probably received for a child widget.
315 // Do nothing.
322 // Do nothing.
316 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
323 // Note: The DragLeave event, doesn't have any mean to determine who sent it.
317 }
324 }
318
325
319 QWidget::dragLeaveEvent(event);
326 QWidget::dragLeaveEvent(event);
320 }
327 }
321
328
322 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
329 void VisualizationDragDropContainer::dragMoveEvent(QDragMoveEvent *event)
323 {
330 {
324 if (impl->acceptMimeData(event->mimeData())) {
331 if (impl->acceptMimeData(event->mimeData())) {
325 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
332 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
326 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
333 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
327 impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge, this);
334 impl->findPlaceHolderPosition(event->pos(), event->mimeData(), canInsert, canMerge, this);
328 }
335 }
329 else {
336 else {
330 event->ignore();
337 event->ignore();
331 }
338 }
332
339
333 QWidget::dragMoveEvent(event);
340 QWidget::dragMoveEvent(event);
334 }
341 }
335
342
336 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
343 void VisualizationDragDropContainer::dropEvent(QDropEvent *event)
337 {
344 {
338 auto &helper = sqpApp->dragDropHelper();
345 auto &helper = sqpApp->dragDropHelper();
339
346
340 if (impl->acceptMimeData(event->mimeData())) {
347 if (impl->acceptMimeData(event->mimeData())) {
341 auto dragWidget = helper.getCurrentDragWidget();
348 auto dragWidget = helper.getCurrentDragWidget();
342 if (impl->hasPlaceHolder()) {
349 if (impl->hasPlaceHolder()) {
343 // drop where the placeHolder is located
350 // drop where the placeHolder is located
344
351
345 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
352 auto canInsert = impl->allowInsertForMimeData(event->mimeData());
346 if (canInsert) {
353 if (canInsert) {
347 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
354 auto droppedIndex = impl->m_Layout->indexOf(&helper.placeHolder());
348
355
349 if (dragWidget) {
356 if (dragWidget) {
350 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
357 auto dragWidgetIndex = impl->m_Layout->indexOf(dragWidget);
351 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
358 if (dragWidgetIndex >= 0 && dragWidgetIndex < droppedIndex) {
352 // Correction of the index if the drop occurs in the same container
359 // Correction of the index if the drop occurs in the same container
353 // and if the drag is started from the visualization (in that case, the
360 // and if the drag is started from the visualization (in that case, the
354 // dragWidget is hidden)
361 // dragWidget is hidden)
355 droppedIndex -= 1;
362 droppedIndex -= 1;
356 }
363 }
357
364
358 dragWidget->setVisible(true);
365 dragWidget->setVisible(true);
359 }
366 }
360
367
361 event->acceptProposedAction();
368 event->acceptProposedAction();
362
369
363 helper.removePlaceHolder();
370 helper.removePlaceHolder();
364
371
365 emit dropOccuredInContainer(droppedIndex, event->mimeData());
372 emit dropOccuredInContainer(droppedIndex, event->mimeData());
366 }
373 }
367 else {
374 else {
368 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
375 qCWarning(LOG_VisualizationDragDropContainer()) << tr(
369 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
376 "VisualizationDragDropContainer::dropEvent, dropping on the placeHolder, but "
370 "the insertion is forbidden.");
377 "the insertion is forbidden.");
371 Q_ASSERT(false);
378 Q_ASSERT(false);
372 }
379 }
373 }
380 }
374 else if (helper.getHightlightedDragWidget()) {
381 else if (helper.getHightlightedDragWidget()) {
375 // drop on the highlighted widget
382 // drop on the highlighted widget
376
383
377 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
384 auto canMerge = impl->allowMergeForMimeData(event->mimeData());
378 if (canMerge) {
385 if (canMerge) {
379 event->acceptProposedAction();
386 event->acceptProposedAction();
380 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
387 emit dropOccuredOnWidget(helper.getHightlightedDragWidget(), event->mimeData());
381 }
388 }
382 else {
389 else {
383 qCWarning(LOG_VisualizationDragDropContainer())
390 qCWarning(LOG_VisualizationDragDropContainer())
384 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
391 << tr("VisualizationDragDropContainer::dropEvent, dropping on a widget, but "
385 "the merge is forbidden.");
392 "the merge is forbidden.");
386 Q_ASSERT(false);
393 Q_ASSERT(false);
387 }
394 }
388 }
395 }
389 }
396 }
390 else {
397 else {
391 event->ignore();
398 event->ignore();
392 }
399 }
393
400
394 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
401 sqpApp->dragDropHelper().setHightlightedDragWidget(nullptr);
395 impl->m_MinContainerHeight = 0;
402 impl->m_MinContainerHeight = 0;
396
403
397 QWidget::dropEvent(event);
404 QWidget::dropEvent(event);
398 }
405 }
399
406
400
407
401 bool VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
408 bool VisualizationDragDropContainer::VisualizationDragDropContainerPrivate::findPlaceHolderPosition(
402 const QPoint &pos, const QMimeData *mimeData, bool canInsert, bool canMerge,
409 const QPoint &pos, const QMimeData *mimeData, bool canInsert, bool canMerge,
403 const VisualizationDragDropContainer *container)
410 const VisualizationDragDropContainer *container)
404 {
411 {
405 auto &helper = sqpApp->dragDropHelper();
412 auto &helper = sqpApp->dragDropHelper();
406
413
407 auto absPos = container->mapToGlobal(pos);
414 auto absPos = container->mapToGlobal(pos);
408 auto isOnPlaceHolder = helper.placeHolder().isAncestorOf(sqpApp->widgetAt(absPos));
415 auto isOnPlaceHolder = helper.placeHolder().isAncestorOf(sqpApp->widgetAt(absPos));
409
416
410 if (countDragWidget(container, true) == 0) {
417 if (countDragWidget(container, true) == 0) {
411 // Drop on an empty container, just add the placeHolder at the top
418 // Drop on an empty container, just add the placeHolder at the top
412 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
419 helper.insertPlaceHolder(m_Layout, 0, m_PlaceHolderType, m_PlaceHolderText);
413 }
420 }
414 else if (!isOnPlaceHolder) {
421 else if (!isOnPlaceHolder) {
415 auto nbDragWidget = countDragWidget(container);
422 auto nbDragWidget = countDragWidget(container);
416 if (nbDragWidget > 0) {
423 if (nbDragWidget > 0) {
417
424
418 if (m_MinContainerHeight == 0) {
425 if (m_MinContainerHeight == 0) {
419 m_MinContainerHeight = container->size().height();
426 m_MinContainerHeight = container->size().height();
420 }
427 }
421
428
422 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
429 m_MinContainerHeight = qMin(m_MinContainerHeight, container->size().height());
423 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
430 auto graphHeight = qMax(m_MinContainerHeight / nbDragWidget, GRAPH_MINIMUM_HEIGHT);
424
431
425 auto posY = pos.y();
432 auto posY = pos.y();
426 auto dropIndex = floor(posY / graphHeight);
433 auto dropIndex = floor(posY / graphHeight);
427 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
434 auto zoneSize = qMin(graphHeight / 4.0, 75.0);
428
435
429
436
430 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
437 auto isOnTop = posY < dropIndex * graphHeight + zoneSize;
431 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
438 auto isOnBottom = posY > (dropIndex + 1) * graphHeight - zoneSize;
432
439
433 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
440 auto placeHolderIndex = m_Layout->indexOf(&(helper.placeHolder()));
434
441
435 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
442 auto dragWidgetHovered = getChildDragWidgetAt(container, pos);
436
443
437 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
444 if (canInsert && (isOnTop || isOnBottom || !canMerge)) {
438 if (isOnBottom) {
445 if (isOnBottom) {
439 dropIndex += 1;
446 dropIndex += 1;
440 }
447 }
441
448
442 if (helper.getCurrentDragWidget()) {
449 if (helper.getCurrentDragWidget()) {
443 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
450 auto dragWidgetIndex = m_Layout->indexOf(helper.getCurrentDragWidget());
444 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
451 if (dragWidgetIndex >= 0 && dragWidgetIndex <= dropIndex) {
445 // Correction of the index if the drop occurs in the same container
452 // Correction of the index if the drop occurs in the same container
446 // and if the drag is started from the visualization (in that case, the
453 // and if the drag is started from the visualization (in that case, the
447 // dragWidget is hidden)
454 // dragWidget is hidden)
448 dropIndex += 1;
455 dropIndex += 1;
449 }
456 }
450 }
457 }
451
458
452 if (dropIndex != placeHolderIndex) {
459 if (dropIndex != placeHolderIndex) {
453 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
460 helper.insertPlaceHolder(m_Layout, dropIndex, m_PlaceHolderType,
454 m_PlaceHolderText);
461 m_PlaceHolderText);
455 }
462 }
456
463
457 helper.setHightlightedDragWidget(nullptr);
464 helper.setHightlightedDragWidget(nullptr);
458 }
465 }
459 else if (canMerge && dragWidgetHovered) {
466 else if (canMerge && dragWidgetHovered) {
460 // drop on the middle -> merge
467 // drop on the middle -> merge
461 if (hasPlaceHolder()) {
468 if (hasPlaceHolder()) {
462 helper.removePlaceHolder();
469 helper.removePlaceHolder();
463 }
470 }
464
471
465 if (m_AcceptDragWidgetFun(dragWidgetHovered, mimeData)) {
472 if (m_AcceptDragWidgetFun(dragWidgetHovered, mimeData)) {
466 helper.setHightlightedDragWidget(dragWidgetHovered);
473 helper.setHightlightedDragWidget(dragWidgetHovered);
467 return true;
474 return true;
468 }
475 }
469 else {
476 else {
470 return false;
477 return false;
471 }
478 }
472 }
479 }
473 else {
480 else {
474 qCWarning(LOG_VisualizationDragDropContainer())
481 qCWarning(LOG_VisualizationDragDropContainer())
475 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
482 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no valid drop "
476 "action.");
483 "action.");
477 }
484 }
478 }
485 }
479 else {
486 else {
480 qCWarning(LOG_VisualizationDragDropContainer())
487 qCWarning(LOG_VisualizationDragDropContainer())
481 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
488 << tr("VisualizationDragDropContainer::findPlaceHolderPosition, no widget "
482 "found in the "
489 "found in the "
483 "container");
490 "container");
484 }
491 }
485 }
492 }
486 else {
493 else {
487 // the mouse is hover the placeHolder
494 // the mouse is hover the placeHolder
488 // Do nothing
495 // Do nothing
489 }
496 }
490
497
491 return true;
498 return true;
492 }
499 }
@@ -1,55 +1,61
1 #include "Visualization/VisualizationDragWidget.h"
1 #include "Visualization/VisualizationDragWidget.h"
2 #include "Visualization/VisualizationDragDropContainer.h"
2 #include "Visualization/VisualizationDragDropContainer.h"
3
3
4 #include <QApplication>
4 #include <QApplication>
5 #include <QMouseEvent>
5 #include <QMouseEvent>
6
6
7 #include <SqpApplication.h>
7 #include <SqpApplication.h>
8
8
9 struct VisualizationDragWidget::VisualizationDragWidgetPrivate {
9 struct VisualizationDragWidget::VisualizationDragWidgetPrivate {
10
10
11 QPoint m_DragStartPosition;
11 QPoint m_DragStartPosition;
12 bool m_DragStartPositionValid = false;
12 bool m_DragStartPositionValid = false;
13
13
14 explicit VisualizationDragWidgetPrivate() {}
14 explicit VisualizationDragWidgetPrivate() {}
15 };
15 };
16
16
17 VisualizationDragWidget::VisualizationDragWidget(QWidget *parent)
17 VisualizationDragWidget::VisualizationDragWidget(QWidget *parent)
18 : QWidget{parent}, impl{spimpl::make_unique_impl<VisualizationDragWidgetPrivate>()}
18 : QWidget{parent}, impl{spimpl::make_unique_impl<VisualizationDragWidgetPrivate>()}
19 {
19 {
20 }
20 }
21
21
22 virtual QPixmap VisualizationDragWidget::customDragPixmap(const QPoint &dragPosition)
23 {
24 Q_UNUSED(dragPosition);
25 return QPixmap();
26 }
27
22 void VisualizationDragWidget::mousePressEvent(QMouseEvent *event)
28 void VisualizationDragWidget::mousePressEvent(QMouseEvent *event)
23 {
29 {
24 if (event->button() == Qt::LeftButton) {
30 if (event->button() == Qt::LeftButton) {
25 impl->m_DragStartPosition = event->pos();
31 impl->m_DragStartPosition = event->pos();
26 }
32 }
27
33
28 impl->m_DragStartPositionValid = isDragAllowed();
34 impl->m_DragStartPositionValid = isDragAllowed();
29
35
30 QWidget::mousePressEvent(event);
36 QWidget::mousePressEvent(event);
31 }
37 }
32
38
33 void VisualizationDragWidget::mouseMoveEvent(QMouseEvent *event)
39 void VisualizationDragWidget::mouseMoveEvent(QMouseEvent *event)
34 {
40 {
35 if (!impl->m_DragStartPositionValid || !isDragAllowed()) {
41 if (!impl->m_DragStartPositionValid || !isDragAllowed()) {
36 return;
42 return;
37 }
43 }
38
44
39 if (!(event->buttons() & Qt::LeftButton)) {
45 if (!(event->buttons() & Qt::LeftButton)) {
40 return;
46 return;
41 }
47 }
42
48
43 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::DragAndDrop
49 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::DragAndDrop
44 || event->modifiers().testFlag(Qt::AltModifier)) {
50 || event->modifiers().testFlag(Qt::AltModifier)) {
45
51
46 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
52 if ((event->pos() - impl->m_DragStartPosition).manhattanLength()
47 < QApplication::startDragDistance()) {
53 < QApplication::startDragDistance()) {
48 return;
54 return;
49 }
55 }
50
56
51 emit dragDetected(this, impl->m_DragStartPosition);
57 emit dragDetected(this, impl->m_DragStartPosition);
52 }
58 }
53
59
54 QWidget::mouseMoveEvent(event);
60 QWidget::mouseMoveEvent(event);
55 }
61 }
@@ -1,747 +1,797
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationZoneWidget.h"
8 #include "Visualization/VisualizationZoneWidget.h"
9 #include "ui_VisualizationGraphWidget.h"
9 #include "ui_VisualizationGraphWidget.h"
10
10
11 #include <Common/MimeTypesDef.h>
11 #include <Common/MimeTypesDef.h>
12 #include <Data/ArrayData.h>
12 #include <Data/ArrayData.h>
13 #include <Data/IDataSeries.h>
13 #include <Data/IDataSeries.h>
14 #include <Data/SpectrogramSeries.h>
14 #include <Data/SpectrogramSeries.h>
15 #include <DragAndDrop/DragDropHelper.h>
15 #include <DragAndDrop/DragDropHelper.h>
16 #include <Settings/SqpSettingsDefs.h>
16 #include <Settings/SqpSettingsDefs.h>
17 #include <SqpApplication.h>
17 #include <SqpApplication.h>
18 #include <Time/TimeController.h>
18 #include <Time/TimeController.h>
19 #include <Variable/Variable.h>
19 #include <Variable/Variable.h>
20 #include <Variable/VariableController.h>
20 #include <Variable/VariableController.h>
21
21
22 #include <unordered_map>
22 #include <unordered_map>
23
23
24 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
24 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
25
25
26 namespace {
26 namespace {
27
27
28 /// Key pressed to enable drag&drop in all modes
29 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
30
28 /// Key pressed to enable zoom on horizontal axis
31 /// Key pressed to enable zoom on horizontal axis
29 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
32 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
30
33
31 /// Key pressed to enable zoom on vertical axis
34 /// Key pressed to enable zoom on vertical axis
32 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
35 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
33
36
34 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
37 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
35 const auto PAN_SPEED = 5;
38 const auto PAN_SPEED = 5;
36
39
37 /// Key pressed to enable a calibration pan
40 /// Key pressed to enable a calibration pan
38 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
41 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
39
42
40 /// Minimum size for the zoom box, in percentage of the axis range
43 /// Minimum size for the zoom box, in percentage of the axis range
41 const auto ZOOM_BOX_MIN_SIZE = 0.8;
44 const auto ZOOM_BOX_MIN_SIZE = 0.8;
42
45
43 /// Format of the dates appearing in the label of a cursor
46 /// Format of the dates appearing in the label of a cursor
44 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
47 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
45
48
46 } // namespace
49 } // namespace
47
50
48 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
51 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
49
52
50 explicit VisualizationGraphWidgetPrivate(const QString &name)
53 explicit VisualizationGraphWidgetPrivate(const QString &name)
51 : m_Name{name},
54 : m_Name{name},
52 m_DoAcquisition{true},
55 m_DoAcquisition{true},
53 m_IsCalibration{false},
56 m_IsCalibration{false},
54 m_RenderingDelegate{nullptr}
57 m_RenderingDelegate{nullptr}
55 {
58 {
56 }
59 }
57
60
58 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
61 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
59 const SqpRange &range)
62 const SqpRange &range)
60 {
63 {
61 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
64 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
62
65
63 // Prevents that data has changed to update rendering
66 // Prevents that data has changed to update rendering
64 m_RenderingDelegate->onPlotUpdated();
67 m_RenderingDelegate->onPlotUpdated();
65 }
68 }
66
69
67 QString m_Name;
70 QString m_Name;
68 // 1 variable -> n qcpplot
71 // 1 variable -> n qcpplot
69 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
72 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
70 bool m_DoAcquisition;
73 bool m_DoAcquisition;
71 bool m_IsCalibration;
74 bool m_IsCalibration;
72 /// Delegate used to attach rendering features to the plot
75 /// Delegate used to attach rendering features to the plot
73 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
76 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
74
77
75 QCPItemRect *m_DrawingZoomRect = nullptr;
78 QCPItemRect *m_DrawingZoomRect = nullptr;
76 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
79 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
77
80
78 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
81 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
79 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
82 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
80
83
81 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
84 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
82 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
85 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
83 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
86 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
84
87
85 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
88 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
86 {
89 {
87 removeDrawingRect(plot);
90 removeDrawingRect(plot);
88
91
89 auto axisPos = posToAxisPos(pos, plot);
92 auto axisPos = posToAxisPos(pos, plot);
90
93
91 m_DrawingZoomRect = new QCPItemRect{&plot};
94 m_DrawingZoomRect = new QCPItemRect{&plot};
92 QPen p;
95 QPen p;
93 p.setWidth(2);
96 p.setWidth(2);
94 m_DrawingZoomRect->setPen(p);
97 m_DrawingZoomRect->setPen(p);
95
98
96 m_DrawingZoomRect->topLeft->setCoords(axisPos);
99 m_DrawingZoomRect->topLeft->setCoords(axisPos);
97 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
100 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
98 }
101 }
99
102
100 void removeDrawingRect(QCustomPlot &plot)
103 void removeDrawingRect(QCustomPlot &plot)
101 {
104 {
102 if (m_DrawingZoomRect) {
105 if (m_DrawingZoomRect) {
103 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
106 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
104 m_DrawingZoomRect = nullptr;
107 m_DrawingZoomRect = nullptr;
105 plot.replot(QCustomPlot::rpQueuedReplot);
108 plot.replot(QCustomPlot::rpQueuedReplot);
106 }
109 }
107 }
110 }
108
111
109 void startDrawingZone(const QPoint &pos, QCustomPlot &plot)
112 void startDrawingZone(const QPoint &pos, QCustomPlot &plot)
110 {
113 {
111 endDrawingZone(plot);
114 endDrawingZone(plot);
112
115
113 auto axisPos = posToAxisPos(pos, plot);
116 auto axisPos = posToAxisPos(pos, plot);
114
117
115 m_DrawingZone = new VisualizationSelectionZoneItem{&plot};
118 m_DrawingZone = new VisualizationSelectionZoneItem{&plot};
116 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
119 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
117 m_DrawingZone->setEditionEnabled(false);
120 m_DrawingZone->setEditionEnabled(false);
118 }
121 }
119
122
120 void endDrawingZone(QCustomPlot &plot)
123 void endDrawingZone(QCustomPlot &plot)
121 {
124 {
122 if (m_DrawingZone) {
125 if (m_DrawingZone) {
123 auto drawingZoneRange = m_DrawingZone->range();
126 auto drawingZoneRange = m_DrawingZone->range();
124 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
127 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
125 m_DrawingZone->setEditionEnabled(true);
128 m_DrawingZone->setEditionEnabled(true);
126 m_SelectionZones.append(m_DrawingZone);
129 m_SelectionZones.append(m_DrawingZone);
127 }
130 }
128 else {
131 else {
129 plot.removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
132 plot.removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
130 }
133 }
131
134
132 plot.replot(QCustomPlot::rpQueuedReplot);
135 plot.replot(QCustomPlot::rpQueuedReplot);
133 m_DrawingZone = nullptr;
136 m_DrawingZone = nullptr;
134 }
137 }
135 }
138 }
136
139
137 void setSelectionZonesEditionEnabled(bool value)
140 void setSelectionZonesEditionEnabled(bool value)
138 {
141 {
139 for (auto s : m_SelectionZones) {
142 for (auto s : m_SelectionZones) {
140 s->setEditionEnabled(value);
143 s->setEditionEnabled(value);
141 }
144 }
142 }
145 }
143
146
147 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
148 const QCustomPlot &plot) const
149 {
150 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
151 auto minDistanceToZone = -1;
152 for (auto zone : m_SelectionZones) {
153 auto distanceToZone = zone->selectTest(pos, false);
154 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
155 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
156 selectionZoneItemUnderCursor = zone;
157 }
158 }
159
160 return selectionZoneItemUnderCursor;
161 }
162
144 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
163 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
145 {
164 {
146 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
165 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
147 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
166 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
148 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
167 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
149 }
168 }
150
169
151 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
170 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
152 {
171 {
153 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
172 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
154 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
173 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
155 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
174 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
156 }
175 }
157 };
176 };
158
177
159 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
178 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
160 : VisualizationDragWidget{parent},
179 : VisualizationDragWidget{parent},
161 ui{new Ui::VisualizationGraphWidget},
180 ui{new Ui::VisualizationGraphWidget},
162 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
181 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
163 {
182 {
164 ui->setupUi(this);
183 ui->setupUi(this);
165
184
166 // 'Close' options : widget is deleted when closed
185 // 'Close' options : widget is deleted when closed
167 setAttribute(Qt::WA_DeleteOnClose);
186 setAttribute(Qt::WA_DeleteOnClose);
168
187
169 // Set qcpplot properties :
188 // Set qcpplot properties :
170 // - zoom is enabled
189 // - zoom is enabled
171 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
190 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
172 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
191 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
173 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
192 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
174
193
175 // The delegate must be initialized after the ui as it uses the plot
194 // The delegate must be initialized after the ui as it uses the plot
176 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
195 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
177
196
178 // Init the cursors
197 // Init the cursors
179 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
198 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
180 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
199 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
181 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
200 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
182 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
201 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
183
202
184 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
203 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
185 connect(ui->widget, &QCustomPlot::mouseRelease, this,
204 connect(ui->widget, &QCustomPlot::mouseRelease, this,
186 &VisualizationGraphWidget::onMouseRelease);
205 &VisualizationGraphWidget::onMouseRelease);
187 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
206 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
188 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
207 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
189 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
208 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
190 &VisualizationGraphWidget::onMouseDoubleClick);
209 &VisualizationGraphWidget::onMouseDoubleClick);
191 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
210 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
192 &QCPAxis::rangeChanged),
211 &QCPAxis::rangeChanged),
193 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
212 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
194
213
195 // Activates menu when right clicking on the graph
214 // Activates menu when right clicking on the graph
196 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
215 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
197 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
216 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
198 &VisualizationGraphWidget::onGraphMenuRequested);
217 &VisualizationGraphWidget::onGraphMenuRequested);
199
218
200 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
219 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
201 &VariableController::onRequestDataLoading);
220 &VariableController::onRequestDataLoading);
202
221
203 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
222 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
204 &VisualizationGraphWidget::onUpdateVarDisplaying);
223 &VisualizationGraphWidget::onUpdateVarDisplaying);
205
224
206 #ifdef Q_OS_MAC
225 #ifdef Q_OS_MAC
207 plot().setPlottingHint(QCP::phFastPolylines, true);
226 plot().setPlottingHint(QCP::phFastPolylines, true);
208 #endif
227 #endif
209 }
228 }
210
229
211
230
212 VisualizationGraphWidget::~VisualizationGraphWidget()
231 VisualizationGraphWidget::~VisualizationGraphWidget()
213 {
232 {
214 delete ui;
233 delete ui;
215 }
234 }
216
235
217 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
236 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
218 {
237 {
219 auto parent = parentWidget();
238 auto parent = parentWidget();
220 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
239 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
221 parent = parent->parentWidget();
240 parent = parent->parentWidget();
222 }
241 }
223
242
224 return qobject_cast<VisualizationZoneWidget *>(parent);
243 return qobject_cast<VisualizationZoneWidget *>(parent);
225 }
244 }
226
245
227 void VisualizationGraphWidget::enableAcquisition(bool enable)
246 void VisualizationGraphWidget::enableAcquisition(bool enable)
228 {
247 {
229 impl->m_DoAcquisition = enable;
248 impl->m_DoAcquisition = enable;
230 }
249 }
231
250
232 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
251 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
233 {
252 {
234 // Uses delegate to create the qcpplot components according to the variable
253 // Uses delegate to create the qcpplot components according to the variable
235 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
254 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
236
255
237 if (auto dataSeries = variable->dataSeries()) {
256 if (auto dataSeries = variable->dataSeries()) {
238 // Set axes properties according to the units of the data series
257 // Set axes properties according to the units of the data series
239 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
258 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
240
259
241 // Sets rendering properties for the new plottables
260 // Sets rendering properties for the new plottables
242 // Warning: this method must be called after setAxesProperties(), as it can access to some
261 // Warning: this method must be called after setAxesProperties(), as it can access to some
243 // axes properties that have to be initialized
262 // axes properties that have to be initialized
244 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
263 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
245 }
264 }
246
265
247 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
266 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
248
267
249 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
268 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
250
269
251 this->enableAcquisition(false);
270 this->enableAcquisition(false);
252 this->setGraphRange(range);
271 this->setGraphRange(range);
253 this->enableAcquisition(true);
272 this->enableAcquisition(true);
254
273
255 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
274 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
256
275
257 emit variableAdded(variable);
276 emit variableAdded(variable);
258 }
277 }
259
278
260 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
279 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
261 {
280 {
262 // Each component associated to the variable :
281 // Each component associated to the variable :
263 // - is removed from qcpplot (which deletes it)
282 // - is removed from qcpplot (which deletes it)
264 // - is no longer referenced in the map
283 // - is no longer referenced in the map
265 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
284 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
266 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
285 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
267 emit variableAboutToBeRemoved(variable);
286 emit variableAboutToBeRemoved(variable);
268
287
269 auto &plottablesMap = variableIt->second;
288 auto &plottablesMap = variableIt->second;
270
289
271 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
290 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
272 plottableIt != plottableEnd;) {
291 plottableIt != plottableEnd;) {
273 ui->widget->removePlottable(plottableIt->second);
292 ui->widget->removePlottable(plottableIt->second);
274 plottableIt = plottablesMap.erase(plottableIt);
293 plottableIt = plottablesMap.erase(plottableIt);
275 }
294 }
276
295
277 impl->m_VariableToPlotMultiMap.erase(variableIt);
296 impl->m_VariableToPlotMultiMap.erase(variableIt);
278 }
297 }
279
298
280 // Updates graph
299 // Updates graph
281 ui->widget->replot();
300 ui->widget->replot();
282 }
301 }
283
302
284 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
303 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
285 {
304 {
286 auto variables = QList<std::shared_ptr<Variable> >{};
305 auto variables = QList<std::shared_ptr<Variable> >{};
287 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
306 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
288 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
307 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
289 variables << it->first;
308 variables << it->first;
290 }
309 }
291
310
292 return variables;
311 return variables;
293 }
312 }
294
313
295 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
314 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
296 {
315 {
297 if (!variable) {
316 if (!variable) {
298 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
317 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
299 return;
318 return;
300 }
319 }
301
320
302 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
321 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
303 }
322 }
304
323
305 SqpRange VisualizationGraphWidget::graphRange() const noexcept
324 SqpRange VisualizationGraphWidget::graphRange() const noexcept
306 {
325 {
307 auto graphRange = ui->widget->xAxis->range();
326 auto graphRange = ui->widget->xAxis->range();
308 return SqpRange{graphRange.lower, graphRange.upper};
327 return SqpRange{graphRange.lower, graphRange.upper};
309 }
328 }
310
329
311 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
330 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
312 {
331 {
313 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
332 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
314 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
333 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
315 ui->widget->replot();
334 ui->widget->replot();
316 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
335 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
317 }
336 }
318
337
319 void VisualizationGraphWidget::undoZoom()
338 void VisualizationGraphWidget::undoZoom()
320 {
339 {
321 auto zoom = impl->m_ZoomStack.pop();
340 auto zoom = impl->m_ZoomStack.pop();
322 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
341 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
323 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
342 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
324
343
325 axisX->setRange(zoom.first);
344 axisX->setRange(zoom.first);
326 axisY->setRange(zoom.second);
345 axisY->setRange(zoom.second);
327
346
328 plot().replot(QCustomPlot::rpQueuedReplot);
347 plot().replot(QCustomPlot::rpQueuedReplot);
329 }
348 }
330
349
331 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
350 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
332 {
351 {
333 if (visitor) {
352 if (visitor) {
334 visitor->visit(this);
353 visitor->visit(this);
335 }
354 }
336 else {
355 else {
337 qCCritical(LOG_VisualizationGraphWidget())
356 qCCritical(LOG_VisualizationGraphWidget())
338 << tr("Can't visit widget : the visitor is null");
357 << tr("Can't visit widget : the visitor is null");
339 }
358 }
340 }
359 }
341
360
342 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
361 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
343 {
362 {
344 auto isSpectrogram = [](const auto &variable) {
363 auto isSpectrogram = [](const auto &variable) {
345 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
364 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
346 };
365 };
347
366
348 // - A spectrogram series can't be dropped on graph with existing plottables
367 // - A spectrogram series can't be dropped on graph with existing plottables
349 // - No data series can be dropped on graph with existing spectrogram series
368 // - No data series can be dropped on graph with existing spectrogram series
350 return isSpectrogram(variable)
369 return isSpectrogram(variable)
351 ? impl->m_VariableToPlotMultiMap.empty()
370 ? impl->m_VariableToPlotMultiMap.empty()
352 : std::none_of(
371 : std::none_of(
353 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
372 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
354 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
373 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
355 }
374 }
356
375
357 bool VisualizationGraphWidget::contains(const Variable &variable) const
376 bool VisualizationGraphWidget::contains(const Variable &variable) const
358 {
377 {
359 // Finds the variable among the keys of the map
378 // Finds the variable among the keys of the map
360 auto variablePtr = &variable;
379 auto variablePtr = &variable;
361 auto findVariable
380 auto findVariable
362 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
381 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
363
382
364 auto end = impl->m_VariableToPlotMultiMap.cend();
383 auto end = impl->m_VariableToPlotMultiMap.cend();
365 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
384 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
366 return it != end;
385 return it != end;
367 }
386 }
368
387
369 QString VisualizationGraphWidget::name() const
388 QString VisualizationGraphWidget::name() const
370 {
389 {
371 return impl->m_Name;
390 return impl->m_Name;
372 }
391 }
373
392
374 QMimeData *VisualizationGraphWidget::mimeData() const
393 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
375 {
394 {
376 auto mimeData = new QMimeData;
395 auto mimeData = new QMimeData;
396
397 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
398 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
399 && selectionZoneItemUnderCursor) {
400 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
401 selectionZoneItemUnderCursor->range()));
402 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
403 selectionZoneItemUnderCursor->range()));
404 }
405 else {
377 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
406 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
378
407
379 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
408 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
380 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
409 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
410 }
381
411
382 return mimeData;
412 return mimeData;
383 }
413 }
384
414
415 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
416 {
417 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
418 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
419 && selectionZoneItemUnderCursor) {
420
421 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
422 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
423
424 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
425 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
426 .toSize();
427
428 auto pixmap = QPixmap(zoneSize);
429 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
430
431 return pixmap;
432 }
433
434 return QPixmap();
435 }
436
385 bool VisualizationGraphWidget::isDragAllowed() const
437 bool VisualizationGraphWidget::isDragAllowed() const
386 {
438 {
387 return true;
439 return true;
388 }
440 }
389
441
390 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
442 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
391 {
443 {
392 if (highlighted) {
444 if (highlighted) {
393 plot().setBackground(QBrush(QColor("#BBD5EE")));
445 plot().setBackground(QBrush(QColor("#BBD5EE")));
394 }
446 }
395 else {
447 else {
396 plot().setBackground(QBrush(Qt::white));
448 plot().setBackground(QBrush(Qt::white));
397 }
449 }
398
450
399 plot().update();
451 plot().update();
400 }
452 }
401
453
402 void VisualizationGraphWidget::addVerticalCursor(double time)
454 void VisualizationGraphWidget::addVerticalCursor(double time)
403 {
455 {
404 impl->m_VerticalCursor->setPosition(time);
456 impl->m_VerticalCursor->setPosition(time);
405 impl->m_VerticalCursor->setVisible(true);
457 impl->m_VerticalCursor->setVisible(true);
406
458
407 auto text
459 auto text
408 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
460 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
409 impl->m_VerticalCursor->setLabelText(text);
461 impl->m_VerticalCursor->setLabelText(text);
410 }
462 }
411
463
412 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
464 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
413 {
465 {
414 impl->m_VerticalCursor->setAbsolutePosition(position);
466 impl->m_VerticalCursor->setAbsolutePosition(position);
415 impl->m_VerticalCursor->setVisible(true);
467 impl->m_VerticalCursor->setVisible(true);
416
468
417 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
469 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
418 auto text
470 auto text
419 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
471 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
420 impl->m_VerticalCursor->setLabelText(text);
472 impl->m_VerticalCursor->setLabelText(text);
421 }
473 }
422
474
423 void VisualizationGraphWidget::removeVerticalCursor()
475 void VisualizationGraphWidget::removeVerticalCursor()
424 {
476 {
425 impl->m_VerticalCursor->setVisible(false);
477 impl->m_VerticalCursor->setVisible(false);
426 plot().replot(QCustomPlot::rpQueuedReplot);
478 plot().replot(QCustomPlot::rpQueuedReplot);
427 }
479 }
428
480
429 void VisualizationGraphWidget::addHorizontalCursor(double value)
481 void VisualizationGraphWidget::addHorizontalCursor(double value)
430 {
482 {
431 impl->m_HorizontalCursor->setPosition(value);
483 impl->m_HorizontalCursor->setPosition(value);
432 impl->m_HorizontalCursor->setVisible(true);
484 impl->m_HorizontalCursor->setVisible(true);
433 impl->m_HorizontalCursor->setLabelText(QString::number(value));
485 impl->m_HorizontalCursor->setLabelText(QString::number(value));
434 }
486 }
435
487
436 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
488 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
437 {
489 {
438 impl->m_HorizontalCursor->setAbsolutePosition(position);
490 impl->m_HorizontalCursor->setAbsolutePosition(position);
439 impl->m_HorizontalCursor->setVisible(true);
491 impl->m_HorizontalCursor->setVisible(true);
440
492
441 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
493 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
442 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
494 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
443 }
495 }
444
496
445 void VisualizationGraphWidget::removeHorizontalCursor()
497 void VisualizationGraphWidget::removeHorizontalCursor()
446 {
498 {
447 impl->m_HorizontalCursor->setVisible(false);
499 impl->m_HorizontalCursor->setVisible(false);
448 plot().replot(QCustomPlot::rpQueuedReplot);
500 plot().replot(QCustomPlot::rpQueuedReplot);
449 }
501 }
450
502
451 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
503 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
452 {
504 {
453 Q_UNUSED(event);
505 Q_UNUSED(event);
454
506
455 // Prevents that all variables will be removed from graph when it will be closed
507 // Prevents that all variables will be removed from graph when it will be closed
456 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
508 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
457 emit variableAboutToBeRemoved(variableEntry.first);
509 emit variableAboutToBeRemoved(variableEntry.first);
458 }
510 }
459 }
511 }
460
512
461 void VisualizationGraphWidget::enterEvent(QEvent *event)
513 void VisualizationGraphWidget::enterEvent(QEvent *event)
462 {
514 {
463 Q_UNUSED(event);
515 Q_UNUSED(event);
464 impl->m_RenderingDelegate->showGraphOverlay(true);
516 impl->m_RenderingDelegate->showGraphOverlay(true);
465 }
517 }
466
518
467 void VisualizationGraphWidget::leaveEvent(QEvent *event)
519 void VisualizationGraphWidget::leaveEvent(QEvent *event)
468 {
520 {
469 Q_UNUSED(event);
521 Q_UNUSED(event);
470 impl->m_RenderingDelegate->showGraphOverlay(false);
522 impl->m_RenderingDelegate->showGraphOverlay(false);
471
523
472 if (auto parentZone = parentZoneWidget()) {
524 if (auto parentZone = parentZoneWidget()) {
473 parentZone->notifyMouseLeaveGraph(this);
525 parentZone->notifyMouseLeaveGraph(this);
474 }
526 }
475 else {
527 else {
476 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
528 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
477 }
529 }
478
530
479 if (impl->m_HoveredZone) {
531 if (impl->m_HoveredZone) {
480 impl->m_HoveredZone->setHovered(false);
532 impl->m_HoveredZone->setHovered(false);
481 impl->m_HoveredZone = nullptr;
533 impl->m_HoveredZone = nullptr;
482 }
534 }
483 }
535 }
484
536
485 QCustomPlot &VisualizationGraphWidget::plot() noexcept
537 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
486 {
538 {
487 return *ui->widget;
539 return *ui->widget;
488 }
540 }
489
541
490 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
542 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
491 {
543 {
492 QMenu graphMenu{};
544 QMenu graphMenu{};
493
545
494 // Iterates on variables (unique keys)
546 // Iterates on variables (unique keys)
495 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
547 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
496 end = impl->m_VariableToPlotMultiMap.cend();
548 end = impl->m_VariableToPlotMultiMap.cend();
497 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
549 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
498 // 'Remove variable' action
550 // 'Remove variable' action
499 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
551 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
500 [ this, var = it->first ]() { removeVariable(var); });
552 [ this, var = it->first ]() { removeVariable(var); });
501 }
553 }
502
554
503 if (!impl->m_ZoomStack.isEmpty()) {
555 if (!impl->m_ZoomStack.isEmpty()) {
504 if (!graphMenu.isEmpty()) {
556 if (!graphMenu.isEmpty()) {
505 graphMenu.addSeparator();
557 graphMenu.addSeparator();
506 }
558 }
507
559
508 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
560 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
509 }
561 }
510
562
511 if (!graphMenu.isEmpty()) {
563 if (!graphMenu.isEmpty()) {
512 graphMenu.exec(QCursor::pos());
564 graphMenu.exec(QCursor::pos());
513 }
565 }
514 }
566 }
515
567
516 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
568 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
517 {
569 {
518 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
570 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
519 << QThread::currentThread()->objectName() << "DoAcqui"
571 << QThread::currentThread()->objectName() << "DoAcqui"
520 << impl->m_DoAcquisition;
572 << impl->m_DoAcquisition;
521
573
522 auto graphRange = SqpRange{t1.lower, t1.upper};
574 auto graphRange = SqpRange{t1.lower, t1.upper};
523 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
575 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
524
576
525 if (impl->m_DoAcquisition) {
577 if (impl->m_DoAcquisition) {
526 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
578 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
527
579
528 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
580 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
529 end = impl->m_VariableToPlotMultiMap.end();
581 end = impl->m_VariableToPlotMultiMap.end();
530 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
582 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
531 variableUnderGraphVector.push_back(it->first);
583 variableUnderGraphVector.push_back(it->first);
532 }
584 }
533 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
585 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
534 !impl->m_IsCalibration);
586 !impl->m_IsCalibration);
535
587
536 if (!impl->m_IsCalibration) {
588 if (!impl->m_IsCalibration) {
537 qCDebug(LOG_VisualizationGraphWidget())
589 qCDebug(LOG_VisualizationGraphWidget())
538 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
590 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
539 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
591 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
540 emit synchronize(graphRange, oldGraphRange);
592 emit synchronize(graphRange, oldGraphRange);
541 }
593 }
542 }
594 }
543
595
544 auto pos = mapFromGlobal(QCursor::pos());
596 auto pos = mapFromGlobal(QCursor::pos());
545 auto axisPos = impl->posToAxisPos(pos, plot());
597 auto axisPos = impl->posToAxisPos(pos, plot());
546 if (auto parentZone = parentZoneWidget()) {
598 if (auto parentZone = parentZoneWidget()) {
547 if (impl->pointIsInAxisRect(axisPos, plot())) {
599 if (impl->pointIsInAxisRect(axisPos, plot())) {
548 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
600 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
549 }
601 }
550 else {
602 else {
551 parentZone->notifyMouseLeaveGraph(this);
603 parentZone->notifyMouseLeaveGraph(this);
552 }
604 }
553 }
605 }
554 else {
606 else {
555 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
607 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
556 }
608 }
557 }
609 }
558
610
559 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
611 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
560 {
612 {
561 impl->m_RenderingDelegate->onMouseDoubleClick(event);
613 impl->m_RenderingDelegate->onMouseDoubleClick(event);
562 }
614 }
563
615
564 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
616 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
565 {
617 {
566 // Handles plot rendering when mouse is moving
618 // Handles plot rendering when mouse is moving
567 impl->m_RenderingDelegate->onMouseMove(event);
619 impl->m_RenderingDelegate->onMouseMove(event);
568
620
569 auto axisPos = impl->posToAxisPos(event->pos(), plot());
621 auto axisPos = impl->posToAxisPos(event->pos(), plot());
570
622
571 // Zoom box and zone drawing
623 // Zoom box and zone drawing
572 if (impl->m_DrawingZoomRect) {
624 if (impl->m_DrawingZoomRect) {
573 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
625 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
574 }
626 }
575 else if (impl->m_DrawingZone) {
627 else if (impl->m_DrawingZone) {
576 impl->m_DrawingZone->setEnd(axisPos.x());
628 impl->m_DrawingZone->setEnd(axisPos.x());
577 }
629 }
578
630
579 // Cursor
631 // Cursor
580 if (auto parentZone = parentZoneWidget()) {
632 if (auto parentZone = parentZoneWidget()) {
581 if (impl->pointIsInAxisRect(axisPos, plot())) {
633 if (impl->pointIsInAxisRect(axisPos, plot())) {
582 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
634 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
583 }
635 }
584 else {
636 else {
585 parentZone->notifyMouseLeaveGraph(this);
637 parentZone->notifyMouseLeaveGraph(this);
586 }
638 }
587 }
639 }
588 else {
640 else {
589 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
641 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
590 }
642 }
591
643
592 // Search for the selection zone under the mouse
644 // Search for the selection zone under the mouse
593 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
645 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
594 auto minDistanceToZone = -1;
595 for (auto zone : impl->m_SelectionZones) {
596 auto distanceToZone = zone->selectTest(event->pos(), true);
597 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone) && distanceToZone >= 0
598 && distanceToZone < plot().selectionTolerance()) {
599 selectionZoneItemUnderCursor = zone;
600 }
601 }
602
603 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
646 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
604 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
647 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
605
648
606 // Sets the appropriate cursor shape
649 // Sets the appropriate cursor shape
607 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
650 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
608 setCursor(cursorShape);
651 setCursor(cursorShape);
609
652
610 // Manages the hovered zone
653 // Manages the hovered zone
611 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
654 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
612 if (impl->m_HoveredZone) {
655 if (impl->m_HoveredZone) {
613 impl->m_HoveredZone->setHovered(false);
656 impl->m_HoveredZone->setHovered(false);
614 }
657 }
615 selectionZoneItemUnderCursor->setHovered(true);
658 selectionZoneItemUnderCursor->setHovered(true);
616 impl->m_HoveredZone = selectionZoneItemUnderCursor;
659 impl->m_HoveredZone = selectionZoneItemUnderCursor;
617 plot().replot(QCustomPlot::rpQueuedReplot);
660 plot().replot(QCustomPlot::rpQueuedReplot);
618 }
661 }
619 }
662 }
620 else {
663 else {
621 // There is no zone under the mouse or the interaction mode is not "selection zones"
664 // There is no zone under the mouse or the interaction mode is not "selection zones"
622 if (impl->m_HoveredZone) {
665 if (impl->m_HoveredZone) {
623 impl->m_HoveredZone->setHovered(false);
666 impl->m_HoveredZone->setHovered(false);
624 impl->m_HoveredZone = nullptr;
667 impl->m_HoveredZone = nullptr;
625 }
668 }
626
669
627 setCursor(Qt::ArrowCursor);
670 setCursor(Qt::ArrowCursor);
628 }
671 }
629
672
630 VisualizationDragWidget::mouseMoveEvent(event);
673 VisualizationDragWidget::mouseMoveEvent(event);
631 }
674 }
632
675
633 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
676 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
634 {
677 {
635 auto value = event->angleDelta().x() + event->angleDelta().y();
678 auto value = event->angleDelta().x() + event->angleDelta().y();
636 if (value != 0) {
679 if (value != 0) {
637
680
638 auto direction = value > 0 ? 1.0 : -1.0;
681 auto direction = value > 0 ? 1.0 : -1.0;
639 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
682 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
640 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
683 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
641 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
684 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
642
685
643 auto zoomOrientations = QFlags<Qt::Orientation>{};
686 auto zoomOrientations = QFlags<Qt::Orientation>{};
644 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
687 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
645 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
688 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
646
689
647 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
690 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
648
691
649 if (!isZoomX && !isZoomY) {
692 if (!isZoomX && !isZoomY) {
650 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
693 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
651 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
694 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
652
695
653 axis->setRange(axis->range() + diff);
696 axis->setRange(axis->range() + diff);
654
697
655 if (plot().noAntialiasingOnDrag()) {
698 if (plot().noAntialiasingOnDrag()) {
656 plot().setNotAntialiasedElements(QCP::aeAll);
699 plot().setNotAntialiasedElements(QCP::aeAll);
657 }
700 }
658
701
659 plot().replot(QCustomPlot::rpQueuedReplot);
702 plot().replot(QCustomPlot::rpQueuedReplot);
660 }
703 }
661 }
704 }
662 }
705 }
663
706
664 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
707 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
665 {
708 {
709 bool isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
710
711 if (!isDragDropClick) {
666 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
712 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
667 // Starts a zoom box
713 // Starts a zoom box
668 impl->startDrawingRect(event->pos(), plot());
714 impl->startDrawingRect(event->pos(), plot());
669 }
715 }
670 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
716 else if (sqpApp->plotsInteractionMode()
717 == SqpApplication::PlotsInteractionMode::SelectionZones
671 && impl->m_DrawingZone == nullptr) {
718 && impl->m_DrawingZone == nullptr) {
672 // Starts a new selection zone
719 // Starts a new selection zone
673 auto itemAtPos = plot().itemAt(event->pos(), true);
720 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
674 if (!itemAtPos) {
721 if (!zoneAtPos) {
675 impl->startDrawingZone(event->pos(), plot());
722 impl->startDrawingZone(event->pos(), plot());
676 }
723 }
677 }
724 }
725 }
678 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None) {
726 else if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None) {
679 plot().setInteraction(QCP::iRangeDrag, true);
727 plot().setInteraction(QCP::iRangeDrag, true);
680 }
728 }
681
729
682 // Allows mouse panning only in default mode
730 // Allows mouse panning only in default mode
683 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
731 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
684 == SqpApplication::PlotsInteractionMode::None);
732 == SqpApplication::PlotsInteractionMode::None
733 && !isDragDropClick);
685
734
686 // Allows zone edition only in selection zone mode
735 // Allows zone edition only in selection zone mode without ALT pressed (ALT is for drag&drop)
687 impl->setSelectionZonesEditionEnabled(sqpApp->plotsInteractionMode()
736 impl->setSelectionZonesEditionEnabled(
688 == SqpApplication::PlotsInteractionMode::SelectionZones);
737 sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
738 && !isDragDropClick);
689
739
690 VisualizationDragWidget::mousePressEvent(event);
740 VisualizationDragWidget::mousePressEvent(event);
691 }
741 }
692
742
693 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
743 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
694 {
744 {
695 if (impl->m_DrawingZoomRect) {
745 if (impl->m_DrawingZoomRect) {
696
746
697 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
747 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
698 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
748 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
699
749
700 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
750 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
701 impl->m_DrawingZoomRect->bottomRight->coords().x()};
751 impl->m_DrawingZoomRect->bottomRight->coords().x()};
702
752
703 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
753 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
704 impl->m_DrawingZoomRect->bottomRight->coords().y()};
754 impl->m_DrawingZoomRect->bottomRight->coords().y()};
705
755
706 impl->removeDrawingRect(plot());
756 impl->removeDrawingRect(plot());
707
757
708 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
758 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
709 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
759 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
710 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
760 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
711 axisX->setRange(newAxisXRange);
761 axisX->setRange(newAxisXRange);
712 axisY->setRange(newAxisYRange);
762 axisY->setRange(newAxisYRange);
713
763
714 plot().replot(QCustomPlot::rpQueuedReplot);
764 plot().replot(QCustomPlot::rpQueuedReplot);
715 }
765 }
716 }
766 }
717
767
718 impl->endDrawingZone(plot());
768 impl->endDrawingZone(plot());
719
769
720 impl->m_IsCalibration = false;
770 impl->m_IsCalibration = false;
721 }
771 }
722
772
723 void VisualizationGraphWidget::onDataCacheVariableUpdated()
773 void VisualizationGraphWidget::onDataCacheVariableUpdated()
724 {
774 {
725 auto graphRange = ui->widget->xAxis->range();
775 auto graphRange = ui->widget->xAxis->range();
726 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
776 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
727
777
728 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
778 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
729 auto variable = variableEntry.first;
779 auto variable = variableEntry.first;
730 qCDebug(LOG_VisualizationGraphWidget())
780 qCDebug(LOG_VisualizationGraphWidget())
731 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
781 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
732 qCDebug(LOG_VisualizationGraphWidget())
782 qCDebug(LOG_VisualizationGraphWidget())
733 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
783 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
734 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
784 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
735 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
785 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
736 }
786 }
737 }
787 }
738 }
788 }
739
789
740 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
790 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
741 const SqpRange &range)
791 const SqpRange &range)
742 {
792 {
743 auto it = impl->m_VariableToPlotMultiMap.find(variable);
793 auto it = impl->m_VariableToPlotMultiMap.find(variable);
744 if (it != impl->m_VariableToPlotMultiMap.end()) {
794 if (it != impl->m_VariableToPlotMultiMap.end()) {
745 impl->updateData(it->second, variable->dataSeries(), range);
795 impl->updateData(it->second, variable->dataSeries(), range);
746 }
796 }
747 }
797 }
@@ -1,271 +1,272
1 #include "Visualization/VisualizationSelectionZoneItem.h"
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2
2
3 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
3 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
4
4
5 QCustomPlot *m_Plot;
5 QCustomPlot *m_Plot;
6 double m_T1 = 0;
6 double m_T1 = 0;
7 double m_T2 = 0;
7 double m_T2 = 0;
8 QColor m_Color;
8 QColor m_Color;
9
9
10 bool m_IsEditionEnabled = true;
10 bool m_IsEditionEnabled = true;
11 double m_MovedOrinalT1 = 0;
11 double m_MovedOrinalT1 = 0;
12 double m_MovedOrinalT2 = 0;
12 double m_MovedOrinalT2 = 0;
13
13
14 QCPItemStraightLine *m_LeftLine;
14 QCPItemStraightLine *m_LeftLine;
15 QCPItemStraightLine *m_RightLine;
15 QCPItemStraightLine *m_RightLine;
16 QCPItemText *m_NameLabelItem = nullptr;
16 QCPItemText *m_NameLabelItem = nullptr;
17
17
18 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
18 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
19 EditionMode m_CurrentEditionMode;
19 EditionMode m_CurrentEditionMode;
20
20
21 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
21 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
22 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
22 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
23 {
23 {
24 }
24 }
25
25
26 void updatePosition(VisualizationSelectionZoneItem *item)
26 void updatePosition(VisualizationSelectionZoneItem *item)
27 {
27 {
28 item->topLeft->setCoords(m_T1, 0);
28 item->topLeft->setCoords(m_T1, 0);
29 item->bottomRight->setCoords(m_T2, 1);
29 item->bottomRight->setCoords(m_T2, 1);
30 }
30 }
31
31
32 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
32 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
33 {
33 {
34 auto distanceLeft = m_LeftLine->selectTest(pos, false);
34 auto distanceLeft = m_LeftLine->selectTest(pos, false);
35 auto distanceRight = m_RightLine->selectTest(pos, false);
35 auto distanceRight = m_RightLine->selectTest(pos, false);
36 auto distance = zoneItem->selectTest(pos, true);
36 auto distance = zoneItem->selectTest(pos, false);
37
37
38 if (distanceRight <= distance) {
38 if (distanceRight <= distance) {
39 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
39 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
40 }
40 }
41 else if (distanceLeft <= distance) {
41 else if (distanceLeft <= distance) {
42 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
42 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
43 }
43 }
44
44
45 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
45 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
46 }
46 }
47 };
47 };
48
48
49 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
49 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
50 : QCPItemRect(plot),
50 : QCPItemRect(plot),
51 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
51 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
52 {
52 {
53 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
53 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
54 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
54 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
55 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
55 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
56 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
56 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
57
57
58 impl->m_RightLine = new QCPItemStraightLine(plot);
58 impl->m_RightLine = new QCPItemStraightLine(plot);
59 impl->m_RightLine->point1->setParentAnchor(topRight);
59 impl->m_RightLine->point1->setParentAnchor(topRight);
60 impl->m_RightLine->point2->setParentAnchor(bottomRight);
60 impl->m_RightLine->point2->setParentAnchor(bottomRight);
61 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
61 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
62 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
62 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
63 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
63 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
64 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
64 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
65
65
66 impl->m_LeftLine = new QCPItemStraightLine(plot);
66 impl->m_LeftLine = new QCPItemStraightLine(plot);
67 impl->m_LeftLine->point1->setParentAnchor(topLeft);
67 impl->m_LeftLine->point1->setParentAnchor(topLeft);
68 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
68 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
69 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
69 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
70 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
70 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
71 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
71 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
72 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
72 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
73
73
74 impl->m_RightLine->setSelectable(false);
74 impl->m_RightLine->setSelectable(false);
75 impl->m_LeftLine->setSelectable(false);
75 impl->m_LeftLine->setSelectable(false);
76
76
77 // connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
77 // connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
78 // &QCPItemStraightLine::setSelected);
78 // &QCPItemStraightLine::setSelected);
79 // connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
79 // connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
80 // &QCPItemStraightLine::setSelected);
80 // &QCPItemStraightLine::setSelected);
81
81
82 setColor(QColor("#E79D41"));
82 setColor(QColor("#E79D41"));
83 }
83 }
84
84
85 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
85 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
86 {
86 {
87 impl->m_Plot->removeItem(impl->m_RightLine);
87 impl->m_Plot->removeItem(impl->m_RightLine);
88 impl->m_Plot->removeItem(impl->m_LeftLine);
88 impl->m_Plot->removeItem(impl->m_LeftLine);
89 }
89 }
90
90
91 void VisualizationSelectionZoneItem::setName(const QString &name)
91 void VisualizationSelectionZoneItem::setName(const QString &name)
92 {
92 {
93 if (name.isEmpty() && impl->m_NameLabelItem) {
93 if (name.isEmpty() && impl->m_NameLabelItem) {
94 impl->m_Plot->removeItem(impl->m_NameLabelItem);
94 impl->m_Plot->removeItem(impl->m_NameLabelItem);
95 impl->m_NameLabelItem = nullptr;
95 impl->m_NameLabelItem = nullptr;
96 }
96 }
97 else if (!impl->m_NameLabelItem) {
97 else if (!impl->m_NameLabelItem) {
98 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
98 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
99 impl->m_NameLabelItem->setText(name);
99 impl->m_NameLabelItem->setText(name);
100 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
100 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
101 impl->m_NameLabelItem->setColor(impl->m_Color);
101 impl->m_NameLabelItem->setColor(impl->m_Color);
102 impl->m_NameLabelItem->position->setParentAnchor(top);
102 impl->m_NameLabelItem->position->setParentAnchor(top);
103 }
103 }
104 }
104 }
105
105
106 QString VisualizationSelectionZoneItem::name() const
106 QString VisualizationSelectionZoneItem::name() const
107 {
107 {
108 if (!impl->m_NameLabelItem) {
108 if (!impl->m_NameLabelItem) {
109 return QString();
109 return QString();
110 }
110 }
111
111
112 return impl->m_NameLabelItem->text();
112 return impl->m_NameLabelItem->text();
113 }
113 }
114
114
115 SqpRange VisualizationSelectionZoneItem::range() const
115 SqpRange VisualizationSelectionZoneItem::range() const
116 {
116 {
117 SqpRange range;
117 SqpRange range;
118 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
118 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
119 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
119 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
120 return range;
120 return range;
121 }
121 }
122
122
123 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
123 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
124 {
124 {
125 impl->m_T1 = tstart;
125 impl->m_T1 = tstart;
126 impl->m_T2 = tend;
126 impl->m_T2 = tend;
127 impl->updatePosition(this);
127 impl->updatePosition(this);
128 }
128 }
129
129
130 void VisualizationSelectionZoneItem::setStart(double tstart)
130 void VisualizationSelectionZoneItem::setStart(double tstart)
131 {
131 {
132 impl->m_T1 = tstart;
132 impl->m_T1 = tstart;
133 impl->updatePosition(this);
133 impl->updatePosition(this);
134 }
134 }
135
135
136 void VisualizationSelectionZoneItem::setEnd(double tend)
136 void VisualizationSelectionZoneItem::setEnd(double tend)
137 {
137 {
138 impl->m_T2 = tend;
138 impl->m_T2 = tend;
139 impl->updatePosition(this);
139 impl->updatePosition(this);
140 }
140 }
141
141
142 void VisualizationSelectionZoneItem::setColor(const QColor &color)
142 void VisualizationSelectionZoneItem::setColor(const QColor &color)
143 {
143 {
144 impl->m_Color = color;
144 impl->m_Color = color;
145
145
146 auto brushColor = color;
146 auto brushColor = color;
147 brushColor.setAlpha(40);
147 brushColor.setAlpha(40);
148 setBrush(QBrush(brushColor));
148 setBrush(QBrush(brushColor));
149 setPen(QPen(Qt::NoPen));
149 setPen(QPen(Qt::NoPen));
150
150
151 auto selectedBrushColor = brushColor;
151 auto selectedBrushColor = brushColor;
152 selectedBrushColor.setAlpha(65);
152 selectedBrushColor.setAlpha(65);
153 setSelectedBrush(QBrush(selectedBrushColor));
153 setSelectedBrush(QBrush(selectedBrushColor));
154 setSelectedPen(QPen(Qt::NoPen));
154 setSelectedPen(QPen(Qt::NoPen));
155
155
156 auto linePen = QPen(color);
156 auto linePen = QPen(color);
157 linePen.setStyle(Qt::SolidLine);
157 linePen.setStyle(Qt::SolidLine);
158 linePen.setWidth(2);
158 linePen.setWidth(2);
159
159
160 auto selectedLinePen = linePen;
160 auto selectedLinePen = linePen;
161 selectedLinePen.setColor(color.darker(30));
161 selectedLinePen.setColor(color.darker(30));
162
162
163 impl->m_LeftLine->setPen(linePen);
163 impl->m_LeftLine->setPen(linePen);
164 impl->m_RightLine->setPen(linePen);
164 impl->m_RightLine->setPen(linePen);
165
165
166 impl->m_LeftLine->setSelectedPen(selectedLinePen);
166 impl->m_LeftLine->setSelectedPen(selectedLinePen);
167 impl->m_RightLine->setSelectedPen(selectedLinePen);
167 impl->m_RightLine->setSelectedPen(selectedLinePen);
168 }
168 }
169
169
170 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
170 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
171 {
171 {
172 impl->m_IsEditionEnabled = value;
172 impl->m_IsEditionEnabled = value;
173 setSelectable(value);
173 setSelectable(value);
174 if (!value) {
174 if (!value) {
175 setSelected(false);
175 setSelected(false);
176 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
176 }
177 }
177 }
178 }
178
179
179 bool VisualizationSelectionZoneItem::isEditionEnabled() const
180 bool VisualizationSelectionZoneItem::isEditionEnabled() const
180 {
181 {
181 return impl->m_IsEditionEnabled;
182 return impl->m_IsEditionEnabled;
182 }
183 }
183
184
184 Qt::CursorShape
185 Qt::CursorShape
185 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
186 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
186 {
187 {
187 auto mode = impl->m_CurrentEditionMode
188 auto mode = impl->m_CurrentEditionMode
188 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
189 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
189 ? impl->getEditionMode(position, this)
190 ? impl->getEditionMode(position, this)
190 : impl->m_CurrentEditionMode;
191 : impl->m_CurrentEditionMode;
191 switch (mode) {
192 switch (mode) {
192 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
193 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
193 return Qt::SizeAllCursor;
194 return Qt::SizeAllCursor;
194 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
195 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
195 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
196 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
196 return Qt::SizeHorCursor;
197 return Qt::SizeHorCursor;
197 default:
198 default:
198 return Qt::ArrowCursor;
199 return Qt::ArrowCursor;
199 }
200 }
200 }
201 }
201
202
202 void VisualizationSelectionZoneItem::setHovered(bool value)
203 void VisualizationSelectionZoneItem::setHovered(bool value)
203 {
204 {
204 if (value) {
205 if (value) {
205 auto linePen = impl->m_LeftLine->pen();
206 auto linePen = impl->m_LeftLine->pen();
206 linePen.setStyle(Qt::DotLine);
207 linePen.setStyle(Qt::DotLine);
207 linePen.setWidth(3);
208 linePen.setWidth(3);
208
209
209 auto selectedLinePen = impl->m_LeftLine->selectedPen();
210 auto selectedLinePen = impl->m_LeftLine->selectedPen();
210 ;
211 ;
211 selectedLinePen.setStyle(Qt::DotLine);
212 selectedLinePen.setStyle(Qt::DotLine);
212 selectedLinePen.setWidth(3);
213 selectedLinePen.setWidth(3);
213
214
214 impl->m_LeftLine->setPen(linePen);
215 impl->m_LeftLine->setPen(linePen);
215 impl->m_RightLine->setPen(linePen);
216 impl->m_RightLine->setPen(linePen);
216
217
217 impl->m_LeftLine->setSelectedPen(selectedLinePen);
218 impl->m_LeftLine->setSelectedPen(selectedLinePen);
218 impl->m_RightLine->setSelectedPen(selectedLinePen);
219 impl->m_RightLine->setSelectedPen(selectedLinePen);
219 }
220 }
220 else {
221 else {
221 setColor(impl->m_Color);
222 setColor(impl->m_Color);
222 }
223 }
223 }
224 }
224
225
225 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
226 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
226 {
227 {
227 if (isEditionEnabled()) {
228 if (isEditionEnabled()) {
228 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
229 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
229
230
230 impl->m_MovedOrinalT1 = impl->m_T1;
231 impl->m_MovedOrinalT1 = impl->m_T1;
231 impl->m_MovedOrinalT2 = impl->m_T2;
232 impl->m_MovedOrinalT2 = impl->m_T2;
232 }
233 }
233 else {
234 else {
234 event->ignore();
235 event->ignore();
235 }
236 }
236 }
237 }
237
238
238 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
239 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
239 {
240 {
240 if (isEditionEnabled()) {
241 if (isEditionEnabled()) {
241 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
242 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
242 auto diff = axis->pixelToCoord(event->pos().x()) - axis->pixelToCoord(startPos.x());
243 auto diff = axis->pixelToCoord(event->pos().x()) - axis->pixelToCoord(startPos.x());
243
244
244 switch (impl->m_CurrentEditionMode) {
245 switch (impl->m_CurrentEditionMode) {
245 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
246 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
246 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
247 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
247 break;
248 break;
248 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
249 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
249 setStart(impl->m_MovedOrinalT1 + diff);
250 setStart(impl->m_MovedOrinalT1 + diff);
250 break;
251 break;
251 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
252 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
252 setEnd(impl->m_MovedOrinalT2 + diff);
253 setEnd(impl->m_MovedOrinalT2 + diff);
253 break;
254 break;
254 // default:
255 // default:
255 // unknown edition mode
256 // unknown edition mode
256 }
257 }
257 }
258 }
258 else {
259 else {
259 event->ignore();
260 event->ignore();
260 }
261 }
261 }
262 }
262
263
263 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
264 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
264 {
265 {
265 if (isEditionEnabled()) {
266 if (isEditionEnabled()) {
266 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
267 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
267 }
268 }
268 else {
269 else {
269 event->ignore();
270 event->ignore();
270 }
271 }
271 }
272 }
@@ -1,583 +1,587
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "Visualization/VisualizationWidget.h"
6 #include "Visualization/VisualizationWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
7 #include "ui_VisualizationZoneWidget.h"
8
8
9 #include "Common/MimeTypesDef.h"
9 #include "Common/MimeTypesDef.h"
10 #include "Common/VisualizationDef.h"
10 #include "Common/VisualizationDef.h"
11
11
12 #include <Data/SqpRange.h>
12 #include <Data/SqpRange.h>
13 #include <Time/TimeController.h>
13 #include <Time/TimeController.h>
14 #include <Variable/Variable.h>
14 #include <Variable/Variable.h>
15 #include <Variable/VariableController.h>
15 #include <Variable/VariableController.h>
16
16
17 #include <Visualization/operations/FindVariableOperation.h>
17 #include <Visualization/operations/FindVariableOperation.h>
18
18
19 #include <DragAndDrop/DragDropHelper.h>
19 #include <DragAndDrop/DragDropHelper.h>
20 #include <QUuid>
20 #include <QUuid>
21 #include <SqpApplication.h>
21 #include <SqpApplication.h>
22 #include <cmath>
22 #include <cmath>
23
23
24 #include <QLayout>
24 #include <QLayout>
25
25
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
26 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
27
27
28 namespace {
28 namespace {
29
29
30
30
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
31 /// Generates a default name for a new graph, according to the number of graphs already displayed in
32 /// the zone
32 /// the zone
33 QString defaultGraphName(const QLayout &layout)
33 QString defaultGraphName(const QLayout &layout)
34 {
34 {
35 auto count = 0;
35 auto count = 0;
36 for (auto i = 0; i < layout.count(); ++i) {
36 for (auto i = 0; i < layout.count(); ++i) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
37 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
38 count++;
38 count++;
39 }
39 }
40 }
40 }
41
41
42 return QObject::tr("Graph %1").arg(count + 1);
42 return QObject::tr("Graph %1").arg(count + 1);
43 }
43 }
44
44
45 /**
45 /**
46 * Applies a function to all graphs of the zone represented by its layout
46 * Applies a function to all graphs of the zone represented by its layout
47 * @param layout the layout that contains graphs
47 * @param layout the layout that contains graphs
48 * @param fun the function to apply to each graph
48 * @param fun the function to apply to each graph
49 */
49 */
50 template <typename Fun>
50 template <typename Fun>
51 void processGraphs(QLayout &layout, Fun fun)
51 void processGraphs(QLayout &layout, Fun fun)
52 {
52 {
53 for (auto i = 0; i < layout.count(); ++i) {
53 for (auto i = 0; i < layout.count(); ++i) {
54 if (auto item = layout.itemAt(i)) {
54 if (auto item = layout.itemAt(i)) {
55 if (auto visualizationGraphWidget
55 if (auto visualizationGraphWidget
56 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
56 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
57 fun(*visualizationGraphWidget);
57 fun(*visualizationGraphWidget);
58 }
58 }
59 }
59 }
60 }
60 }
61 }
61 }
62
62
63 } // namespace
63 } // namespace
64
64
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
65 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
66
66
67 explicit VisualizationZoneWidgetPrivate()
67 explicit VisualizationZoneWidgetPrivate()
68 : m_SynchronisationGroupId{QUuid::createUuid()},
68 : m_SynchronisationGroupId{QUuid::createUuid()},
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
69 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
70 {
70 {
71 }
71 }
72 QUuid m_SynchronisationGroupId;
72 QUuid m_SynchronisationGroupId;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
73 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
74
74
75 // Returns the first graph in the zone or nullptr if there is no graph inside
75 // Returns the first graph in the zone or nullptr if there is no graph inside
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
76 VisualizationGraphWidget *firstGraph(const VisualizationZoneWidget *zoneWidget) const
77 {
77 {
78 VisualizationGraphWidget *firstGraph = nullptr;
78 VisualizationGraphWidget *firstGraph = nullptr;
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
79 auto layout = zoneWidget->ui->dragDropContainer->layout();
80 if (layout->count() > 0) {
80 if (layout->count() > 0) {
81 if (auto visualizationGraphWidget
81 if (auto visualizationGraphWidget
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
82 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
83 firstGraph = visualizationGraphWidget;
83 firstGraph = visualizationGraphWidget;
84 }
84 }
85 }
85 }
86
86
87 return firstGraph;
87 return firstGraph;
88 }
88 }
89
89
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
90 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
91 void dropVariables(const QList<std::shared_ptr<Variable> > &variables, int index,
92 VisualizationZoneWidget *zoneWidget);
92 VisualizationZoneWidget *zoneWidget);
93 };
93 };
94
94
95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
95 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
96 : VisualizationDragWidget{parent},
96 : VisualizationDragWidget{parent},
97 ui{new Ui::VisualizationZoneWidget},
97 ui{new Ui::VisualizationZoneWidget},
98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
98 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
99 {
99 {
100 ui->setupUi(this);
100 ui->setupUi(this);
101
101
102 ui->zoneNameLabel->setText(name);
102 ui->zoneNameLabel->setText(name);
103
103
104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
104 ui->dragDropContainer->setPlaceHolderType(DragDropHelper::PlaceHolderType::Graph);
105 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
105 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
106 VisualizationDragDropContainer::DropBehavior::Inserted);
106 VisualizationDragDropContainer::DropBehavior::Inserted);
107 ui->dragDropContainer->setMimeType(
107 ui->dragDropContainer->setMimeType(
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
108 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
109 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
109 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
110 VisualizationDragDropContainer::DropBehavior::Merged);
110 VisualizationDragDropContainer::DropBehavior::Merged);
111 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
111 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
112 VisualizationDragDropContainer::DropBehavior::Forbidden);
112 VisualizationDragDropContainer::DropBehavior::Forbidden);
113 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
114 VisualizationDragDropContainer::DropBehavior::Forbidden);
113 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
115 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
114 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
116 return sqpApp->dragDropHelper().checkMimeDataForVisualization(mimeData,
115 ui->dragDropContainer);
117 ui->dragDropContainer);
116 });
118 });
117
119
118 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
120 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
119 if (!mimeData) {
121 if (!mimeData) {
120 return false;
122 return false;
121 }
123 }
122
124
123 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
125 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
124 auto variables = sqpApp->variableController().variablesForMimeData(
126 auto variables = sqpApp->variableController().variablesForMimeData(
125 mimeData->data(MIME_TYPE_VARIABLE_LIST));
127 mimeData->data(MIME_TYPE_VARIABLE_LIST));
126
128
127 if (variables.count() != 1) {
129 if (variables.count() != 1) {
128 return false;
130 return false;
129 }
131 }
130 auto variable = variables.first();
132 auto variable = variables.first();
131
133
132 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
134 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
133 return graphWidget->canDrop(*variable);
135 return graphWidget->canDrop(*variable);
134 }
136 }
135 }
137 }
136
138
137 return true;
139 return true;
138 };
140 };
139 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
141 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
140
142
141 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
143 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
142 &VisualizationZoneWidget::dropMimeData);
144 &VisualizationZoneWidget::dropMimeData);
143 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
145 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
144 &VisualizationZoneWidget::dropMimeDataOnGraph);
146 &VisualizationZoneWidget::dropMimeDataOnGraph);
145
147
146 // 'Close' options : widget is deleted when closed
148 // 'Close' options : widget is deleted when closed
147 setAttribute(Qt::WA_DeleteOnClose);
149 setAttribute(Qt::WA_DeleteOnClose);
148 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
150 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
149 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
151 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
150
152
151 // Synchronisation id
153 // Synchronisation id
152 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
154 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
153 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
155 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
154 }
156 }
155
157
156 VisualizationZoneWidget::~VisualizationZoneWidget()
158 VisualizationZoneWidget::~VisualizationZoneWidget()
157 {
159 {
158 delete ui;
160 delete ui;
159 }
161 }
160
162
161 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
163 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
162 {
164 {
163 // Synchronize new graph with others in the zone
165 // Synchronize new graph with others in the zone
164 impl->m_Synchronizer->addGraph(*graphWidget);
166 impl->m_Synchronizer->addGraph(*graphWidget);
165
167
166 ui->dragDropContainer->addDragWidget(graphWidget);
168 ui->dragDropContainer->addDragWidget(graphWidget);
167 }
169 }
168
170
169 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
171 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
170 {
172 {
171 // Synchronize new graph with others in the zone
173 // Synchronize new graph with others in the zone
172 impl->m_Synchronizer->addGraph(*graphWidget);
174 impl->m_Synchronizer->addGraph(*graphWidget);
173
175
174 ui->dragDropContainer->insertDragWidget(index, graphWidget);
176 ui->dragDropContainer->insertDragWidget(index, graphWidget);
175 }
177 }
176
178
177 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
179 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
178 {
180 {
179 return createGraph(variable, -1);
181 return createGraph(variable, -1);
180 }
182 }
181
183
182 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
184 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
183 int index)
185 int index)
184 {
186 {
185 auto graphWidget
187 auto graphWidget
186 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
188 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
187
189
188
190
189 // Set graph properties
191 // Set graph properties
190 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
192 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
191 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
193 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
192
194
193
195
194 // Lambda to synchronize zone widget
196 // Lambda to synchronize zone widget
195 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
197 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
196 const SqpRange &oldGraphRange) {
198 const SqpRange &oldGraphRange) {
197
199
198 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
200 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
199 auto frameLayout = ui->dragDropContainer->layout();
201 auto frameLayout = ui->dragDropContainer->layout();
200 for (auto i = 0; i < frameLayout->count(); ++i) {
202 for (auto i = 0; i < frameLayout->count(); ++i) {
201 auto graphChild
203 auto graphChild
202 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
204 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
203 if (graphChild && (graphChild != graphWidget)) {
205 if (graphChild && (graphChild != graphWidget)) {
204
206
205 auto graphChildRange = graphChild->graphRange();
207 auto graphChildRange = graphChild->graphRange();
206 switch (zoomType) {
208 switch (zoomType) {
207 case AcquisitionZoomType::ZoomIn: {
209 case AcquisitionZoomType::ZoomIn: {
208 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
210 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
209 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
211 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
210 graphChildRange.m_TStart += deltaLeft;
212 graphChildRange.m_TStart += deltaLeft;
211 graphChildRange.m_TEnd -= deltaRight;
213 graphChildRange.m_TEnd -= deltaRight;
212 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
214 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
213 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
215 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
214 << deltaLeft;
216 << deltaLeft;
215 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
217 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
216 << deltaRight;
218 << deltaRight;
217 qCDebug(LOG_VisualizationZoneWidget())
219 qCDebug(LOG_VisualizationZoneWidget())
218 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
220 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
219
221
220 break;
222 break;
221 }
223 }
222
224
223 case AcquisitionZoomType::ZoomOut: {
225 case AcquisitionZoomType::ZoomOut: {
224 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
226 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
225 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
227 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
226 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
228 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
227 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
229 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
228 << deltaLeft;
230 << deltaLeft;
229 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
231 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
230 << deltaRight;
232 << deltaRight;
231 qCDebug(LOG_VisualizationZoneWidget())
233 qCDebug(LOG_VisualizationZoneWidget())
232 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
234 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
233 graphChildRange.m_TStart -= deltaLeft;
235 graphChildRange.m_TStart -= deltaLeft;
234 graphChildRange.m_TEnd += deltaRight;
236 graphChildRange.m_TEnd += deltaRight;
235 break;
237 break;
236 }
238 }
237 case AcquisitionZoomType::PanRight: {
239 case AcquisitionZoomType::PanRight: {
238 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
240 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
239 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
241 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
240 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
242 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
241 graphChildRange.m_TStart += deltaLeft;
243 graphChildRange.m_TStart += deltaLeft;
242 graphChildRange.m_TEnd += deltaRight;
244 graphChildRange.m_TEnd += deltaRight;
243 qCDebug(LOG_VisualizationZoneWidget())
245 qCDebug(LOG_VisualizationZoneWidget())
244 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
246 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
245 break;
247 break;
246 }
248 }
247 case AcquisitionZoomType::PanLeft: {
249 case AcquisitionZoomType::PanLeft: {
248 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
250 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
249 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
251 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
250 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
252 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
251 graphChildRange.m_TStart -= deltaLeft;
253 graphChildRange.m_TStart -= deltaLeft;
252 graphChildRange.m_TEnd -= deltaRight;
254 graphChildRange.m_TEnd -= deltaRight;
253 break;
255 break;
254 }
256 }
255 case AcquisitionZoomType::Unknown: {
257 case AcquisitionZoomType::Unknown: {
256 qCDebug(LOG_VisualizationZoneWidget())
258 qCDebug(LOG_VisualizationZoneWidget())
257 << tr("Impossible to synchronize: zoom type unknown");
259 << tr("Impossible to synchronize: zoom type unknown");
258 break;
260 break;
259 }
261 }
260 default:
262 default:
261 qCCritical(LOG_VisualizationZoneWidget())
263 qCCritical(LOG_VisualizationZoneWidget())
262 << tr("Impossible to synchronize: zoom type not take into account");
264 << tr("Impossible to synchronize: zoom type not take into account");
263 // No action
265 // No action
264 break;
266 break;
265 }
267 }
266 graphChild->enableAcquisition(false);
268 graphChild->enableAcquisition(false);
267 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
269 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
268 << graphChild->graphRange();
270 << graphChild->graphRange();
269 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
271 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
270 << graphChildRange;
272 << graphChildRange;
271 qCDebug(LOG_VisualizationZoneWidget())
273 qCDebug(LOG_VisualizationZoneWidget())
272 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
274 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
273 graphChild->setGraphRange(graphChildRange);
275 graphChild->setGraphRange(graphChildRange);
274 graphChild->enableAcquisition(true);
276 graphChild->enableAcquisition(true);
275 }
277 }
276 }
278 }
277 };
279 };
278
280
279 // connection for synchronization
281 // connection for synchronization
280 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
282 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
281 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
283 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
282 &VisualizationZoneWidget::onVariableAdded);
284 &VisualizationZoneWidget::onVariableAdded);
283 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
285 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
284 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
286 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
285
287
286 auto range = SqpRange{};
288 auto range = SqpRange{};
287 if (auto firstGraph = impl->firstGraph(this)) {
289 if (auto firstGraph = impl->firstGraph(this)) {
288 // Case of a new graph in a existant zone
290 // Case of a new graph in a existant zone
289 range = firstGraph->graphRange();
291 range = firstGraph->graphRange();
290 }
292 }
291 else {
293 else {
292 // Case of a new graph as the first of the zone
294 // Case of a new graph as the first of the zone
293 range = variable->range();
295 range = variable->range();
294 }
296 }
295
297
296 this->insertGraph(index, graphWidget);
298 this->insertGraph(index, graphWidget);
297
299
298 graphWidget->addVariable(variable, range);
300 graphWidget->addVariable(variable, range);
299 graphWidget->setYRange(variable);
301 graphWidget->setYRange(variable);
300
302
301 return graphWidget;
303 return graphWidget;
302 }
304 }
303
305
304 VisualizationGraphWidget *
306 VisualizationGraphWidget *
305 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
307 VisualizationZoneWidget::createGraph(const QList<std::shared_ptr<Variable> > variables, int index)
306 {
308 {
307 if (variables.isEmpty()) {
309 if (variables.isEmpty()) {
308 return nullptr;
310 return nullptr;
309 }
311 }
310
312
311 auto graphWidget = createGraph(variables.first(), index);
313 auto graphWidget = createGraph(variables.first(), index);
312 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
314 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
313 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
315 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
314 }
316 }
315
317
316 return graphWidget;
318 return graphWidget;
317 }
319 }
318
320
319 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
321 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
320 {
322 {
321 if (visitor) {
323 if (visitor) {
322 visitor->visitEnter(this);
324 visitor->visitEnter(this);
323
325
324 // Apply visitor to graph children: widgets different from graphs are not visited (no
326 // Apply visitor to graph children: widgets different from graphs are not visited (no
325 // action)
327 // action)
326 processGraphs(
328 processGraphs(
327 *ui->dragDropContainer->layout(),
329 *ui->dragDropContainer->layout(),
328 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
330 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
329
331
330 visitor->visitLeave(this);
332 visitor->visitLeave(this);
331 }
333 }
332 else {
334 else {
333 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
335 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
334 }
336 }
335 }
337 }
336
338
337 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
339 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
338 {
340 {
339 // A tab can always accomodate a variable
341 // A tab can always accomodate a variable
340 Q_UNUSED(variable);
342 Q_UNUSED(variable);
341 return true;
343 return true;
342 }
344 }
343
345
344 bool VisualizationZoneWidget::contains(const Variable &variable) const
346 bool VisualizationZoneWidget::contains(const Variable &variable) const
345 {
347 {
346 Q_UNUSED(variable);
348 Q_UNUSED(variable);
347 return false;
349 return false;
348 }
350 }
349
351
350 QString VisualizationZoneWidget::name() const
352 QString VisualizationZoneWidget::name() const
351 {
353 {
352 return ui->zoneNameLabel->text();
354 return ui->zoneNameLabel->text();
353 }
355 }
354
356
355 QMimeData *VisualizationZoneWidget::mimeData() const
357 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
356 {
358 {
359 Q_UNUSED(position);
360
357 auto mimeData = new QMimeData;
361 auto mimeData = new QMimeData;
358 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
362 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
359
363
360 if (auto firstGraph = impl->firstGraph(this)) {
364 if (auto firstGraph = impl->firstGraph(this)) {
361 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
365 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
362 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
366 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
363 }
367 }
364
368
365 return mimeData;
369 return mimeData;
366 }
370 }
367
371
368 bool VisualizationZoneWidget::isDragAllowed() const
372 bool VisualizationZoneWidget::isDragAllowed() const
369 {
373 {
370 return true;
374 return true;
371 }
375 }
372
376
373 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
377 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
374 const QPointF &plotPosition,
378 const QPointF &plotPosition,
375 VisualizationGraphWidget *graphWidget)
379 VisualizationGraphWidget *graphWidget)
376 {
380 {
377 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
381 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
378 VisualizationGraphWidget &processedGraph) {
382 VisualizationGraphWidget &processedGraph) {
379
383
380 switch (sqpApp->plotsCursorMode()) {
384 switch (sqpApp->plotsCursorMode()) {
381 case SqpApplication::PlotsCursorMode::Vertical:
385 case SqpApplication::PlotsCursorMode::Vertical:
382 processedGraph.removeHorizontalCursor();
386 processedGraph.removeHorizontalCursor();
383 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
387 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
384 break;
388 break;
385 case SqpApplication::PlotsCursorMode::Temporal:
389 case SqpApplication::PlotsCursorMode::Temporal:
386 processedGraph.addVerticalCursor(plotPosition.x());
390 processedGraph.addVerticalCursor(plotPosition.x());
387 processedGraph.removeHorizontalCursor();
391 processedGraph.removeHorizontalCursor();
388 break;
392 break;
389 case SqpApplication::PlotsCursorMode::Horizontal:
393 case SqpApplication::PlotsCursorMode::Horizontal:
390 processedGraph.removeVerticalCursor();
394 processedGraph.removeVerticalCursor();
391 if (&processedGraph == graphWidget) {
395 if (&processedGraph == graphWidget) {
392 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
396 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
393 }
397 }
394 else {
398 else {
395 processedGraph.removeHorizontalCursor();
399 processedGraph.removeHorizontalCursor();
396 }
400 }
397 break;
401 break;
398 case SqpApplication::PlotsCursorMode::Cross:
402 case SqpApplication::PlotsCursorMode::Cross:
399 if (&processedGraph == graphWidget) {
403 if (&processedGraph == graphWidget) {
400 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
404 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
401 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
405 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
402 }
406 }
403 else {
407 else {
404 processedGraph.removeHorizontalCursor();
408 processedGraph.removeHorizontalCursor();
405 processedGraph.removeVerticalCursor();
409 processedGraph.removeVerticalCursor();
406 }
410 }
407 break;
411 break;
408 case SqpApplication::PlotsCursorMode::NoCursor:
412 case SqpApplication::PlotsCursorMode::NoCursor:
409 processedGraph.removeHorizontalCursor();
413 processedGraph.removeHorizontalCursor();
410 processedGraph.removeVerticalCursor();
414 processedGraph.removeVerticalCursor();
411 break;
415 break;
412 }
416 }
413
417
414
418
415 });
419 });
416 }
420 }
417
421
418 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
422 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
419 {
423 {
420 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
424 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
421 processedGraph.removeHorizontalCursor();
425 processedGraph.removeHorizontalCursor();
422 processedGraph.removeVerticalCursor();
426 processedGraph.removeVerticalCursor();
423 });
427 });
424 }
428 }
425
429
426 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
430 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
427 {
431 {
428 // Closes graphs in the zone
432 // Closes graphs in the zone
429 processGraphs(*ui->dragDropContainer->layout(),
433 processGraphs(*ui->dragDropContainer->layout(),
430 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
434 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
431
435
432 // Delete synchronization group from variable controller
436 // Delete synchronization group from variable controller
433 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
437 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
434 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
438 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
435
439
436 QWidget::closeEvent(event);
440 QWidget::closeEvent(event);
437 }
441 }
438
442
439 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
443 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
440 {
444 {
441 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
445 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
442 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
446 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
443 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
447 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
444 }
448 }
445
449
446 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
450 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
447 {
451 {
448 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
452 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
449 Q_ARG(std::shared_ptr<Variable>, variable),
453 Q_ARG(std::shared_ptr<Variable>, variable),
450 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
454 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
451 }
455 }
452
456
453 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
457 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
454 {
458 {
455 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
459 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
456 impl->dropGraph(index, this);
460 impl->dropGraph(index, this);
457 }
461 }
458 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
462 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
459 auto variables = sqpApp->variableController().variablesForMimeData(
463 auto variables = sqpApp->variableController().variablesForMimeData(
460 mimeData->data(MIME_TYPE_VARIABLE_LIST));
464 mimeData->data(MIME_TYPE_VARIABLE_LIST));
461 impl->dropVariables(variables, index, this);
465 impl->dropVariables(variables, index, this);
462 }
466 }
463 else {
467 else {
464 qCWarning(LOG_VisualizationZoneWidget())
468 qCWarning(LOG_VisualizationZoneWidget())
465 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
469 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
466 }
470 }
467 }
471 }
468
472
469 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
473 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
470 const QMimeData *mimeData)
474 const QMimeData *mimeData)
471 {
475 {
472 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
476 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
473 if (!graphWidget) {
477 if (!graphWidget) {
474 qCWarning(LOG_VisualizationZoneWidget())
478 qCWarning(LOG_VisualizationZoneWidget())
475 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
479 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
476 "drop aborted");
480 "drop aborted");
477 Q_ASSERT(false);
481 Q_ASSERT(false);
478 return;
482 return;
479 }
483 }
480
484
481 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
485 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
482 auto variables = sqpApp->variableController().variablesForMimeData(
486 auto variables = sqpApp->variableController().variablesForMimeData(
483 mimeData->data(MIME_TYPE_VARIABLE_LIST));
487 mimeData->data(MIME_TYPE_VARIABLE_LIST));
484 for (const auto &var : variables) {
488 for (const auto &var : variables) {
485 graphWidget->addVariable(var, graphWidget->graphRange());
489 graphWidget->addVariable(var, graphWidget->graphRange());
486 }
490 }
487 }
491 }
488 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
492 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
489 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
493 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
490 graphWidget->setGraphRange(range);
494 graphWidget->setGraphRange(range);
491 }
495 }
492 else {
496 else {
493 qCWarning(LOG_VisualizationZoneWidget())
497 qCWarning(LOG_VisualizationZoneWidget())
494 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
498 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
495 }
499 }
496 }
500 }
497
501
498 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
502 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
499 int index, VisualizationZoneWidget *zoneWidget)
503 int index, VisualizationZoneWidget *zoneWidget)
500 {
504 {
501 auto &helper = sqpApp->dragDropHelper();
505 auto &helper = sqpApp->dragDropHelper();
502
506
503 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
507 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
504 if (!graphWidget) {
508 if (!graphWidget) {
505 qCWarning(LOG_VisualizationZoneWidget())
509 qCWarning(LOG_VisualizationZoneWidget())
506 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
510 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
507 "found or invalid.");
511 "found or invalid.");
508 Q_ASSERT(false);
512 Q_ASSERT(false);
509 return;
513 return;
510 }
514 }
511
515
512 auto parentDragDropContainer
516 auto parentDragDropContainer
513 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
517 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
514 if (!parentDragDropContainer) {
518 if (!parentDragDropContainer) {
515 qCWarning(LOG_VisualizationZoneWidget())
519 qCWarning(LOG_VisualizationZoneWidget())
516 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
520 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
517 "the dropped graph is not found.");
521 "the dropped graph is not found.");
518 Q_ASSERT(false);
522 Q_ASSERT(false);
519 return;
523 return;
520 }
524 }
521
525
522 const auto &variables = graphWidget->variables();
526 const auto &variables = graphWidget->variables();
523
527
524 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
528 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.isEmpty()) {
525 // The drop didn't occur in the same zone
529 // The drop didn't occur in the same zone
526
530
527 // Abort the requests for the variables (if any)
531 // Abort the requests for the variables (if any)
528 // Commented, because it's not sure if it's needed or not
532 // Commented, because it's not sure if it's needed or not
529 // for (const auto& var : variables)
533 // for (const auto& var : variables)
530 //{
534 //{
531 // sqpApp->variableController().onAbortProgressRequested(var);
535 // sqpApp->variableController().onAbortProgressRequested(var);
532 //}
536 //}
533
537
534 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
538 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
535 auto nbGraph = parentDragDropContainer->countDragWidget();
539 auto nbGraph = parentDragDropContainer->countDragWidget();
536 if (nbGraph == 1) {
540 if (nbGraph == 1) {
537 // This is the only graph in the previous zone, close the zone
541 // This is the only graph in the previous zone, close the zone
538 helper.delayedCloseWidget(previousParentZoneWidget);
542 helper.delayedCloseWidget(previousParentZoneWidget);
539 }
543 }
540 else {
544 else {
541 // Close the graph
545 // Close the graph
542 helper.delayedCloseWidget(graphWidget);
546 helper.delayedCloseWidget(graphWidget);
543 }
547 }
544
548
545 // Creates the new graph in the zone
549 // Creates the new graph in the zone
546 zoneWidget->createGraph(variables, index);
550 zoneWidget->createGraph(variables, index);
547 }
551 }
548 else {
552 else {
549 // The drop occurred in the same zone or the graph is empty
553 // The drop occurred in the same zone or the graph is empty
550 // Simple move of the graph, no variable operation associated
554 // Simple move of the graph, no variable operation associated
551 parentDragDropContainer->layout()->removeWidget(graphWidget);
555 parentDragDropContainer->layout()->removeWidget(graphWidget);
552
556
553 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
557 if (variables.isEmpty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
554 // The graph is empty and dropped in a different zone.
558 // The graph is empty and dropped in a different zone.
555 // Take the range of the first graph in the zone (if existing).
559 // Take the range of the first graph in the zone (if existing).
556 auto layout = zoneWidget->ui->dragDropContainer->layout();
560 auto layout = zoneWidget->ui->dragDropContainer->layout();
557 if (layout->count() > 0) {
561 if (layout->count() > 0) {
558 if (auto visualizationGraphWidget
562 if (auto visualizationGraphWidget
559 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
563 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
560 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
564 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
561 }
565 }
562 }
566 }
563 }
567 }
564
568
565 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
569 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
566 }
570 }
567 }
571 }
568
572
569 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
573 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
570 const QList<std::shared_ptr<Variable> > &variables, int index,
574 const QList<std::shared_ptr<Variable> > &variables, int index,
571 VisualizationZoneWidget *zoneWidget)
575 VisualizationZoneWidget *zoneWidget)
572 {
576 {
573 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
577 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
574 // compatible variable here
578 // compatible variable here
575 if (variables.count() > 1) {
579 if (variables.count() > 1) {
576 qCWarning(LOG_VisualizationZoneWidget())
580 qCWarning(LOG_VisualizationZoneWidget())
577 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
581 << tr("VisualizationZoneWidget::dropVariables, dropping multiple variables, operation "
578 "aborted.");
582 "aborted.");
579 return;
583 return;
580 }
584 }
581
585
582 zoneWidget->createGraph(variables, index);
586 zoneWidget->createGraph(variables, index);
583 }
587 }
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

You need to be logged in to leave comments. Login now