##// END OF EJS Templates
Added RAW graph sync implementation...
jeandet -
r1373:15c8e75d755d
parent child
Show More
@@ -1,170 +1,177
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 #include <QUuid>
9 #include <QUuid>
10
10
11 #include <memory>
11 #include <memory>
12
12
13 #include <Common/spimpl.h>
13 #include <Common/spimpl.h>
14
14
15 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
15 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
16
16
17 class QCPRange;
17 class QCPRange;
18 class QCustomPlot;
18 class QCustomPlot;
19 class DateTimeRange;
19 class DateTimeRange;
20 class Variable;
20 class Variable;
21 class VisualizationWidget;
21 class VisualizationWidget;
22 class VisualizationZoneWidget;
22 class VisualizationZoneWidget;
23 class VisualizationSelectionZoneItem;
23 class VisualizationSelectionZoneItem;
24
24
25 namespace Ui {
25 namespace Ui {
26 class VisualizationGraphWidget;
26 class VisualizationGraphWidget;
27 } // namespace Ui
27 } // namespace Ui
28
28
29 /// Defines options that can be associated with the graph
29 /// Defines options that can be associated with the graph
30 enum GraphFlag {
30 enum GraphFlag {
31 DisableAll = 0x0, ///< Disables acquisition and synchronization
31 DisableAll = 0x0, ///< Disables acquisition and synchronization
32 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
32 EnableAcquisition = 0x1, ///< When this flag is set, the change of the graph's range leads to
33 /// the acquisition of data
33 /// the acquisition of data
34 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
34 EnableSynchronization = 0x2, ///< When this flag is set, the change of the graph's range causes
35 /// the call to the synchronization of the graphs contained in the
35 /// the call to the synchronization of the graphs contained in the
36 /// same zone of this graph
36 /// same zone of this graph
37 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
37 EnableAll = ~DisableAll ///< Enables acquisition and synchronization
38 };
38 };
39
39
40 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
40 Q_DECLARE_FLAGS(GraphFlags, GraphFlag)
41 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
41 Q_DECLARE_OPERATORS_FOR_FLAGS(GraphFlags)
42
42
43 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
43 class VisualizationGraphWidget : public VisualizationDragWidget, public IVisualizationWidget {
44 Q_OBJECT
44 Q_OBJECT
45
45
46 friend class QCustomPlotSynchronizer;
46 friend class QCustomPlotSynchronizer;
47 friend class VisualizationGraphRenderingDelegate;
47 friend class VisualizationGraphRenderingDelegate;
48
48
49 public:
49 public:
50 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
50 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
51 virtual ~VisualizationGraphWidget();
51 virtual ~VisualizationGraphWidget();
52
52
53 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
53 /// Returns the VisualizationZoneWidget which contains the graph or nullptr
54 VisualizationZoneWidget *parentZoneWidget() const noexcept;
54 VisualizationZoneWidget *parentZoneWidget() const noexcept;
55
55
56 /// Returns the main VisualizationWidget which contains the graph or nullptr
56 /// Returns the main VisualizationWidget which contains the graph or nullptr
57 VisualizationWidget *parentVisualizationWidget() const;
57 VisualizationWidget *parentVisualizationWidget() const;
58
58
59 /// Sets graph options
59 /// Sets graph options
60 void setFlags(GraphFlags flags);
60 void setFlags(GraphFlags flags);
61
61
62 void addVariable(std::shared_ptr<Variable> variable, DateTimeRange range);
62 void addVariable(std::shared_ptr<Variable> variable, DateTimeRange range);
63
63
64 /// Removes a variable from the graph
64 /// Removes a variable from the graph
65 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
65 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
66
66
67 /// Returns the list of all variables used in the graph
67 /// Returns the list of all variables used in the graph
68 std::vector<std::shared_ptr<Variable> > variables() const;
68 std::vector<std::shared_ptr<Variable> > variables() const;
69
69
70 /// Sets the y-axis range based on the data of a variable
70 /// Sets the y-axis range based on the data of a variable
71 void setYRange(std::shared_ptr<Variable> variable);
71 void setYRange(std::shared_ptr<Variable> variable);
72 DateTimeRange graphRange() const noexcept;
72 DateTimeRange graphRange() const noexcept;
73 void setGraphRange(const DateTimeRange &range, bool calibration = false);
73 void setGraphRange(const DateTimeRange &range, bool updateVar = false);
74 void setAutoRangeOnVariableInitialization(bool value);
74 void setAutoRangeOnVariableInitialization(bool value);
75
75
76 // Zones
76 // Zones
77 /// Returns the ranges of all the selection zones on the graph
77 /// Returns the ranges of all the selection zones on the graph
78 QVector<DateTimeRange> selectionZoneRanges() const;
78 QVector<DateTimeRange> selectionZoneRanges() const;
79 /// Adds new selection zones in the graph
79 /// Adds new selection zones in the graph
80 void addSelectionZones(const QVector<DateTimeRange> &ranges);
80 void addSelectionZones(const QVector<DateTimeRange> &ranges);
81 /// Adds a new selection zone in the graph
81 /// Adds a new selection zone in the graph
82 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const DateTimeRange &range);
82 VisualizationSelectionZoneItem *addSelectionZone(const QString &name, const DateTimeRange &range);
83 /// Removes the specified selection zone
83 /// Removes the specified selection zone
84 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
84 void removeSelectionZone(VisualizationSelectionZoneItem *selectionZone);
85
85
86 /// Undo the last zoom done with a zoom box
86 /// Undo the last zoom done with a zoom box
87 void undoZoom();
87 void undoZoom();
88
88
89 void zoom(double factor, int center, Qt::Orientation orientation);
89 void zoom(double factor, int center, Qt::Orientation orientation, bool forward=true);
90 void move(double factor, Qt::Orientation orientation);
90 void move(double factor, Qt::Orientation orientation, bool forward=true);
91 void move(double dx, double dy, bool forward=true);
91
92
92 // IVisualizationWidget interface
93 // IVisualizationWidget interface
93 void accept(IVisualizationWidgetVisitor *visitor) override;
94 void accept(IVisualizationWidgetVisitor *visitor) override;
94 bool canDrop(const Variable &variable) const override;
95 bool canDrop(const Variable &variable) const override;
95 bool contains(const Variable &variable) const override;
96 bool contains(const Variable &variable) const override;
96 QString name() const override;
97 QString name() const override;
97
98
98 // VisualisationDragWidget
99 // VisualisationDragWidget
99 QMimeData *mimeData(const QPoint &position) const override;
100 QMimeData *mimeData(const QPoint &position) const override;
100 QPixmap customDragPixmap(const QPoint &dragPosition) override;
101 QPixmap customDragPixmap(const QPoint &dragPosition) override;
101 bool isDragAllowed() const override;
102 bool isDragAllowed() const override;
102 void highlightForMerge(bool highlighted) override;
103 void highlightForMerge(bool highlighted) override;
103
104
104 // Cursors
105 // Cursors
105 /// Adds or moves the vertical cursor at the specified value on the x-axis
106 /// Adds or moves the vertical cursor at the specified value on the x-axis
106 void addVerticalCursor(double time);
107 void addVerticalCursor(double time);
107 /// Adds or moves the vertical cursor at the specified value on the x-axis
108 /// Adds or moves the vertical cursor at the specified value on the x-axis
108 void addVerticalCursorAtViewportPosition(double position);
109 void addVerticalCursorAtViewportPosition(double position);
109 void removeVerticalCursor();
110 void removeVerticalCursor();
110 /// Adds or moves the vertical cursor at the specified value on the y-axis
111 /// Adds or moves the vertical cursor at the specified value on the y-axis
111 void addHorizontalCursor(double value);
112 void addHorizontalCursor(double value);
112 /// Adds or moves the vertical cursor at the specified value on the y-axis
113 /// Adds or moves the vertical cursor at the specified value on the y-axis
113 void addHorizontalCursorAtViewportPosition(double position);
114 void addHorizontalCursorAtViewportPosition(double position);
114 void removeHorizontalCursor();
115 void removeHorizontalCursor();
115
116
116 signals:
117 signals:
117 void synchronize(const DateTimeRange &range, const DateTimeRange &oldRange);
118 void synchronize(const DateTimeRange &range, const DateTimeRange &oldRange);
118 void changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange &range);
119 void changeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange &range);
119
120
120 /// Signal emitted when the variable is about to be removed from the graph
121 /// Signal emitted when the variable is about to be removed from the graph
121 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
122 void variableAboutToBeRemoved(std::shared_ptr<Variable> var);
122 /// Signal emitted when the variable has been added to the graph
123 /// Signal emitted when the variable has been added to the graph
123 void variableAdded(std::shared_ptr<Variable> var);
124 void variableAdded(std::shared_ptr<Variable> var);
124
125
126
127 void zoom_sig(double factor, int center, Qt::Orientation orientation, bool forward=true);
128 void move_sig(double factor, Qt::Orientation orientation, bool forward=true);
129 void move_sig(double dx, double dy, bool forward=true);
130
125 protected:
131 protected:
126 void closeEvent(QCloseEvent *event) override;
132 void closeEvent(QCloseEvent *event) override;
127 void enterEvent(QEvent *event) override;
133 void enterEvent(QEvent *event) override;
128 void leaveEvent(QEvent *event) override;
134 void leaveEvent(QEvent *event) override;
129 void wheelEvent(QWheelEvent * event) override;
135 void wheelEvent(QWheelEvent * event) override;
130 void mouseMoveEvent(QMouseEvent *event) override;
136 void mouseMoveEvent(QMouseEvent *event) override;
131 void mouseReleaseEvent(QMouseEvent *event) override;
137 void mouseReleaseEvent(QMouseEvent *event) override;
132 void mousePressEvent(QMouseEvent *event) override;
138 void mousePressEvent(QMouseEvent *event) override;
133 void mouseDoubleClickEvent(QMouseEvent *event) override;
139 void mouseDoubleClickEvent(QMouseEvent *event) override;
134 void keyReleaseEvent(QKeyEvent * event) override;
140 void keyReleaseEvent(QKeyEvent * event) override;
135 void keyPressEvent(QKeyEvent * event) override;
141 void keyPressEvent(QKeyEvent * event) override;
136
142
137 QCustomPlot &plot() const noexcept;
143 QCustomPlot &plot() const noexcept;
138
144
139 private:
145 private:
140 Ui::VisualizationGraphWidget *ui;
146 Ui::VisualizationGraphWidget *ui;
141
147
142 class VisualizationGraphWidgetPrivate;
148 class VisualizationGraphWidgetPrivate;
143 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
149 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
144
150
151 void _ugly_sync_(const QPoint& pos,const QPointF& axisPos);
145 private slots:
152 private slots:
146 /// Slot called when right clicking on the graph (displays a menu)
153 /// Slot called when right clicking on the graph (displays a menu)
147 void onGraphMenuRequested(const QPoint &pos) noexcept;
154 void onGraphMenuRequested(const QPoint &pos) noexcept;
148
155
149 /// Rescale the X axe to range parameter
156 /// Rescale the X axe to range parameter
150 // void onRangeChanged(const QCPRange &newRange, const QCPRange &oldRange);
157 // void onRangeChanged(const QCPRange &newRange, const QCPRange &oldRange);
151
158
152 /// Slot called when a mouse double click was made
159 /// Slot called when a mouse double click was made
153 void onMouseDoubleClick(QMouseEvent *event) noexcept;
160 void onMouseDoubleClick(QMouseEvent *event) noexcept;
154 /// Slot called when a mouse move was made
161 /// Slot called when a mouse move was made
155 void onMouseMove(QMouseEvent *event) noexcept;
162 void onMouseMove(QMouseEvent *event) noexcept;
156 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
163 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
157 void onMouseWheel(QWheelEvent *event) noexcept;
164 void onMouseWheel(QWheelEvent *event) noexcept;
158 /// Slot called when a mouse press was made, to activate the calibration of a graph
165 /// Slot called when a mouse press was made, to activate the calibration of a graph
159 void onMousePress(QMouseEvent *event) noexcept;
166 void onMousePress(QMouseEvent *event) noexcept;
160 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
167 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
161 void onMouseRelease(QMouseEvent *event) noexcept;
168 void onMouseRelease(QMouseEvent *event) noexcept;
162
169
163 void onDataCacheVariableUpdated();
170 void onDataCacheVariableUpdated();
164
171
165 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const DateTimeRange &range);
172 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const DateTimeRange &range);
166
173
167 void variableUpdated(QUuid id);
174 void variableUpdated(QUuid id);
168 };
175 };
169
176
170 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
177 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,1319 +1,1367
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/VisualizationMultiZoneSelectionDialog.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
10 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
13
13
14 #include <Actions/ActionsGuiController.h>
14 #include <Actions/ActionsGuiController.h>
15 #include <Actions/FilteringAction.h>
15 #include <Actions/FilteringAction.h>
16 #include <Common/MimeTypesDef.h>
16 #include <Common/MimeTypesDef.h>
17 #include <Data/ArrayData.h>
17 #include <Data/ArrayData.h>
18 #include <Data/IDataSeries.h>
18 #include <Data/IDataSeries.h>
19 #include <Data/SpectrogramSeries.h>
19 #include <Data/SpectrogramSeries.h>
20 #include <DragAndDrop/DragDropGuiController.h>
20 #include <DragAndDrop/DragDropGuiController.h>
21 #include <Settings/SqpSettingsDefs.h>
21 #include <Settings/SqpSettingsDefs.h>
22 #include <SqpApplication.h>
22 #include <SqpApplication.h>
23 #include <Time/TimeController.h>
23 #include <Time/TimeController.h>
24 #include <Variable/Variable.h>
24 #include <Variable/Variable.h>
25 #include <Variable/VariableController2.h>
25 #include <Variable/VariableController2.h>
26
26
27 #include <unordered_map>
27 #include <unordered_map>
28
28
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
29 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
30
30
31 namespace {
31 namespace {
32
32
33 /// Key pressed to enable drag&drop in all modes
33 /// Key pressed to enable drag&drop in all modes
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
34 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
35
35
36 /// Key pressed to enable zoom on horizontal axis
36 /// Key pressed to enable zoom on horizontal axis
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
37 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
38
38
39 /// Key pressed to enable zoom on vertical axis
39 /// Key pressed to enable zoom on vertical axis
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
40 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
41
41
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
42 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
43 const auto PAN_SPEED = 5;
43 const auto PAN_SPEED = 5;
44
44
45 /// Key pressed to enable a calibration pan
45 /// Key pressed to enable a calibration pan
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
46 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
47
47
48 /// Key pressed to enable multi selection of selection zones
48 /// Key pressed to enable multi selection of selection zones
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
49 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
50
50
51 /// Minimum size for the zoom box, in percentage of the axis range
51 /// Minimum size for the zoom box, in percentage of the axis range
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
52 const auto ZOOM_BOX_MIN_SIZE = 0.8;
53
53
54 /// Format of the dates appearing in the label of a cursor
54 /// Format of the dates appearing in the label of a cursor
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
55 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
56
56
57 } // namespace
57 } // namespace
58
58
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
59 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
60
60
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
61 explicit VisualizationGraphWidgetPrivate(const QString &name)
62 : m_Name{name},
62 : m_Name{name},
63 m_Flags{GraphFlag::EnableAll},
63 m_Flags{GraphFlag::EnableAll},
64 m_IsCalibration{false},
64 m_IsCalibration{false},
65 m_RenderingDelegate{nullptr}
65 m_RenderingDelegate{nullptr}
66 {
66 {
67 m_plot = new QCustomPlot();
67 m_plot = new QCustomPlot();
68 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
68 // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable.
69 m_plot->setPlottingHint(QCP::phFastPolylines, true);
69 m_plot->setPlottingHint(QCP::phFastPolylines, true);
70 }
70 }
71
71
72 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
72 void updateData(PlottablesMap &plottables, std::shared_ptr<Variable> variable,
73 const DateTimeRange &range)
73 const DateTimeRange &range)
74 {
74 {
75 VisualizationGraphHelper::updateData(plottables, variable, range);
75 VisualizationGraphHelper::updateData(plottables, variable, range);
76
76
77 // Prevents that data has changed to update rendering
77 // Prevents that data has changed to update rendering
78 m_RenderingDelegate->onPlotUpdated();
78 m_RenderingDelegate->onPlotUpdated();
79 }
79 }
80
80
81 QString m_Name;
81 QString m_Name;
82 // 1 variable -> n qcpplot
82 // 1 variable -> n qcpplot
83 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
83 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
84 GraphFlags m_Flags;
84 GraphFlags m_Flags;
85 bool m_IsCalibration;
85 bool m_IsCalibration;
86 QCustomPlot* m_plot;
86 QCustomPlot* m_plot;
87 QPoint m_lastMousePos;
87 QPoint m_lastMousePos;
88 QCPRange m_lastXRange;
89 QCPRange m_lastYRange;
88 /// Delegate used to attach rendering features to the plot
90 /// Delegate used to attach rendering features to the plot
89 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
91 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
90
92
91 QCPItemRect* m_DrawingZoomRect = nullptr;
93 QCPItemRect* m_DrawingZoomRect = nullptr;
92 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
94 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
93
95
94 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
96 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
95 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
97 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
96
98
97 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
99 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
98 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
100 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
99 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
101 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
100
102
101 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
103 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
102
104
103 bool m_VariableAutoRangeOnInit = true;
105 bool m_VariableAutoRangeOnInit = true;
104
106
105 inline void updateMousePosition(const QPoint& position)
107 inline void enterPlotDrag(const QPoint& position)
106 {
108 {
107 m_lastMousePos = position;
109 m_lastMousePos = m_plot->mapFromParent(position);
110 m_lastXRange = m_plot->xAxis->range();
111 m_lastYRange = m_plot->yAxis->range();
112
108 }
113 }
109
114
110 inline bool isDrawingZoomRect(){return m_DrawingZoomRect!=nullptr;}
115 inline bool isDrawingZoomRect(){return m_DrawingZoomRect!=nullptr;}
111 void updateZoomRect(const QPoint& newPos)
116 void updateZoomRect(const QPoint& newPos)
112 {
117 {
113 QPointF pos{m_plot->xAxis->pixelToCoord(newPos.x()), m_plot->yAxis->pixelToCoord(newPos.y())};
118 QPointF pos{m_plot->xAxis->pixelToCoord(newPos.x()), m_plot->yAxis->pixelToCoord(newPos.y())};
114 m_DrawingZoomRect->bottomRight->setCoords(pos);
119 m_DrawingZoomRect->bottomRight->setCoords(pos);
115 m_plot->replot(QCustomPlot::rpQueuedReplot);
120 m_plot->replot(QCustomPlot::rpQueuedReplot);
116 }
121 }
117
122
118 void applyZoomRect()
123 void applyZoomRect()
119 {
124 {
120 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
125 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
121 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
126 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
122
127
123 auto newAxisXRange = QCPRange{m_DrawingZoomRect->topLeft->coords().x(),
128 auto newAxisXRange = QCPRange{m_DrawingZoomRect->topLeft->coords().x(),
124 m_DrawingZoomRect->bottomRight->coords().x()};
129 m_DrawingZoomRect->bottomRight->coords().x()};
125
130
126 auto newAxisYRange = QCPRange{m_DrawingZoomRect->topLeft->coords().y(),
131 auto newAxisYRange = QCPRange{m_DrawingZoomRect->topLeft->coords().y(),
127 m_DrawingZoomRect->bottomRight->coords().y()};
132 m_DrawingZoomRect->bottomRight->coords().y()};
128
133
129 removeDrawingRect();
134 removeDrawingRect();
130
135
131 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
136 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
132 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
137 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
133 m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
138 m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
134 axisX->setRange(newAxisXRange);
139 axisX->setRange(newAxisXRange);
135 axisY->setRange(newAxisYRange);
140 axisY->setRange(newAxisYRange);
136
141
137 m_plot->replot(QCustomPlot::rpQueuedReplot);
142 m_plot->replot(QCustomPlot::rpQueuedReplot);
138 }
143 }
139 }
144 }
140
145
141 inline bool isDrawingZoneRect(){return m_DrawingZone!=nullptr;}
146 inline bool isDrawingZoneRect(){return m_DrawingZone!=nullptr;}
142 void updateZoneRect(const QPoint& newPos)
147 void updateZoneRect(const QPoint& newPos)
143 {
148 {
144 m_DrawingZone->setEnd(m_plot->xAxis->pixelToCoord(newPos.x()));
149 m_DrawingZone->setEnd(m_plot->xAxis->pixelToCoord(newPos.x()));
145 m_plot->replot(QCustomPlot::rpQueuedReplot);
150 m_plot->replot(QCustomPlot::rpQueuedReplot);
146 }
151 }
147
152
148 void startDrawingRect(const QPoint &pos)
153 void startDrawingRect(const QPoint &pos)
149 {
154 {
150 removeDrawingRect();
155 removeDrawingRect();
151
156
152 auto axisPos = posToAxisPos(pos);
157 auto axisPos = posToAxisPos(pos);
153
158
154 m_DrawingZoomRect = new QCPItemRect{m_plot};
159 m_DrawingZoomRect = new QCPItemRect{m_plot};
155 QPen p;
160 QPen p;
156 p.setWidth(2);
161 p.setWidth(2);
157 m_DrawingZoomRect->setPen(p);
162 m_DrawingZoomRect->setPen(p);
158
163
159 m_DrawingZoomRect->topLeft->setCoords(axisPos);
164 m_DrawingZoomRect->topLeft->setCoords(axisPos);
160 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
165 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
161 }
166 }
162
167
163 void removeDrawingRect()
168 void removeDrawingRect()
164 {
169 {
165 if (m_DrawingZoomRect) {
170 if (m_DrawingZoomRect) {
166 m_plot->removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
171 m_plot->removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
167 m_DrawingZoomRect = nullptr;
172 m_DrawingZoomRect = nullptr;
168 m_plot->replot(QCustomPlot::rpQueuedReplot);
173 m_plot->replot(QCustomPlot::rpQueuedReplot);
169 }
174 }
170 }
175 }
171
176
172 void selectZone(const QPoint &pos)
177 void selectZone(const QPoint &pos)
173 {
178 {
174 auto zoneAtPos = selectionZoneAt(pos);
179 auto zoneAtPos = selectionZoneAt(pos);
175 setSelectionZonesEditionEnabled(sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones);
180 setSelectionZonesEditionEnabled(sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones);
176 }
181 }
177
182
178 void startDrawingZone(const QPoint &pos)
183 void startDrawingZone(const QPoint &pos)
179 {
184 {
180 endDrawingZone();
185 endDrawingZone();
181
186
182 auto axisPos = posToAxisPos(pos);
187 auto axisPos = posToAxisPos(pos);
183
188
184 m_DrawingZone = new VisualizationSelectionZoneItem{m_plot};
189 m_DrawingZone = new VisualizationSelectionZoneItem{m_plot};
185 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
190 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
186 m_DrawingZone->setEditionEnabled(false);
191 m_DrawingZone->setEditionEnabled(false);
187 }
192 }
188
193
189 void endDrawingZone()
194 void endDrawingZone()
190 {
195 {
191 if (m_DrawingZone) {
196 if (m_DrawingZone) {
192 auto drawingZoneRange = m_DrawingZone->range();
197 auto drawingZoneRange = m_DrawingZone->range();
193 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
198 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
194 m_DrawingZone->setEditionEnabled(true);
199 m_DrawingZone->setEditionEnabled(true);
195 addSelectionZone(m_DrawingZone);
200 addSelectionZone(m_DrawingZone);
196 }
201 }
197 else {
202 else {
198 m_plot->removeItem(m_DrawingZone);
203 m_plot->removeItem(m_DrawingZone);
199 }
204 }
200
205
201 m_plot->replot(QCustomPlot::rpQueuedReplot);
206 m_plot->replot(QCustomPlot::rpQueuedReplot);
202 m_DrawingZone = nullptr;
207 m_DrawingZone = nullptr;
203 }
208 }
204 }
209 }
205
210
206 void moveSelectionZone(const QPoint& destination)
211 void moveSelectionZone(const QPoint& destination)
207 {
212 {
208 /*
213 /*
209 * I give up on this for now
214 * I give up on this for now
210 * @TODO implement this, the difficulty is that selection zones have their own
215 * @TODO implement this, the difficulty is that selection zones have their own
211 * event handling code which seems to rely on QCP GUI event handling propagation
216 * event handling code which seems to rely on QCP GUI event handling propagation
212 * which was a realy bad design choice.
217 * which was a realy bad design choice.
213 */
218 */
214 }
219 }
215
220
216 void setSelectionZonesEditionEnabled(bool value)
221 void setSelectionZonesEditionEnabled(bool value)
217 {
222 {
218 for (auto s : m_SelectionZones) {
223 for (auto s : m_SelectionZones) {
219 s->setEditionEnabled(value);
224 s->setEditionEnabled(value);
220 }
225 }
221 }
226 }
222
227
223 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
228 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
224
229
225 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos) const
230 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos) const
226 {
231 {
227 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
232 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
228 auto minDistanceToZone = -1;
233 auto minDistanceToZone = -1;
229 for (auto zone : m_SelectionZones) {
234 for (auto zone : m_SelectionZones) {
230 auto distanceToZone = zone->selectTest(pos, false);
235 auto distanceToZone = zone->selectTest(pos, false);
231 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
236 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
232 && distanceToZone >= 0 && distanceToZone < m_plot->selectionTolerance()) {
237 && distanceToZone >= 0 && distanceToZone < m_plot->selectionTolerance()) {
233 selectionZoneItemUnderCursor = zone;
238 selectionZoneItemUnderCursor = zone;
234 }
239 }
235 }
240 }
236
241
237 return selectionZoneItemUnderCursor;
242 return selectionZoneItemUnderCursor;
238 }
243 }
239
244
240 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
245 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
241 const QCustomPlot &plot) const
246 const QCustomPlot &plot) const
242 {
247 {
243 QVector<VisualizationSelectionZoneItem *> zones;
248 QVector<VisualizationSelectionZoneItem *> zones;
244 for (auto zone : m_SelectionZones) {
249 for (auto zone : m_SelectionZones) {
245 auto distanceToZone = zone->selectTest(pos, false);
250 auto distanceToZone = zone->selectTest(pos, false);
246 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
251 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
247 zones << zone;
252 zones << zone;
248 }
253 }
249 }
254 }
250
255
251 return zones;
256 return zones;
252 }
257 }
253
258
254 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
259 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
255 {
260 {
256 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
261 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
257 zone->moveToTop();
262 zone->moveToTop();
258 m_SelectionZones.removeAll(zone);
263 m_SelectionZones.removeAll(zone);
259 m_SelectionZones.append(zone);
264 m_SelectionZones.append(zone);
260 }
265 }
261 }
266 }
262
267
263 QPointF posToAxisPos(const QPoint &pos) const
268 QPointF posToAxisPos(const QPoint &pos) const
264 {
269 {
265 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
270 auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom);
266 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
271 auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft);
267 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
272 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
268 }
273 }
269
274
270 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
275 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
271 {
276 {
272 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
277 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
273 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
278 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
274 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
279 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
275 }
280 }
276
281
277 inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis *axis)
282 inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis *axis)
278 {
283 {
279 if (axis->scaleType() == QCPAxis::stLinear)
284 if (axis->scaleType() == QCPAxis::stLinear)
280 {
285 {
281 auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2);
286 auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2);
282 return QCPRange{axis->range().lower + diff, axis->range().upper + diff};
287 return QCPRange{axis->range().lower + diff, axis->range().upper + diff};
283 }
288 }
284 else
289 else
285 {
290 {
286 auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2);
291 auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2);
287 return QCPRange{axis->range().lower * diff, axis->range().upper * diff};
292 return QCPRange{axis->range().lower * diff, axis->range().upper * diff};
288 }
293 }
289 }
294 }
290
295
291 void setRange(const QCPRange &newRange)
296 void setRange(const DateTimeRange &newRange)
292 {
297 {
293 auto graphRange = DateTimeRange{newRange.lower, newRange.upper};
294
295 if (m_Flags.testFlag(GraphFlag::EnableAcquisition))
298 if (m_Flags.testFlag(GraphFlag::EnableAcquisition))
296 {
299 {
297 for (auto it = m_VariableToPlotMultiMap.begin(),
300 for (auto it = m_VariableToPlotMultiMap.begin(),
298 end = m_VariableToPlotMultiMap.end();
301 end = m_VariableToPlotMultiMap.end();
299 it != end; it = m_VariableToPlotMultiMap.upper_bound(it->first))
302 it != end; it = m_VariableToPlotMultiMap.upper_bound(it->first))
300 {
303 {
301 sqpApp->variableController().asyncChangeRange(it->first, graphRange);
304 sqpApp->variableController().asyncChangeRange(it->first, newRange);
302 }
305 }
303 }
306 }
304 }
307 }
305
308
306 void moveGraph(const QPoint& destination)
309 void setRange(const QCPRange &newRange)
310 {
311 auto graphRange = DateTimeRange{newRange.lower, newRange.upper};
312 setRange(graphRange);
313 }
314
315 std::tuple<double,double> moveGraph(const QPoint& destination)
316 {
317 auto currentPos = m_plot->mapFromParent(destination);
318 auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
319 auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
320 auto oldXRange = xAxis->range();
321 auto oldYRange = yAxis->range();
322 double dx = xAxis->pixelToCoord(m_lastMousePos.x()) - xAxis->pixelToCoord(currentPos.x());
323 xAxis->setRange(m_lastXRange.lower+dx, m_lastXRange.upper+dx);
324 if(yAxis->scaleType() == QCPAxis::stLinear)
325 {
326 double dy = yAxis->pixelToCoord(m_lastMousePos.y()) - yAxis->pixelToCoord(currentPos.y());
327 yAxis->setRange(m_lastYRange.lower+dy, m_lastYRange.upper+dy);
328 }
329 else
330 {
331 double dy = yAxis->pixelToCoord(m_lastMousePos.y()) / yAxis->pixelToCoord(currentPos.y());
332 yAxis->setRange(m_lastYRange.lower*dy, m_lastYRange.upper*dy);
333 }
334 auto newXRange = xAxis->range();
335 auto newYRange = yAxis->range();
336 setRange(xAxis->range());
337 m_plot->replot(QCustomPlot::rpQueuedReplot);
338 //m_lastMousePos = currentPos;
339 return {newXRange.lower - oldXRange.lower, newYRange.lower - oldYRange.lower};
340 }
341
342 void zoom(double factor, int center, Qt::Orientation orientation)
343 {
344 QCPAxis *axis = m_plot->axisRect()->rangeZoomAxis(orientation);
345 axis->scaleRange(factor, axis->pixelToCoord(center));
346 if (orientation == Qt::Horizontal)
347 setRange(axis->range());
348 m_plot->replot(QCustomPlot::rpQueuedReplot);
349 }
350
351 void move(double dx, double dy)
307 {
352 {
308 auto currentPos = destination;
309 auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
353 auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
310 auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
354 auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
311 xAxis->setRange(_pixDistanceToRange(m_lastMousePos.x(), currentPos.x(), xAxis));
355 xAxis->setRange(QCPRange(xAxis->range().lower+dx, xAxis->range().upper+dx));
312 yAxis->setRange(_pixDistanceToRange(m_lastMousePos.y(), currentPos.y(), yAxis));
356 yAxis->setRange(QCPRange(yAxis->range().lower+dy, yAxis->range().upper+dy));
313 setRange(xAxis->range());
357 setRange(xAxis->range());
314 m_plot->replot(QCustomPlot::rpQueuedReplot);
358 m_plot->replot(QCustomPlot::rpQueuedReplot);
315 m_lastMousePos = destination;
359 }
360
361 void move(double factor, Qt::Orientation orientation)
362 {
363 auto oldRange = m_plot->xAxis->range();
364 QCPAxis *axis = m_plot->axisRect()->rangeDragAxis(orientation);
365 if (m_plot->xAxis->scaleType() == QCPAxis::stLinear) {
366 double rg = (axis->range().upper - axis->range().lower) * (factor / 10);
367 axis->setRange(axis->range().lower + (rg), axis->range().upper + (rg));
368 }
369 else if (m_plot->xAxis->scaleType() == QCPAxis::stLogarithmic) {
370 int start = 0, stop = 0;
371 double diff = 0.;
372 if (factor > 0.0) {
373 stop = m_plot->width() * factor / 10;
374 start = 2 * m_plot->width() * factor / 10;
375 }
376 if (factor < 0.0) {
377 factor *= -1.0;
378 start = m_plot->width() * factor / 10;
379 stop = 2 * m_plot->width() * factor / 10;
380 }
381 diff = axis->pixelToCoord(start) / axis->pixelToCoord(stop);
382 axis->setRange(m_plot->axisRect()->rangeDragAxis(orientation)->range().lower * diff,
383 m_plot->axisRect()->rangeDragAxis(orientation)->range().upper * diff);
384 }
385 if (orientation == Qt::Horizontal)
386 setRange(axis->range());
387 m_plot->replot(QCustomPlot::rpQueuedReplot);
316 }
388 }
317 };
389 };
318
390
319 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
391 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
320 : VisualizationDragWidget{parent},
392 : VisualizationDragWidget{parent},
321 ui{new Ui::VisualizationGraphWidget},
393 ui{new Ui::VisualizationGraphWidget},
322 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
394 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
323 {
395 {
324 ui->setupUi(this);
396 ui->setupUi(this);
325 this->layout()->addWidget(impl->m_plot);
397 this->layout()->addWidget(impl->m_plot);
326 // 'Close' options : widget is deleted when closed
398 // 'Close' options : widget is deleted when closed
327 setAttribute(Qt::WA_DeleteOnClose);
399 setAttribute(Qt::WA_DeleteOnClose);
328
400
329 // The delegate must be initialized after the ui as it uses the plot
401 // The delegate must be initialized after the ui as it uses the plot
330 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
402 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
331
403
332 // Init the cursors
404 // Init the cursors
333 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
405 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
334 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
406 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
335 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
407 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
336 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
408 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
337
409
338 this->setFocusPolicy(Qt::WheelFocus);
410 this->setFocusPolicy(Qt::WheelFocus);
339 this->setMouseTracking(true);
411 this->setMouseTracking(true);
340 impl->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents);
412 impl->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents);
341 impl->m_plot->setContextMenuPolicy(Qt::CustomContextMenu);
413 impl->m_plot->setContextMenuPolicy(Qt::CustomContextMenu);
342 impl->m_plot->setParent(this);
414 impl->m_plot->setParent(this);
343 }
415 }
344
416
345
417
346 VisualizationGraphWidget::~VisualizationGraphWidget()
418 VisualizationGraphWidget::~VisualizationGraphWidget()
347 {
419 {
348 delete ui;
420 delete ui;
349 }
421 }
350
422
351 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
423 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
352 {
424 {
353 auto parent = parentWidget();
425 auto parent = parentWidget();
354 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
426 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
355 parent = parent->parentWidget();
427 parent = parent->parentWidget();
356 }
428 }
357
429
358 return qobject_cast<VisualizationZoneWidget *>(parent);
430 return qobject_cast<VisualizationZoneWidget *>(parent);
359 }
431 }
360
432
361 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
433 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
362 {
434 {
363 auto parent = parentWidget();
435 auto parent = parentWidget();
364 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
436 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
365 parent = parent->parentWidget();
437 parent = parent->parentWidget();
366 }
438 }
367
439
368 return qobject_cast<VisualizationWidget *>(parent);
440 return qobject_cast<VisualizationWidget *>(parent);
369 }
441 }
370
442
371 void VisualizationGraphWidget::setFlags(GraphFlags flags)
443 void VisualizationGraphWidget::setFlags(GraphFlags flags)
372 {
444 {
373 impl->m_Flags = std::move(flags);
445 impl->m_Flags = std::move(flags);
374 }
446 }
375
447
376 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
448 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, DateTimeRange range)
377 {
449 {
378 // Uses delegate to create the qcpplot components according to the variable
450 // Uses delegate to create the qcpplot components according to the variable
379 auto createdPlottables = VisualizationGraphHelper::create(variable, *impl->m_plot);
451 auto createdPlottables = VisualizationGraphHelper::create(variable, *impl->m_plot);
380
452
381 // Sets graph properties
453 // Sets graph properties
382 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
454 impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables);
383
455
384 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
456 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
385
457
386 // If the variable already has its data loaded, load its units and its range in the graph
458 // If the variable already has its data loaded, load its units and its range in the graph
387 if (variable->dataSeries() != nullptr) {
459 if (variable->dataSeries() != nullptr) {
388 impl->m_RenderingDelegate->setAxesUnits(*variable);
460 impl->m_RenderingDelegate->setAxesUnits(*variable);
389 this->setFlags(GraphFlag::DisableAll);
461 this->setFlags(GraphFlag::DisableAll);
390 setGraphRange(range);
462 setGraphRange(range);
391 this->setFlags(GraphFlag::EnableAll);
463 this->setFlags(GraphFlag::EnableAll);
392 }
464 }
393 //@TODO this is bad! when variable is moved to another graph it still fires
465 //@TODO this is bad! when variable is moved to another graph it still fires
394 // even if this has been deleted
466 // even if this has been deleted
395 connect(variable.get(), &Variable::updated, this, &VisualizationGraphWidget::variableUpdated);
467 connect(variable.get(), &Variable::updated, this, &VisualizationGraphWidget::variableUpdated);
396 this->onUpdateVarDisplaying(variable, range); // My bullshit
468 this->onUpdateVarDisplaying(variable, range); // My bullshit
397 emit variableAdded(variable);
469 emit variableAdded(variable);
398 }
470 }
399
471
400 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
472 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
401 {
473 {
402 // Each component associated to the variable :
474 // Each component associated to the variable :
403 // - is removed from qcpplot (which deletes it)
475 // - is removed from qcpplot (which deletes it)
404 // - is no longer referenced in the map
476 // - is no longer referenced in the map
405 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
477 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
406 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
478 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
407 emit variableAboutToBeRemoved(variable);
479 emit variableAboutToBeRemoved(variable);
408
480
409 auto &plottablesMap = variableIt->second;
481 auto &plottablesMap = variableIt->second;
410
482
411 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
483 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
412 plottableIt != plottableEnd;) {
484 plottableIt != plottableEnd;) {
413 impl->m_plot->removePlottable(plottableIt->second);
485 impl->m_plot->removePlottable(plottableIt->second);
414 plottableIt = plottablesMap.erase(plottableIt);
486 plottableIt = plottablesMap.erase(plottableIt);
415 }
487 }
416
488
417 impl->m_VariableToPlotMultiMap.erase(variableIt);
489 impl->m_VariableToPlotMultiMap.erase(variableIt);
418 }
490 }
419
491
420 // Updates graph
492 // Updates graph
421 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
493 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
422 }
494 }
423
495
424 std::vector<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
496 std::vector<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
425 {
497 {
426 auto variables = std::vector<std::shared_ptr<Variable> >{};
498 auto variables = std::vector<std::shared_ptr<Variable> >{};
427 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
499 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
428 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
500 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
429 variables.push_back(it->first);
501 variables.push_back(it->first);
430 }
502 }
431
503
432 return variables;
504 return variables;
433 }
505 }
434
506
435 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
507 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
436 {
508 {
437 if (!variable) {
509 if (!variable) {
438 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
510 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
439 return;
511 return;
440 }
512 }
441
513
442 VisualizationGraphHelper::setYAxisRange(variable, *impl->m_plot);
514 VisualizationGraphHelper::setYAxisRange(variable, *impl->m_plot);
443 }
515 }
444
516
445 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
517 DateTimeRange VisualizationGraphWidget::graphRange() const noexcept
446 {
518 {
447 auto graphRange = impl->m_plot->xAxis->range();
519 auto graphRange = impl->m_plot->xAxis->range();
448 return DateTimeRange{graphRange.lower, graphRange.upper};
520 return DateTimeRange{graphRange.lower, graphRange.upper};
449 }
521 }
450
522
451 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool calibration)
523 void VisualizationGraphWidget::setGraphRange(const DateTimeRange &range, bool updateVar)
452 {
524 {
453 if (calibration) {
454 impl->m_IsCalibration = true;
455 }
456
525
526 if(updateVar)
527 impl->setRange(range);
457 impl->m_plot->xAxis->setRange(range.m_TStart, range.m_TEnd);
528 impl->m_plot->xAxis->setRange(range.m_TStart, range.m_TEnd);
458 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
529 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
459
530
460 if (calibration) {
461 impl->m_IsCalibration = false;
462 }
463 }
531 }
464
532
465 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
533 void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value)
466 {
534 {
467 impl->m_VariableAutoRangeOnInit = value;
535 impl->m_VariableAutoRangeOnInit = value;
468 }
536 }
469
537
470 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
538 QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const
471 {
539 {
472 QVector<DateTimeRange> ranges;
540 QVector<DateTimeRange> ranges;
473 for (auto zone : impl->m_SelectionZones) {
541 for (auto zone : impl->m_SelectionZones) {
474 ranges << zone->range();
542 ranges << zone->range();
475 }
543 }
476
544
477 return ranges;
545 return ranges;
478 }
546 }
479
547
480 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
548 void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange> &ranges)
481 {
549 {
482 for (const auto &range : ranges) {
550 for (const auto &range : ranges) {
483 // note: ownership is transfered to QCustomPlot
551 // note: ownership is transfered to QCustomPlot
484 auto zone = new VisualizationSelectionZoneItem(&plot());
552 auto zone = new VisualizationSelectionZoneItem(&plot());
485 zone->setRange(range.m_TStart, range.m_TEnd);
553 zone->setRange(range.m_TStart, range.m_TEnd);
486 impl->addSelectionZone(zone);
554 impl->addSelectionZone(zone);
487 }
555 }
488
556
489 plot().replot(QCustomPlot::rpQueuedReplot);
557 plot().replot(QCustomPlot::rpQueuedReplot);
490 }
558 }
491
559
492 VisualizationSelectionZoneItem *
560 VisualizationSelectionZoneItem *
493 VisualizationGraphWidget::addSelectionZone(const QString &name, const DateTimeRange &range)
561 VisualizationGraphWidget::addSelectionZone(const QString &name, const DateTimeRange &range)
494 {
562 {
495 // note: ownership is transfered to QCustomPlot
563 // note: ownership is transfered to QCustomPlot
496 auto zone = new VisualizationSelectionZoneItem(&plot());
564 auto zone = new VisualizationSelectionZoneItem(&plot());
497 zone->setName(name);
565 zone->setName(name);
498 zone->setRange(range.m_TStart, range.m_TEnd);
566 zone->setRange(range.m_TStart, range.m_TEnd);
499 impl->addSelectionZone(zone);
567 impl->addSelectionZone(zone);
500
568
501 plot().replot(QCustomPlot::rpQueuedReplot);
569 plot().replot(QCustomPlot::rpQueuedReplot);
502
570
503 return zone;
571 return zone;
504 }
572 }
505
573
506 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
574 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
507 {
575 {
508 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
576 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
509
577
510 if (impl->m_HoveredZone == selectionZone) {
578 if (impl->m_HoveredZone == selectionZone) {
511 impl->m_HoveredZone = nullptr;
579 impl->m_HoveredZone = nullptr;
512 setCursor(Qt::ArrowCursor);
580 setCursor(Qt::ArrowCursor);
513 }
581 }
514
582
515 impl->m_SelectionZones.removeAll(selectionZone);
583 impl->m_SelectionZones.removeAll(selectionZone);
516 plot().removeItem(selectionZone);
584 plot().removeItem(selectionZone);
517 plot().replot(QCustomPlot::rpQueuedReplot);
585 plot().replot(QCustomPlot::rpQueuedReplot);
518 }
586 }
519
587
520 void VisualizationGraphWidget::undoZoom()
588 void VisualizationGraphWidget::undoZoom()
521 {
589 {
522 auto zoom = impl->m_ZoomStack.pop();
590 auto zoom = impl->m_ZoomStack.pop();
523 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
591 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
524 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
592 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
525
593
526 axisX->setRange(zoom.first);
594 axisX->setRange(zoom.first);
527 axisY->setRange(zoom.second);
595 axisY->setRange(zoom.second);
528
596
529 plot().replot(QCustomPlot::rpQueuedReplot);
597 plot().replot(QCustomPlot::rpQueuedReplot);
530 }
598 }
531
599
532 void VisualizationGraphWidget::zoom(double factor, int center, Qt::Orientation orientation)
600 void VisualizationGraphWidget::zoom(double factor, int center, Qt::Orientation orientation, bool forward)
601 {
602 impl->zoom(factor, center, orientation);
603 if(forward && orientation==Qt::Horizontal)
604 emit this->zoom_sig(factor, center, orientation, false);
605 }
533
606
607 void VisualizationGraphWidget::move(double factor, Qt::Orientation orientation, bool forward)
534 {
608 {
535 QCPAxis *axis = impl->m_plot->axisRect()->rangeZoomAxis(orientation);
609 impl->move(factor, orientation);
536 axis->scaleRange(factor, axis->pixelToCoord(center));
610 if(forward)
537 if (orientation == Qt::Horizontal)
611 emit this->move_sig(factor, orientation, false);
538 impl->setRange(axis->range());
539 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
540 }
612 }
541
613
542 void VisualizationGraphWidget::move(double factor, Qt::Orientation orientation)
614 void VisualizationGraphWidget::move(double dx, double dy, bool forward)
543 {
615 {
544 auto oldRange = impl->m_plot->xAxis->range();
616 impl->move(dx, dy);
545 QCPAxis *axis = impl->m_plot->axisRect()->rangeDragAxis(orientation);
617 if(forward)
546 if (impl->m_plot->xAxis->scaleType() == QCPAxis::stLinear) {
618 emit this->move_sig(dx, dy, false);
547 double rg = (axis->range().upper - axis->range().lower) * (factor / 10);
548 axis->setRange(axis->range().lower + (rg), axis->range().upper + (rg));
549 }
550 else if (impl->m_plot->xAxis->scaleType() == QCPAxis::stLogarithmic) {
551 int start = 0, stop = 0;
552 double diff = 0.;
553 if (factor > 0.0) {
554 stop = this->width() * factor / 10;
555 start = 2 * this->width() * factor / 10;
556 }
557 if (factor < 0.0) {
558 factor *= -1.0;
559 start = this->width() * factor / 10;
560 stop = 2 * this->width() * factor / 10;
561 }
562 diff = axis->pixelToCoord(start) / axis->pixelToCoord(stop);
563 axis->setRange(impl->m_plot->axisRect()->rangeDragAxis(orientation)->range().lower * diff,
564 impl->m_plot->axisRect()->rangeDragAxis(orientation)->range().upper * diff);
565 }
566 if (orientation == Qt::Horizontal)
567 impl->setRange(axis->range());
568 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
569 }
619 }
570
620
571 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
621 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
572 {
622 {
573 if (visitor) {
623 if (visitor) {
574 visitor->visit(this);
624 visitor->visit(this);
575 }
625 }
576 else {
626 else {
577 qCCritical(LOG_VisualizationGraphWidget())
627 qCCritical(LOG_VisualizationGraphWidget())
578 << tr("Can't visit widget : the visitor is null");
628 << tr("Can't visit widget : the visitor is null");
579 }
629 }
580 }
630 }
581
631
582 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
632 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
583 {
633 {
584 auto isSpectrogram = [](const auto &variable) {
634 auto isSpectrogram = [](const auto &variable) {
585 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
635 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
586 };
636 };
587
637
588 // - A spectrogram series can't be dropped on graph with existing plottables
638 // - A spectrogram series can't be dropped on graph with existing plottables
589 // - No data series can be dropped on graph with existing spectrogram series
639 // - No data series can be dropped on graph with existing spectrogram series
590 return isSpectrogram(variable)
640 return isSpectrogram(variable)
591 ? impl->m_VariableToPlotMultiMap.empty()
641 ? impl->m_VariableToPlotMultiMap.empty()
592 : std::none_of(
642 : std::none_of(
593 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
643 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
594 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
644 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
595 }
645 }
596
646
597 bool VisualizationGraphWidget::contains(const Variable &variable) const
647 bool VisualizationGraphWidget::contains(const Variable &variable) const
598 {
648 {
599 // Finds the variable among the keys of the map
649 // Finds the variable among the keys of the map
600 auto variablePtr = &variable;
650 auto variablePtr = &variable;
601 auto findVariable
651 auto findVariable
602 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
652 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
603
653
604 auto end = impl->m_VariableToPlotMultiMap.cend();
654 auto end = impl->m_VariableToPlotMultiMap.cend();
605 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
655 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
606 return it != end;
656 return it != end;
607 }
657 }
608
658
609 QString VisualizationGraphWidget::name() const
659 QString VisualizationGraphWidget::name() const
610 {
660 {
611 return impl->m_Name;
661 return impl->m_Name;
612 }
662 }
613
663
614 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
664 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
615 {
665 {
616 auto mimeData = new QMimeData;
666 auto mimeData = new QMimeData;
617
667
618 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position);
668 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position);
619 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
669 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
620 && selectionZoneItemUnderCursor) {
670 && selectionZoneItemUnderCursor) {
621 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
671 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
622 selectionZoneItemUnderCursor->range()));
672 selectionZoneItemUnderCursor->range()));
623 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
673 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
624 selectionZoneItemUnderCursor->range()));
674 selectionZoneItemUnderCursor->range()));
625 }
675 }
626 else {
676 else {
627 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
677 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
628
678
629 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
679 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
630 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
680 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
631 }
681 }
632
682
633 return mimeData;
683 return mimeData;
634 }
684 }
635
685
636 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
686 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
637 {
687 {
638 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition);
688 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition);
639 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
689 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
640 && selectionZoneItemUnderCursor) {
690 && selectionZoneItemUnderCursor) {
641
691
642 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
692 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
643 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
693 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
644
694
645 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
695 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
646 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
696 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
647 .toSize();
697 .toSize();
648
698
649 auto pixmap = QPixmap(zoneSize);
699 auto pixmap = QPixmap(zoneSize);
650 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
700 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
651
701
652 return pixmap;
702 return pixmap;
653 }
703 }
654
704
655 return QPixmap();
705 return QPixmap();
656 }
706 }
657
707
658 bool VisualizationGraphWidget::isDragAllowed() const
708 bool VisualizationGraphWidget::isDragAllowed() const
659 {
709 {
660 return true;
710 return true;
661 }
711 }
662
712
663 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
713 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
664 {
714 {
665 if (highlighted) {
715 if (highlighted) {
666 plot().setBackground(QBrush(QColor("#BBD5EE")));
716 plot().setBackground(QBrush(QColor("#BBD5EE")));
667 }
717 }
668 else {
718 else {
669 plot().setBackground(QBrush(Qt::white));
719 plot().setBackground(QBrush(Qt::white));
670 }
720 }
671
721
672 plot().update();
722 plot().update();
673 }
723 }
674
724
675 void VisualizationGraphWidget::addVerticalCursor(double time)
725 void VisualizationGraphWidget::addVerticalCursor(double time)
676 {
726 {
677 impl->m_VerticalCursor->setPosition(time);
727 impl->m_VerticalCursor->setPosition(time);
678 impl->m_VerticalCursor->setVisible(true);
728 impl->m_VerticalCursor->setVisible(true);
679
729
680 auto text
730 auto text
681 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
731 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
682 impl->m_VerticalCursor->setLabelText(text);
732 impl->m_VerticalCursor->setLabelText(text);
683 }
733 }
684
734
685 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
735 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
686 {
736 {
687 impl->m_VerticalCursor->setAbsolutePosition(position);
737 impl->m_VerticalCursor->setAbsolutePosition(position);
688 impl->m_VerticalCursor->setVisible(true);
738 impl->m_VerticalCursor->setVisible(true);
689
739
690 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
740 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
691 auto text
741 auto text
692 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
742 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
693 impl->m_VerticalCursor->setLabelText(text);
743 impl->m_VerticalCursor->setLabelText(text);
694 }
744 }
695
745
696 void VisualizationGraphWidget::removeVerticalCursor()
746 void VisualizationGraphWidget::removeVerticalCursor()
697 {
747 {
698 impl->m_VerticalCursor->setVisible(false);
748 impl->m_VerticalCursor->setVisible(false);
699 plot().replot(QCustomPlot::rpQueuedReplot);
749 plot().replot(QCustomPlot::rpQueuedReplot);
700 }
750 }
701
751
702 void VisualizationGraphWidget::addHorizontalCursor(double value)
752 void VisualizationGraphWidget::addHorizontalCursor(double value)
703 {
753 {
704 impl->m_HorizontalCursor->setPosition(value);
754 impl->m_HorizontalCursor->setPosition(value);
705 impl->m_HorizontalCursor->setVisible(true);
755 impl->m_HorizontalCursor->setVisible(true);
706 impl->m_HorizontalCursor->setLabelText(QString::number(value));
756 impl->m_HorizontalCursor->setLabelText(QString::number(value));
707 }
757 }
708
758
709 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
759 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
710 {
760 {
711 impl->m_HorizontalCursor->setAbsolutePosition(position);
761 impl->m_HorizontalCursor->setAbsolutePosition(position);
712 impl->m_HorizontalCursor->setVisible(true);
762 impl->m_HorizontalCursor->setVisible(true);
713
763
714 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
764 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
715 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
765 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
716 }
766 }
717
767
718 void VisualizationGraphWidget::removeHorizontalCursor()
768 void VisualizationGraphWidget::removeHorizontalCursor()
719 {
769 {
720 impl->m_HorizontalCursor->setVisible(false);
770 impl->m_HorizontalCursor->setVisible(false);
721 plot().replot(QCustomPlot::rpQueuedReplot);
771 plot().replot(QCustomPlot::rpQueuedReplot);
722 }
772 }
723
773
724 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
774 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
725 {
775 {
726 Q_UNUSED(event);
776 Q_UNUSED(event);
727
777
728 for (auto i : impl->m_SelectionZones) {
778 for (auto i : impl->m_SelectionZones) {
729 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
779 parentVisualizationWidget()->selectionZoneManager().setSelected(i, false);
730 }
780 }
731
781
732 // Prevents that all variables will be removed from graph when it will be closed
782 // Prevents that all variables will be removed from graph when it will be closed
733 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
783 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
734 emit variableAboutToBeRemoved(variableEntry.first);
784 emit variableAboutToBeRemoved(variableEntry.first);
735 }
785 }
736 }
786 }
737
787
738 void VisualizationGraphWidget::enterEvent(QEvent *event)
788 void VisualizationGraphWidget::enterEvent(QEvent *event)
739 {
789 {
740 Q_UNUSED(event);
790 Q_UNUSED(event);
741 impl->m_RenderingDelegate->showGraphOverlay(true);
791 impl->m_RenderingDelegate->showGraphOverlay(true);
742 }
792 }
743
793
744 void VisualizationGraphWidget::leaveEvent(QEvent *event)
794 void VisualizationGraphWidget::leaveEvent(QEvent *event)
745 {
795 {
746 Q_UNUSED(event);
796 Q_UNUSED(event);
747 impl->m_RenderingDelegate->showGraphOverlay(false);
797 impl->m_RenderingDelegate->showGraphOverlay(false);
748
798
749 if (auto parentZone = parentZoneWidget()) {
799 if (auto parentZone = parentZoneWidget()) {
750 parentZone->notifyMouseLeaveGraph(this);
800 parentZone->notifyMouseLeaveGraph(this);
751 }
801 }
752 else {
802 else {
753 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
803 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
754 }
804 }
755
805
756 if (impl->m_HoveredZone) {
806 if (impl->m_HoveredZone) {
757 impl->m_HoveredZone->setHovered(false);
807 impl->m_HoveredZone->setHovered(false);
758 impl->m_HoveredZone = nullptr;
808 impl->m_HoveredZone = nullptr;
759 }
809 }
760 }
810 }
761
811
762 void VisualizationGraphWidget::wheelEvent(QWheelEvent *event)
812 void VisualizationGraphWidget::wheelEvent(QWheelEvent *event)
763 {
813 {
764 double factor;
814 double factor;
765 double wheelSteps = event->delta() / 120.0; // a single step delta is +/-120 usually
815 double wheelSteps = event->delta() / 120.0; // a single step delta is +/-120 usually
766 if (event->modifiers() == Qt::ControlModifier) {
816 if (event->modifiers() == Qt::ControlModifier) {
767 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
817 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
768 {
818 {
769 setCursor(Qt::SizeVerCursor);
819 setCursor(Qt::SizeVerCursor);
770 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps);
820 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps);
771 zoom(factor, event->pos().y(), Qt::Vertical);
821 zoom(factor, event->pos().y(), Qt::Vertical);
772 }
822 }
773 }
823 }
774 else if (event->modifiers() == Qt::ShiftModifier) {
824 else if (event->modifiers() == Qt::ShiftModifier) {
775 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
825 if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical))
776 {
826 {
777 setCursor(Qt::SizeHorCursor);
827 setCursor(Qt::SizeHorCursor);
778 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps);
828 factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps);
779 zoom(factor, event->pos().x(), Qt::Horizontal);
829 zoom(factor, event->pos().x(), Qt::Horizontal);
780 }
830 }
781 }
831 }
782 else {
832 else {
783 move(wheelSteps, Qt::Horizontal);
833 move(wheelSteps, Qt::Horizontal);
784 }
834 }
785 QWidget::wheelEvent(event);
835 //QWidget::wheelEvent(event);
786 }
836 }
787
837
788
838
789
839
790 void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent *event)
840 void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent *event)
791 {
841 {
792 if(impl->isDrawingZoomRect())
842 if(impl->isDrawingZoomRect())
793 {
843 {
794 impl->updateZoomRect(event->pos());
844 impl->updateZoomRect(event->pos());
795 }
845 }
796 else if (impl->isDrawingZoneRect())
846 else if (impl->isDrawingZoneRect())
797 {
847 {
798 impl->updateZoneRect(event->pos());
848 impl->updateZoneRect(event->pos());
799 }
849 }
800 else if (event->buttons() == Qt::LeftButton)
850 else if (event->buttons() == Qt::LeftButton)
801 {
851 {
802 switch (sqpApp->plotsInteractionMode())
852 if(sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None)
803 {
853 {
804 case SqpApplication::PlotsInteractionMode::None:
854 auto [dx,dy] = impl->moveGraph(event->pos());
805 impl->moveGraph(event->pos());
855 emit this->move_sig(dx,0., false); // don't sync Y transformations
806 break;
856 }
807 case SqpApplication::PlotsInteractionMode::SelectionZones:
857 else if(sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones)
808
858 {
809 break;
859
810 default:
811 break;
812 }
860 }
813 }
861 }
814 else
862 else
815 {
863 {
816 impl->m_RenderingDelegate->updateTooltip(event);
864 impl->m_RenderingDelegate->updateTooltip(event);
817 }
865 }
818 QWidget::mouseMoveEvent(event);
866 QWidget::mouseMoveEvent(event);
819 }
867 }
820
868
821 void VisualizationGraphWidget::mouseReleaseEvent(QMouseEvent *event)
869 void VisualizationGraphWidget::mouseReleaseEvent(QMouseEvent *event)
822 {
870 {
823 if(impl->isDrawingZoomRect())
871 if(impl->isDrawingZoomRect())
824 {
872 {
825 impl->applyZoomRect();
873 impl->applyZoomRect();
826 }
874 }
827 else if(impl->isDrawingZoneRect())
875 else if(impl->isDrawingZoneRect())
828 {
876 {
829 impl->endDrawingZone();
877 impl->endDrawingZone();
830 }
878 }
831 else
879 else
832 {
880 {
833 setCursor(Qt::ArrowCursor);
881 setCursor(Qt::ArrowCursor);
834 }
882 }
835 QWidget::mouseReleaseEvent(event);
883 QWidget::mouseReleaseEvent(event);
836 }
884 }
837
885
838 void VisualizationGraphWidget::mousePressEvent(QMouseEvent *event)
886 void VisualizationGraphWidget::mousePressEvent(QMouseEvent *event)
839 {
887 {
840 if (event->button()==Qt::RightButton)
888 if (event->button()==Qt::RightButton)
841 {
889 {
842 onGraphMenuRequested(event->pos());
890 onGraphMenuRequested(event->pos());
843 }
891 }
844 else
892 else
845 {
893 {
846 auto selectedZone = impl->selectionZoneAt(event->pos());
894 auto selectedZone = impl->selectionZoneAt(event->pos());
847 switch (sqpApp->plotsInteractionMode())
895 switch (sqpApp->plotsInteractionMode())
848 {
896 {
849 case SqpApplication::PlotsInteractionMode::DragAndDrop :
897 case SqpApplication::PlotsInteractionMode::DragAndDrop :
850 break;
898 break;
851 case SqpApplication::PlotsInteractionMode::SelectionZones :
899 case SqpApplication::PlotsInteractionMode::SelectionZones :
852 impl->setSelectionZonesEditionEnabled(true);
900 impl->setSelectionZonesEditionEnabled(true);
853 if ((event->modifiers() == Qt::ControlModifier) && (selectedZone != nullptr))
901 if ((event->modifiers() == Qt::ControlModifier) && (selectedZone != nullptr))
854 {
902 {
855 selectedZone->setAssociatedEditedZones(parentVisualizationWidget()->selectionZoneManager().selectedItems());
903 selectedZone->setAssociatedEditedZones(parentVisualizationWidget()->selectionZoneManager().selectedItems());
856 }
904 }
857 else
905 else
858 {
906 {
859 if (!selectedZone)
907 if (!selectedZone)
860 {
908 {
861 parentVisualizationWidget()->selectionZoneManager().clearSelection();
909 parentVisualizationWidget()->selectionZoneManager().clearSelection();
862 impl->startDrawingZone(event->pos());
910 impl->startDrawingZone(event->pos());
863 }
911 }
864 else
912 else
865 {
913 {
866 parentVisualizationWidget()->selectionZoneManager().select({ selectedZone });
914 parentVisualizationWidget()->selectionZoneManager().select({ selectedZone });
867 }
915 }
868 }
916 }
869 break;
917 break;
870 case SqpApplication::PlotsInteractionMode::ZoomBox :
918 case SqpApplication::PlotsInteractionMode::ZoomBox :
871 impl->startDrawingRect(event->pos());
919 impl->startDrawingRect(event->pos());
872 break;
920 break;
873 default:
921 default:
874 setCursor(Qt::ClosedHandCursor);
922 setCursor(Qt::ClosedHandCursor);
875 impl->updateMousePosition(event->pos());
923 impl->enterPlotDrag(event->pos());
876 }
924 }
877 }
925 }
878 QWidget::mousePressEvent(event);
926 QWidget::mousePressEvent(event);
879 }
927 }
880
928
881 void VisualizationGraphWidget::mouseDoubleClickEvent(QMouseEvent *event)
929 void VisualizationGraphWidget::mouseDoubleClickEvent(QMouseEvent *event)
882 {
930 {
883 impl->m_RenderingDelegate->onMouseDoubleClick(event);
931 impl->m_RenderingDelegate->onMouseDoubleClick(event);
884 }
932 }
885
933
886 void VisualizationGraphWidget::keyReleaseEvent(QKeyEvent *event)
934 void VisualizationGraphWidget::keyReleaseEvent(QKeyEvent *event)
887 {
935 {
888 switch (event->key()) {
936 switch (event->key()) {
889 case Qt::Key_Control:
937 case Qt::Key_Control:
890 event->accept();
938 event->accept();
891 break;
939 break;
892 case Qt::Key_Shift:
940 case Qt::Key_Shift:
893 event->accept();
941 event->accept();
894 break;
942 break;
895 default:
943 default:
896 QWidget::keyReleaseEvent(event);
944 QWidget::keyReleaseEvent(event);
897 break;
945 break;
898 }
946 }
899 setCursor(Qt::ArrowCursor);
947 setCursor(Qt::ArrowCursor);
900 }
948 }
901
949
902 void VisualizationGraphWidget::keyPressEvent(QKeyEvent *event)
950 void VisualizationGraphWidget::keyPressEvent(QKeyEvent *event)
903 {
951 {
904 switch (event->key()) {
952 switch (event->key()) {
905 case Qt::Key_Control:
953 case Qt::Key_Control:
906 setCursor(Qt::CrossCursor);
954 setCursor(Qt::CrossCursor);
907 break;
955 break;
908 case Qt::Key_Shift:
956 case Qt::Key_Shift:
909 break;
957 break;
910 case Qt::Key_M:
958 case Qt::Key_M:
911 impl->m_plot->rescaleAxes();
959 impl->m_plot->rescaleAxes();
912 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
960 impl->m_plot->replot(QCustomPlot::rpQueuedReplot);
913 break;
961 break;
914 case Qt::Key_Left:
962 case Qt::Key_Left:
915 if (event->modifiers() != Qt::ControlModifier) {
963 if (event->modifiers() != Qt::ControlModifier) {
916 move(-0.1, Qt::Horizontal);
964 move(-0.1, Qt::Horizontal);
917 }
965 }
918 else {
966 else {
919 zoom(2, this->width() / 2, Qt::Horizontal);
967 zoom(2, this->width() / 2, Qt::Horizontal);
920 }
968 }
921 break;
969 break;
922 case Qt::Key_Right:
970 case Qt::Key_Right:
923 if (event->modifiers() != Qt::ControlModifier) {
971 if (event->modifiers() != Qt::ControlModifier) {
924 move(0.1, Qt::Horizontal);
972 move(0.1, Qt::Horizontal);
925 }
973 }
926 else {
974 else {
927 zoom(0.5, this->width() / 2, Qt::Horizontal);
975 zoom(0.5, this->width() / 2, Qt::Horizontal);
928 }
976 }
929 break;
977 break;
930 case Qt::Key_Up:
978 case Qt::Key_Up:
931 if (event->modifiers() != Qt::ControlModifier) {
979 if (event->modifiers() != Qt::ControlModifier) {
932 move(0.1, Qt::Vertical);
980 move(0.1, Qt::Vertical);
933 }
981 }
934 else {
982 else {
935 zoom(0.5, this->height() / 2, Qt::Vertical);
983 zoom(0.5, this->height() / 2, Qt::Vertical);
936 }
984 }
937 break;
985 break;
938 case Qt::Key_Down:
986 case Qt::Key_Down:
939 if (event->modifiers() != Qt::ControlModifier) {
987 if (event->modifiers() != Qt::ControlModifier) {
940 move(-0.1, Qt::Vertical);
988 move(-0.1, Qt::Vertical);
941 }
989 }
942 else {
990 else {
943 zoom(2, this->height() / 2, Qt::Vertical);
991 zoom(2, this->height() / 2, Qt::Vertical);
944 }
992 }
945 break;
993 break;
946 default:
994 default:
947 QWidget::keyPressEvent(event);
995 QWidget::keyPressEvent(event);
948 break;
996 break;
949 }
997 }
950 }
998 }
951
999
952 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
1000 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
953 {
1001 {
954 return *impl->m_plot;
1002 return *impl->m_plot;
955 }
1003 }
956
1004
957 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
1005 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
958 {
1006 {
959 QMenu graphMenu{};
1007 QMenu graphMenu{};
960
1008
961 // Iterates on variables (unique keys)
1009 // Iterates on variables (unique keys)
962 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
1010 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
963 end = impl->m_VariableToPlotMultiMap.cend();
1011 end = impl->m_VariableToPlotMultiMap.cend();
964 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
1012 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
965 // 'Remove variable' action
1013 // 'Remove variable' action
966 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
1014 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
967 [this, var = it->first]() { removeVariable(var); });
1015 [this, var = it->first]() { removeVariable(var); });
968 }
1016 }
969
1017
970 if (!impl->m_ZoomStack.isEmpty()) {
1018 if (!impl->m_ZoomStack.isEmpty()) {
971 if (!graphMenu.isEmpty()) {
1019 if (!graphMenu.isEmpty()) {
972 graphMenu.addSeparator();
1020 graphMenu.addSeparator();
973 }
1021 }
974
1022
975 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
1023 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
976 }
1024 }
977
1025
978 // Selection Zone Actions
1026 // Selection Zone Actions
979 auto selectionZoneItem = impl->selectionZoneAt(pos);
1027 auto selectionZoneItem = impl->selectionZoneAt(pos);
980 if (selectionZoneItem) {
1028 if (selectionZoneItem) {
981 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
1029 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
982 selectedItems.removeAll(selectionZoneItem);
1030 selectedItems.removeAll(selectionZoneItem);
983 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
1031 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
984
1032
985 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
1033 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
986 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
1034 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
987 graphMenu.addSeparator();
1035 graphMenu.addSeparator();
988 }
1036 }
989
1037
990 QHash<QString, QMenu *> subMenus;
1038 QHash<QString, QMenu *> subMenus;
991 QHash<QString, bool> subMenusEnabled;
1039 QHash<QString, bool> subMenusEnabled;
992 QHash<QString, FilteringAction *> filteredMenu;
1040 QHash<QString, FilteringAction *> filteredMenu;
993
1041
994 for (auto zoneAction : zoneActions) {
1042 for (auto zoneAction : zoneActions) {
995
1043
996 auto isEnabled = zoneAction->isEnabled(selectedItems);
1044 auto isEnabled = zoneAction->isEnabled(selectedItems);
997
1045
998 auto menu = &graphMenu;
1046 auto menu = &graphMenu;
999 QString menuPath;
1047 QString menuPath;
1000 for (auto subMenuName : zoneAction->subMenuList()) {
1048 for (auto subMenuName : zoneAction->subMenuList()) {
1001 menuPath += '/';
1049 menuPath += '/';
1002 menuPath += subMenuName;
1050 menuPath += subMenuName;
1003
1051
1004 if (!subMenus.contains(menuPath)) {
1052 if (!subMenus.contains(menuPath)) {
1005 menu = menu->addMenu(subMenuName);
1053 menu = menu->addMenu(subMenuName);
1006 subMenus[menuPath] = menu;
1054 subMenus[menuPath] = menu;
1007 subMenusEnabled[menuPath] = isEnabled;
1055 subMenusEnabled[menuPath] = isEnabled;
1008 }
1056 }
1009 else {
1057 else {
1010 menu = subMenus.value(menuPath);
1058 menu = subMenus.value(menuPath);
1011 if (isEnabled) {
1059 if (isEnabled) {
1012 // The sub menu is enabled if at least one of its actions is enabled
1060 // The sub menu is enabled if at least one of its actions is enabled
1013 subMenusEnabled[menuPath] = true;
1061 subMenusEnabled[menuPath] = true;
1014 }
1062 }
1015 }
1063 }
1016 }
1064 }
1017
1065
1018 FilteringAction *filterAction = nullptr;
1066 FilteringAction *filterAction = nullptr;
1019 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
1067 if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) {
1020 filterAction = filteredMenu.value(menuPath);
1068 filterAction = filteredMenu.value(menuPath);
1021 if (!filterAction) {
1069 if (!filterAction) {
1022 filterAction = new FilteringAction{this};
1070 filterAction = new FilteringAction{this};
1023 filteredMenu[menuPath] = filterAction;
1071 filteredMenu[menuPath] = filterAction;
1024 menu->addAction(filterAction);
1072 menu->addAction(filterAction);
1025 }
1073 }
1026 }
1074 }
1027
1075
1028 auto action = menu->addAction(zoneAction->name());
1076 auto action = menu->addAction(zoneAction->name());
1029 action->setEnabled(isEnabled);
1077 action->setEnabled(isEnabled);
1030 action->setShortcut(zoneAction->displayedShortcut());
1078 action->setShortcut(zoneAction->displayedShortcut());
1031 QObject::connect(action, &QAction::triggered,
1079 QObject::connect(action, &QAction::triggered,
1032 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
1080 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
1033
1081
1034 if (filterAction && zoneAction->isFilteringAllowed()) {
1082 if (filterAction && zoneAction->isFilteringAllowed()) {
1035 filterAction->addActionToFilter(action);
1083 filterAction->addActionToFilter(action);
1036 }
1084 }
1037 }
1085 }
1038
1086
1039 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
1087 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
1040 it.value()->setEnabled(subMenusEnabled[it.key()]);
1088 it.value()->setEnabled(subMenusEnabled[it.key()]);
1041 }
1089 }
1042 }
1090 }
1043
1091
1044 if (!graphMenu.isEmpty()) {
1092 if (!graphMenu.isEmpty()) {
1045 graphMenu.exec(QCursor::pos());
1093 graphMenu.exec(QCursor::pos());
1046 }
1094 }
1047 }
1095 }
1048
1096
1049 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
1097 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
1050 {
1098 {
1051 impl->m_RenderingDelegate->onMouseDoubleClick(event);
1099 impl->m_RenderingDelegate->onMouseDoubleClick(event);
1052 }
1100 }
1053
1101
1054 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
1102 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
1055 {
1103 {
1056 // Handles plot rendering when mouse is moving
1104 // Handles plot rendering when mouse is moving
1057 impl->m_RenderingDelegate->updateTooltip(event);
1105 impl->m_RenderingDelegate->updateTooltip(event);
1058
1106
1059 auto axisPos = impl->posToAxisPos(event->pos());
1107 auto axisPos = impl->posToAxisPos(event->pos());
1060
1108
1061 // Zoom box and zone drawing
1109 // Zoom box and zone drawing
1062 if (impl->m_DrawingZoomRect) {
1110 if (impl->m_DrawingZoomRect) {
1063 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
1111 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
1064 }
1112 }
1065 else if (impl->m_DrawingZone) {
1113 else if (impl->m_DrawingZone) {
1066 impl->m_DrawingZone->setEnd(axisPos.x());
1114 impl->m_DrawingZone->setEnd(axisPos.x());
1067 }
1115 }
1068
1116
1069 // Cursor
1117 // Cursor
1070 if (auto parentZone = parentZoneWidget()) {
1118 if (auto parentZone = parentZoneWidget()) {
1071 if (impl->pointIsInAxisRect(axisPos, plot())) {
1119 if (impl->pointIsInAxisRect(axisPos, plot())) {
1072 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
1120 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
1073 }
1121 }
1074 else {
1122 else {
1075 parentZone->notifyMouseLeaveGraph(this);
1123 parentZone->notifyMouseLeaveGraph(this);
1076 }
1124 }
1077 }
1125 }
1078
1126
1079 // Search for the selection zone under the mouse
1127 // Search for the selection zone under the mouse
1080 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1128 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1081 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
1129 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
1082 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
1130 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
1083
1131
1084 // Sets the appropriate cursor shape
1132 // Sets the appropriate cursor shape
1085 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
1133 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
1086 setCursor(cursorShape);
1134 setCursor(cursorShape);
1087
1135
1088 // Manages the hovered zone
1136 // Manages the hovered zone
1089 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
1137 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
1090 if (impl->m_HoveredZone) {
1138 if (impl->m_HoveredZone) {
1091 impl->m_HoveredZone->setHovered(false);
1139 impl->m_HoveredZone->setHovered(false);
1092 }
1140 }
1093 selectionZoneItemUnderCursor->setHovered(true);
1141 selectionZoneItemUnderCursor->setHovered(true);
1094 impl->m_HoveredZone = selectionZoneItemUnderCursor;
1142 impl->m_HoveredZone = selectionZoneItemUnderCursor;
1095 plot().replot(QCustomPlot::rpQueuedReplot);
1143 plot().replot(QCustomPlot::rpQueuedReplot);
1096 }
1144 }
1097 }
1145 }
1098 else {
1146 else {
1099 // There is no zone under the mouse or the interaction mode is not "selection zones"
1147 // There is no zone under the mouse or the interaction mode is not "selection zones"
1100 if (impl->m_HoveredZone) {
1148 if (impl->m_HoveredZone) {
1101 impl->m_HoveredZone->setHovered(false);
1149 impl->m_HoveredZone->setHovered(false);
1102 impl->m_HoveredZone = nullptr;
1150 impl->m_HoveredZone = nullptr;
1103 }
1151 }
1104
1152
1105 setCursor(Qt::ArrowCursor);
1153 setCursor(Qt::ArrowCursor);
1106 }
1154 }
1107
1155
1108 impl->m_HasMovedMouse = true;
1156 impl->m_HasMovedMouse = true;
1109 VisualizationDragWidget::mouseMoveEvent(event);
1157 VisualizationDragWidget::mouseMoveEvent(event);
1110 }
1158 }
1111
1159
1112 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
1160 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
1113 {
1161 {
1114 // Processes event only if the wheel occurs on axis rect
1162 // Processes event only if the wheel occurs on axis rect
1115 if (!dynamic_cast<QCPAxisRect *>(impl->m_plot->layoutElementAt(event->posF()))) {
1163 if (!dynamic_cast<QCPAxisRect *>(impl->m_plot->layoutElementAt(event->posF()))) {
1116 return;
1164 return;
1117 }
1165 }
1118
1166
1119 auto value = event->angleDelta().x() + event->angleDelta().y();
1167 auto value = event->angleDelta().x() + event->angleDelta().y();
1120 if (value != 0) {
1168 if (value != 0) {
1121
1169
1122 auto direction = value > 0 ? 1.0 : -1.0;
1170 auto direction = value > 0 ? 1.0 : -1.0;
1123 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
1171 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
1124 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
1172 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
1125 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
1173 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
1126
1174
1127 auto zoomOrientations = QFlags<Qt::Orientation>{};
1175 auto zoomOrientations = QFlags<Qt::Orientation>{};
1128 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
1176 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
1129 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
1177 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
1130
1178
1131 impl->m_plot->axisRect()->setRangeZoom(zoomOrientations);
1179 impl->m_plot->axisRect()->setRangeZoom(zoomOrientations);
1132
1180
1133 if (!isZoomX && !isZoomY) {
1181 if (!isZoomX && !isZoomY) {
1134 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
1182 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
1135 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
1183 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
1136
1184
1137 axis->setRange(axis->range() + diff);
1185 axis->setRange(axis->range() + diff);
1138
1186
1139 if (plot().noAntialiasingOnDrag()) {
1187 if (plot().noAntialiasingOnDrag()) {
1140 plot().setNotAntialiasedElements(QCP::aeAll);
1188 plot().setNotAntialiasedElements(QCP::aeAll);
1141 }
1189 }
1142
1190
1143 // plot().replot(QCustomPlot::rpQueuedReplot);
1191 // plot().replot(QCustomPlot::rpQueuedReplot);
1144 }
1192 }
1145 }
1193 }
1146 }
1194 }
1147
1195
1148 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
1196 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
1149 {
1197 {
1150 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
1198 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
1151 auto isSelectionZoneMode
1199 auto isSelectionZoneMode
1152 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1200 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1153 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
1201 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
1154
1202
1155 if (!isDragDropClick && isLeftClick) {
1203 if (!isDragDropClick && isLeftClick) {
1156 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
1204 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
1157 // Starts a zoom box
1205 // Starts a zoom box
1158 impl->startDrawingRect(event->pos());
1206 impl->startDrawingRect(event->pos());
1159 }
1207 }
1160 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
1208 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
1161 // Starts a new selection zone
1209 // Starts a new selection zone
1162 auto zoneAtPos = impl->selectionZoneAt(event->pos());
1210 auto zoneAtPos = impl->selectionZoneAt(event->pos());
1163 if (!zoneAtPos) {
1211 if (!zoneAtPos) {
1164 impl->startDrawingZone(event->pos());
1212 impl->startDrawingZone(event->pos());
1165 }
1213 }
1166 }
1214 }
1167 }
1215 }
1168
1216
1169
1217
1170 // Allows zone edition only in selection zone mode without drag&drop
1218 // Allows zone edition only in selection zone mode without drag&drop
1171 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
1219 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
1172
1220
1173 // Selection / Deselection
1221 // Selection / Deselection
1174 if (isSelectionZoneMode) {
1222 if (isSelectionZoneMode) {
1175 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1223 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1176 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1224 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1177
1225
1178
1226
1179 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
1227 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
1180 && !isMultiSelectionClick) {
1228 && !isMultiSelectionClick) {
1181 parentVisualizationWidget()->selectionZoneManager().select(
1229 parentVisualizationWidget()->selectionZoneManager().select(
1182 {selectionZoneItemUnderCursor});
1230 {selectionZoneItemUnderCursor});
1183 }
1231 }
1184 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
1232 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
1185 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1233 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1186 }
1234 }
1187 else {
1235 else {
1188 // No selection change
1236 // No selection change
1189 }
1237 }
1190
1238
1191 if (selectionZoneItemUnderCursor && isLeftClick) {
1239 if (selectionZoneItemUnderCursor && isLeftClick) {
1192 selectionZoneItemUnderCursor->setAssociatedEditedZones(
1240 selectionZoneItemUnderCursor->setAssociatedEditedZones(
1193 parentVisualizationWidget()->selectionZoneManager().selectedItems());
1241 parentVisualizationWidget()->selectionZoneManager().selectedItems());
1194 }
1242 }
1195 }
1243 }
1196
1244
1197
1245
1198 impl->m_HasMovedMouse = false;
1246 impl->m_HasMovedMouse = false;
1199 VisualizationDragWidget::mousePressEvent(event);
1247 VisualizationDragWidget::mousePressEvent(event);
1200 }
1248 }
1201
1249
1202 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
1250 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
1203 {
1251 {
1204 if (impl->m_DrawingZoomRect) {
1252 if (impl->m_DrawingZoomRect) {
1205
1253
1206 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
1254 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
1207 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
1255 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
1208
1256
1209 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
1257 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
1210 impl->m_DrawingZoomRect->bottomRight->coords().x()};
1258 impl->m_DrawingZoomRect->bottomRight->coords().x()};
1211
1259
1212 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
1260 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
1213 impl->m_DrawingZoomRect->bottomRight->coords().y()};
1261 impl->m_DrawingZoomRect->bottomRight->coords().y()};
1214
1262
1215 impl->removeDrawingRect();
1263 impl->removeDrawingRect();
1216
1264
1217 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
1265 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
1218 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
1266 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
1219 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
1267 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
1220 axisX->setRange(newAxisXRange);
1268 axisX->setRange(newAxisXRange);
1221 axisY->setRange(newAxisYRange);
1269 axisY->setRange(newAxisYRange);
1222
1270
1223 plot().replot(QCustomPlot::rpQueuedReplot);
1271 plot().replot(QCustomPlot::rpQueuedReplot);
1224 }
1272 }
1225 }
1273 }
1226
1274
1227 impl->endDrawingZone();
1275 impl->endDrawingZone();
1228
1276
1229 // Selection / Deselection
1277 // Selection / Deselection
1230 auto isSelectionZoneMode
1278 auto isSelectionZoneMode
1231 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1279 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
1232 if (isSelectionZoneMode) {
1280 if (isSelectionZoneMode) {
1233 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1281 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
1234 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1282 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos());
1235 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1283 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
1236 && !impl->m_HasMovedMouse) {
1284 && !impl->m_HasMovedMouse) {
1237
1285
1238 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1286 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
1239 if (zonesUnderCursor.count() > 1) {
1287 if (zonesUnderCursor.count() > 1) {
1240 // There are multiple zones under the mouse.
1288 // There are multiple zones under the mouse.
1241 // Performs the selection with a selection dialog.
1289 // Performs the selection with a selection dialog.
1242 VisualizationMultiZoneSelectionDialog dialog{this};
1290 VisualizationMultiZoneSelectionDialog dialog{this};
1243 dialog.setZones(zonesUnderCursor);
1291 dialog.setZones(zonesUnderCursor);
1244 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1292 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
1245 dialog.activateWindow();
1293 dialog.activateWindow();
1246 dialog.raise();
1294 dialog.raise();
1247 if (dialog.exec() == QDialog::Accepted) {
1295 if (dialog.exec() == QDialog::Accepted) {
1248 auto selection = dialog.selectedZones();
1296 auto selection = dialog.selectedZones();
1249
1297
1250 if (!isMultiSelectionClick) {
1298 if (!isMultiSelectionClick) {
1251 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1299 parentVisualizationWidget()->selectionZoneManager().clearSelection();
1252 }
1300 }
1253
1301
1254 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1302 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
1255 auto zone = it.key();
1303 auto zone = it.key();
1256 auto isSelected = it.value();
1304 auto isSelected = it.value();
1257 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1305 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
1258 isSelected);
1306 isSelected);
1259
1307
1260 if (isSelected) {
1308 if (isSelected) {
1261 // Puts the zone on top of the stack so it can be moved or resized
1309 // Puts the zone on top of the stack so it can be moved or resized
1262 impl->moveSelectionZoneOnTop(zone, plot());
1310 impl->moveSelectionZoneOnTop(zone, plot());
1263 }
1311 }
1264 }
1312 }
1265 }
1313 }
1266 }
1314 }
1267 else {
1315 else {
1268 if (!isMultiSelectionClick) {
1316 if (!isMultiSelectionClick) {
1269 parentVisualizationWidget()->selectionZoneManager().select(
1317 parentVisualizationWidget()->selectionZoneManager().select(
1270 {selectionZoneItemUnderCursor});
1318 {selectionZoneItemUnderCursor});
1271 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1319 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
1272 }
1320 }
1273 else {
1321 else {
1274 parentVisualizationWidget()->selectionZoneManager().setSelected(
1322 parentVisualizationWidget()->selectionZoneManager().setSelected(
1275 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1323 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
1276 || event->button() == Qt::RightButton);
1324 || event->button() == Qt::RightButton);
1277 }
1325 }
1278 }
1326 }
1279 }
1327 }
1280 else {
1328 else {
1281 // No selection change
1329 // No selection change
1282 }
1330 }
1283 }
1331 }
1284 }
1332 }
1285
1333
1286 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1334 void VisualizationGraphWidget::onDataCacheVariableUpdated()
1287 {
1335 {
1288 auto graphRange = impl->m_plot->xAxis->range();
1336 auto graphRange = impl->m_plot->xAxis->range();
1289 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1337 auto dateTime = DateTimeRange{graphRange.lower, graphRange.upper};
1290
1338
1291 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1339 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
1292 auto variable = variableEntry.first;
1340 auto variable = variableEntry.first;
1293 qCDebug(LOG_VisualizationGraphWidget())
1341 qCDebug(LOG_VisualizationGraphWidget())
1294 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1342 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
1295 qCDebug(LOG_VisualizationGraphWidget())
1343 qCDebug(LOG_VisualizationGraphWidget())
1296 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1344 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
1297 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1345 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
1298 impl->updateData(variableEntry.second, variable, variable->range());
1346 impl->updateData(variableEntry.second, variable, variable->range());
1299 }
1347 }
1300 }
1348 }
1301 }
1349 }
1302
1350
1303 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1351 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
1304 const DateTimeRange &range)
1352 const DateTimeRange &range)
1305 {
1353 {
1306 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1354 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1307 if (it != impl->m_VariableToPlotMultiMap.end()) {
1355 if (it != impl->m_VariableToPlotMultiMap.end()) {
1308 impl->updateData(it->second, variable, range);
1356 impl->updateData(it->second, variable, range);
1309 }
1357 }
1310 }
1358 }
1311
1359
1312 void VisualizationGraphWidget::variableUpdated(QUuid id)
1360 void VisualizationGraphWidget::variableUpdated(QUuid id)
1313 {
1361 {
1314 for (auto &[var, plotables] : impl->m_VariableToPlotMultiMap) {
1362 for (auto &[var, plotables] : impl->m_VariableToPlotMultiMap) {
1315 if (var->ID() == id) {
1363 if (var->ID() == id) {
1316 impl->updateData(plotables, var, this->graphRange());
1364 impl->updateData(plotables, var, this->graphRange());
1317 }
1365 }
1318 }
1366 }
1319 }
1367 }
@@ -1,629 +1,656
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/DateTimeRange.h>
12 #include <Data/DateTimeRange.h>
13 #include <Data/DateTimeRangeHelper.h>
13 #include <Data/DateTimeRangeHelper.h>
14 #include <DataSource/DataSourceController.h>
14 #include <DataSource/DataSourceController.h>
15 #include <Time/TimeController.h>
15 #include <Time/TimeController.h>
16 #include <Variable/Variable.h>
16 #include <Variable/Variable.h>
17 #include <Variable/VariableController2.h>
17 #include <Variable/VariableController2.h>
18
18
19 #include <Visualization/operations/FindVariableOperation.h>
19 #include <Visualization/operations/FindVariableOperation.h>
20
20
21 #include <DragAndDrop/DragDropGuiController.h>
21 #include <DragAndDrop/DragDropGuiController.h>
22 #include <QUuid>
22 #include <QUuid>
23 #include <SqpApplication.h>
23 #include <SqpApplication.h>
24 #include <cmath>
24 #include <cmath>
25
25
26 #include <QLayout>
26 #include <QLayout>
27 #include <QStyle>
27 #include <QStyle>
28
28
29 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
29 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
30
30
31 namespace {
31 namespace {
32
32
33 /**
33 /**
34 * Applies a function to all graphs of the zone represented by its layout
34 * Applies a function to all graphs of the zone represented by its layout
35 * @param layout the layout that contains graphs
35 * @param layout the layout that contains graphs
36 * @param fun the function to apply to each graph
36 * @param fun the function to apply to each graph
37 */
37 */
38 template <typename Fun>
38 template <typename Fun>
39 void processGraphs(QLayout &layout, Fun fun)
39 void processGraphs(QLayout &layout, Fun fun)
40 {
40 {
41 for (auto i = 0; i < layout.count(); ++i) {
41 for (auto i = 0; i < layout.count(); ++i) {
42 if (auto item = layout.itemAt(i)) {
42 if (auto item = layout.itemAt(i)) {
43 if (auto visualizationGraphWidget
43 if (auto visualizationGraphWidget
44 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
44 = qobject_cast<VisualizationGraphWidget *>(item->widget())) {
45 fun(*visualizationGraphWidget);
45 fun(*visualizationGraphWidget);
46 }
46 }
47 }
47 }
48 }
48 }
49 }
49 }
50
50
51 /// Generates a default name for a new graph, according to the number of graphs already displayed in
51 /// Generates a default name for a new graph, according to the number of graphs already displayed in
52 /// the zone
52 /// the zone
53 QString defaultGraphName(QLayout &layout)
53 QString defaultGraphName(QLayout &layout)
54 {
54 {
55 QSet<QString> existingNames;
55 QSet<QString> existingNames;
56 processGraphs(
56 processGraphs(
57 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
57 layout, [&existingNames](auto &graphWidget) { existingNames.insert(graphWidget.name()); });
58
58
59 int zoneNum = 1;
59 int zoneNum = 1;
60 QString name;
60 QString name;
61 do {
61 do {
62 name = QObject::tr("Graph ").append(QString::number(zoneNum));
62 name = QObject::tr("Graph ").append(QString::number(zoneNum));
63 ++zoneNum;
63 ++zoneNum;
64 } while (existingNames.contains(name));
64 } while (existingNames.contains(name));
65
65
66 return name;
66 return name;
67 }
67 }
68
68
69 } // namespace
69 } // namespace
70
70
71 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
71 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
72
72
73 explicit VisualizationZoneWidgetPrivate()
73 explicit VisualizationZoneWidgetPrivate()
74 : m_SynchronisationGroupId{QUuid::createUuid()},
74 : m_SynchronisationGroupId{QUuid::createUuid()},
75 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
75 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
76 {
76 {
77 }
77 }
78 QUuid m_SynchronisationGroupId;
78 QUuid m_SynchronisationGroupId;
79 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
79 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
80
80
81 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
81 void dropGraph(int index, VisualizationZoneWidget *zoneWidget);
82 void dropVariables(const std::vector<std::shared_ptr<Variable> > &variables, int index,
82 void dropVariables(const std::vector<std::shared_ptr<Variable> > &variables, int index,
83 VisualizationZoneWidget *zoneWidget);
83 VisualizationZoneWidget *zoneWidget);
84 void dropProducts(const QVariantList &productsData, int index,
84 void dropProducts(const QVariantList &productsData, int index,
85 VisualizationZoneWidget *zoneWidget);
85 VisualizationZoneWidget *zoneWidget);
86 };
86 };
87
87
88 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
88 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
89 : VisualizationDragWidget{parent},
89 : VisualizationDragWidget{parent},
90 ui{new Ui::VisualizationZoneWidget},
90 ui{new Ui::VisualizationZoneWidget},
91 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
91 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
92 {
92 {
93 ui->setupUi(this);
93 ui->setupUi(this);
94
94
95 ui->zoneNameLabel->setText(name);
95 ui->zoneNameLabel->setText(name);
96
96
97 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
97 ui->dragDropContainer->setPlaceHolderType(DragDropGuiController::PlaceHolderType::Graph);
98 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
98 ui->dragDropContainer->setMimeType(MIME_TYPE_GRAPH,
99 VisualizationDragDropContainer::DropBehavior::Inserted);
99 VisualizationDragDropContainer::DropBehavior::Inserted);
100 ui->dragDropContainer->setMimeType(
100 ui->dragDropContainer->setMimeType(
101 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
101 MIME_TYPE_VARIABLE_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
102 ui->dragDropContainer->setMimeType(
102 ui->dragDropContainer->setMimeType(
103 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
103 MIME_TYPE_PRODUCT_LIST, VisualizationDragDropContainer::DropBehavior::InsertedAndMerged);
104 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
104 ui->dragDropContainer->setMimeType(MIME_TYPE_TIME_RANGE,
105 VisualizationDragDropContainer::DropBehavior::Merged);
105 VisualizationDragDropContainer::DropBehavior::Merged);
106 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
106 ui->dragDropContainer->setMimeType(MIME_TYPE_ZONE,
107 VisualizationDragDropContainer::DropBehavior::Forbidden);
107 VisualizationDragDropContainer::DropBehavior::Forbidden);
108 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
108 ui->dragDropContainer->setMimeType(MIME_TYPE_SELECTION_ZONE,
109 VisualizationDragDropContainer::DropBehavior::Forbidden);
109 VisualizationDragDropContainer::DropBehavior::Forbidden);
110 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
110 ui->dragDropContainer->setAcceptMimeDataFunction([this](auto mimeData) {
111 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
111 return sqpApp->dragDropGuiController().checkMimeDataForVisualization(mimeData,
112 ui->dragDropContainer);
112 ui->dragDropContainer);
113 });
113 });
114
114
115 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
115 auto acceptDragWidgetFun = [](auto dragWidget, auto mimeData) {
116 if (!mimeData) {
116 if (!mimeData) {
117 return false;
117 return false;
118 }
118 }
119
119
120 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
120 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
121 auto variables = sqpApp->variableController().variables(
121 auto variables = sqpApp->variableController().variables(
122 Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
122 Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
123
123
124 if (variables.size() != 1) {
124 if (variables.size() != 1) {
125 return false;
125 return false;
126 }
126 }
127 auto variable = variables.front();
127 auto variable = variables.front();
128
128
129 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
129 if (auto graphWidget = dynamic_cast<const VisualizationGraphWidget *>(dragWidget)) {
130 return graphWidget->canDrop(*variable);
130 return graphWidget->canDrop(*variable);
131 }
131 }
132 }
132 }
133
133
134 return true;
134 return true;
135 };
135 };
136 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
136 ui->dragDropContainer->setAcceptDragWidgetFunction(acceptDragWidgetFun);
137
137
138 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
138 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredInContainer, this,
139 &VisualizationZoneWidget::dropMimeData);
139 &VisualizationZoneWidget::dropMimeData);
140 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
140 connect(ui->dragDropContainer, &VisualizationDragDropContainer::dropOccuredOnWidget, this,
141 &VisualizationZoneWidget::dropMimeDataOnGraph);
141 &VisualizationZoneWidget::dropMimeDataOnGraph);
142
142
143 // 'Close' options : widget is deleted when closed
143 // 'Close' options : widget is deleted when closed
144 setAttribute(Qt::WA_DeleteOnClose);
144 setAttribute(Qt::WA_DeleteOnClose);
145 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
145 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
146 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
146 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
147
147
148 // Synchronisation id
148 // Synchronisation id
149 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
149 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
150 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
150 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
151 }
151 }
152
152
153 VisualizationZoneWidget::~VisualizationZoneWidget()
153 VisualizationZoneWidget::~VisualizationZoneWidget()
154 {
154 {
155 delete ui;
155 delete ui;
156 }
156 }
157
157
158 void VisualizationZoneWidget::setZoneRange(const DateTimeRange &range)
158 void VisualizationZoneWidget::setZoneRange(const DateTimeRange &range)
159 {
159 {
160 if (auto graph = firstGraph()) {
160 if (auto graph = firstGraph()) {
161 graph->setGraphRange(range);
161 graph->setGraphRange(range);
162 }
162 }
163 else {
163 else {
164 qCWarning(LOG_VisualizationZoneWidget())
164 qCWarning(LOG_VisualizationZoneWidget())
165 << tr("setZoneRange:Cannot set the range of an empty zone.");
165 << tr("setZoneRange:Cannot set the range of an empty zone.");
166 }
166 }
167 }
167 }
168
168
169 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
169 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
170 {
170 {
171 // Synchronize new graph with others in the zone
171 // Synchronize new graph with others in the zone
172 impl->m_Synchronizer->addGraph(*graphWidget);
172 impl->m_Synchronizer->addGraph(*graphWidget);
173
173
174 ui->dragDropContainer->addDragWidget(graphWidget);
174 ui->dragDropContainer->addDragWidget(graphWidget);
175
175 }
176 }
176
177
177 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
178 void VisualizationZoneWidget::insertGraph(int index, VisualizationGraphWidget *graphWidget)
178 {
179 {
180 DEPRECATE(
181 auto layout = ui->dragDropContainer->layout();
182 for(int i=0;i<layout->count();i++)
183 {
184 auto graph = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(i)->widget());
185 connect(graphWidget, &VisualizationGraphWidget::zoom_sig, graph, &VisualizationGraphWidget::zoom);
186
187 connect(graphWidget, qOverload<double,Qt::Orientation,bool>(&VisualizationGraphWidget::move_sig),
188 graph, qOverload<double,Qt::Orientation,bool>(&VisualizationGraphWidget::move));
189 connect(graphWidget, qOverload<double,double,bool>(&VisualizationGraphWidget::move_sig),
190 graph, qOverload<double,double,bool>(&VisualizationGraphWidget::move));
191
192 connect(graph, &VisualizationGraphWidget::zoom_sig, graphWidget, &VisualizationGraphWidget::zoom);
193
194 connect(graph, qOverload<double,Qt::Orientation,bool>(&VisualizationGraphWidget::move_sig),
195 graphWidget, qOverload<double,Qt::Orientation,bool>(&VisualizationGraphWidget::move));
196 connect(graph, qOverload<double,double,bool>(&VisualizationGraphWidget::move_sig),
197 graphWidget, qOverload<double,double,bool>(&VisualizationGraphWidget::move));
198 }
199 if(auto graph = firstGraph())
200 {
201 graphWidget->setGraphRange(graph->graphRange(), true);
202 }
203 )
204
179 // Synchronize new graph with others in the zone
205 // Synchronize new graph with others in the zone
180 impl->m_Synchronizer->addGraph(*graphWidget);
206 impl->m_Synchronizer->addGraph(*graphWidget);
181
207
182 ui->dragDropContainer->insertDragWidget(index, graphWidget);
208 ui->dragDropContainer->insertDragWidget(index, graphWidget);
209
183 }
210 }
184
211
185 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
212 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
186 {
213 {
187 return createGraph(variable, -1);
214 return createGraph(variable, -1);
188 }
215 }
189
216
190 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
217 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable,
191 int index)
218 int index)
192 {
219 {
193 auto graphWidget
220 auto graphWidget
194 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
221 = new VisualizationGraphWidget{defaultGraphName(*ui->dragDropContainer->layout()), this};
195
222
196
223
197 // Set graph properties
224 // Set graph properties
198 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
225 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
199 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
226 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
200
227
201
228
202 // Lambda to synchronize zone widget
229 // Lambda to synchronize zone widget
203 auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange,
230 auto synchronizeZoneWidget = [this, graphWidget](const DateTimeRange &graphRange,
204 const DateTimeRange &oldGraphRange) {
231 const DateTimeRange &oldGraphRange) {
205
232
206 auto zoomType = DateTimeRangeHelper::getTransformationType(oldGraphRange, graphRange);
233 auto zoomType = DateTimeRangeHelper::getTransformationType(oldGraphRange, graphRange);
207 auto frameLayout = ui->dragDropContainer->layout();
234 auto frameLayout = ui->dragDropContainer->layout();
208 for (auto i = 0; i < frameLayout->count(); ++i) {
235 for (auto i = 0; i < frameLayout->count(); ++i) {
209 auto graphChild
236 auto graphChild
210 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
237 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
211 if (graphChild && (graphChild != graphWidget)) {
238 if (graphChild && (graphChild != graphWidget)) {
212
239
213 auto graphChildRange = graphChild->graphRange();
240 auto graphChildRange = graphChild->graphRange();
214 switch (zoomType) {
241 switch (zoomType) {
215 case TransformationType::ZoomIn: {
242 case TransformationType::ZoomIn: {
216 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
243 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
217 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
244 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
218 graphChildRange.m_TStart += deltaLeft;
245 graphChildRange.m_TStart += deltaLeft;
219 graphChildRange.m_TEnd -= deltaRight;
246 graphChildRange.m_TEnd -= deltaRight;
220 break;
247 break;
221 }
248 }
222
249
223 case TransformationType::ZoomOut: {
250 case TransformationType::ZoomOut: {
224 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
251 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
225 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
252 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
226 graphChildRange.m_TStart -= deltaLeft;
253 graphChildRange.m_TStart -= deltaLeft;
227 graphChildRange.m_TEnd += deltaRight;
254 graphChildRange.m_TEnd += deltaRight;
228 break;
255 break;
229 }
256 }
230 case TransformationType::PanRight: {
257 case TransformationType::PanRight: {
231 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
258 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
232 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
259 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
233 graphChildRange.m_TStart += deltaLeft;
260 graphChildRange.m_TStart += deltaLeft;
234 graphChildRange.m_TEnd += deltaRight;
261 graphChildRange.m_TEnd += deltaRight;
235 break;
262 break;
236 }
263 }
237 case TransformationType::PanLeft: {
264 case TransformationType::PanLeft: {
238 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
265 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
239 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
266 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
240 graphChildRange.m_TStart -= deltaLeft;
267 graphChildRange.m_TStart -= deltaLeft;
241 graphChildRange.m_TEnd -= deltaRight;
268 graphChildRange.m_TEnd -= deltaRight;
242 break;
269 break;
243 }
270 }
244 case TransformationType::Unknown: {
271 case TransformationType::Unknown: {
245 break;
272 break;
246 }
273 }
247 default:
274 default:
248 qCCritical(LOG_VisualizationZoneWidget())
275 qCCritical(LOG_VisualizationZoneWidget())
249 << tr("Impossible to synchronize: zoom type not take into account");
276 << tr("Impossible to synchronize: zoom type not take into account");
250 // No action
277 // No action
251 break;
278 break;
252 }
279 }
253 graphChild->setFlags(GraphFlag::DisableAll);
280 graphChild->setFlags(GraphFlag::DisableAll);
254 graphChild->setGraphRange(graphChildRange);
281 graphChild->setGraphRange(graphChildRange);
255 graphChild->setFlags(GraphFlag::EnableAll);
282 graphChild->setFlags(GraphFlag::EnableAll);
256 }
283 }
257 }
284 }
258 };
285 };
259
286
260 // connection for synchronization
287 // connection for synchronization
261 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
288 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
262 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
289 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
263 &VisualizationZoneWidget::onVariableAdded);
290 &VisualizationZoneWidget::onVariableAdded);
264 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
291 connect(graphWidget, &VisualizationGraphWidget::variableAboutToBeRemoved, this,
265 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
292 &VisualizationZoneWidget::onVariableAboutToBeRemoved);
266
293
267 auto range = DateTimeRange{};
294 auto range = DateTimeRange{};
268 if (auto firstGraph = this->firstGraph()) {
295 if (auto firstGraph = this->firstGraph()) {
269 // Case of a new graph in a existant zone
296 // Case of a new graph in a existant zone
270 range = firstGraph->graphRange();
297 range = firstGraph->graphRange();
271 }
298 }
272 else {
299 else {
273 // Case of a new graph as the first of the zone
300 // Case of a new graph as the first of the zone
274 range = variable->range();
301 range = variable->range();
275 }
302 }
276
303
277 this->insertGraph(index, graphWidget);
304 this->insertGraph(index, graphWidget);
278
305
279 graphWidget->addVariable(variable, range);
306 graphWidget->addVariable(variable, range);
280 graphWidget->setYRange(variable);
307 graphWidget->setYRange(variable);
281
308
282 return graphWidget;
309 return graphWidget;
283 }
310 }
284
311
285 VisualizationGraphWidget *
312 VisualizationGraphWidget *
286 VisualizationZoneWidget::createGraph(const std::vector<std::shared_ptr<Variable> > variables, int index)
313 VisualizationZoneWidget::createGraph(const std::vector<std::shared_ptr<Variable> > variables, int index)
287 {
314 {
288 if (variables.empty()) {
315 if (variables.empty()) {
289 return nullptr;
316 return nullptr;
290 }
317 }
291
318
292 auto graphWidget = createGraph(variables.front(), index);
319 auto graphWidget = createGraph(variables.front(), index);
293 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
320 for (auto variableIt = variables.cbegin() + 1; variableIt != variables.cend(); ++variableIt) {
294 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
321 graphWidget->addVariable(*variableIt, graphWidget->graphRange());
295 }
322 }
296
323
297 return graphWidget;
324 return graphWidget;
298 }
325 }
299
326
300 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
327 VisualizationGraphWidget *VisualizationZoneWidget::firstGraph() const
301 {
328 {
302 VisualizationGraphWidget *firstGraph = nullptr;
329 VisualizationGraphWidget *firstGraph = nullptr;
303 auto layout = ui->dragDropContainer->layout();
330 auto layout = ui->dragDropContainer->layout();
304 if (layout->count() > 0) {
331 if (layout->count() > 0) {
305 if (auto visualizationGraphWidget
332 if (auto visualizationGraphWidget
306 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
333 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
307 firstGraph = visualizationGraphWidget;
334 firstGraph = visualizationGraphWidget;
308 }
335 }
309 }
336 }
310
337
311 return firstGraph;
338 return firstGraph;
312 }
339 }
313
340
314 void VisualizationZoneWidget::closeAllGraphs()
341 void VisualizationZoneWidget::closeAllGraphs()
315 {
342 {
316 processGraphs(*ui->dragDropContainer->layout(),
343 processGraphs(*ui->dragDropContainer->layout(),
317 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
344 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
318 }
345 }
319
346
320 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
347 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
321 {
348 {
322 if (visitor) {
349 if (visitor) {
323 visitor->visitEnter(this);
350 visitor->visitEnter(this);
324
351
325 // Apply visitor to graph children: widgets different from graphs are not visited (no
352 // Apply visitor to graph children: widgets different from graphs are not visited (no
326 // action)
353 // action)
327 processGraphs(
354 processGraphs(
328 *ui->dragDropContainer->layout(),
355 *ui->dragDropContainer->layout(),
329 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
356 [visitor](VisualizationGraphWidget &graphWidget) { graphWidget.accept(visitor); });
330
357
331 visitor->visitLeave(this);
358 visitor->visitLeave(this);
332 }
359 }
333 else {
360 else {
334 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
361 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
335 }
362 }
336 }
363 }
337
364
338 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
365 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
339 {
366 {
340 // A tab can always accomodate a variable
367 // A tab can always accomodate a variable
341 Q_UNUSED(variable);
368 Q_UNUSED(variable);
342 return true;
369 return true;
343 }
370 }
344
371
345 bool VisualizationZoneWidget::contains(const Variable &variable) const
372 bool VisualizationZoneWidget::contains(const Variable &variable) const
346 {
373 {
347 Q_UNUSED(variable);
374 Q_UNUSED(variable);
348 return false;
375 return false;
349 }
376 }
350
377
351 QString VisualizationZoneWidget::name() const
378 QString VisualizationZoneWidget::name() const
352 {
379 {
353 return ui->zoneNameLabel->text();
380 return ui->zoneNameLabel->text();
354 }
381 }
355
382
356 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
383 QMimeData *VisualizationZoneWidget::mimeData(const QPoint &position) const
357 {
384 {
358 Q_UNUSED(position);
385 Q_UNUSED(position);
359
386
360 auto mimeData = new QMimeData;
387 auto mimeData = new QMimeData;
361 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
388 mimeData->setData(MIME_TYPE_ZONE, QByteArray{});
362
389
363 if (auto firstGraph = this->firstGraph()) {
390 if (auto firstGraph = this->firstGraph()) {
364 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
391 auto timeRangeData = TimeController::mimeDataForTimeRange(firstGraph->graphRange());
365 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
392 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
366 }
393 }
367
394
368 return mimeData;
395 return mimeData;
369 }
396 }
370
397
371 bool VisualizationZoneWidget::isDragAllowed() const
398 bool VisualizationZoneWidget::isDragAllowed() const
372 {
399 {
373 return true;
400 return true;
374 }
401 }
375
402
376 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
403 void VisualizationZoneWidget::notifyMouseMoveInGraph(const QPointF &graphPosition,
377 const QPointF &plotPosition,
404 const QPointF &plotPosition,
378 VisualizationGraphWidget *graphWidget)
405 VisualizationGraphWidget *graphWidget)
379 {
406 {
380 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
407 processGraphs(*ui->dragDropContainer->layout(), [&graphPosition, &plotPosition, &graphWidget](
381 VisualizationGraphWidget &processedGraph) {
408 VisualizationGraphWidget &processedGraph) {
382
409
383 switch (sqpApp->plotsCursorMode()) {
410 switch (sqpApp->plotsCursorMode()) {
384 case SqpApplication::PlotsCursorMode::Vertical:
411 case SqpApplication::PlotsCursorMode::Vertical:
385 processedGraph.removeHorizontalCursor();
412 processedGraph.removeHorizontalCursor();
386 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
413 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
387 break;
414 break;
388 case SqpApplication::PlotsCursorMode::Temporal:
415 case SqpApplication::PlotsCursorMode::Temporal:
389 processedGraph.addVerticalCursor(plotPosition.x());
416 processedGraph.addVerticalCursor(plotPosition.x());
390 processedGraph.removeHorizontalCursor();
417 processedGraph.removeHorizontalCursor();
391 break;
418 break;
392 case SqpApplication::PlotsCursorMode::Horizontal:
419 case SqpApplication::PlotsCursorMode::Horizontal:
393 processedGraph.removeVerticalCursor();
420 processedGraph.removeVerticalCursor();
394 if (&processedGraph == graphWidget) {
421 if (&processedGraph == graphWidget) {
395 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
422 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
396 }
423 }
397 else {
424 else {
398 processedGraph.removeHorizontalCursor();
425 processedGraph.removeHorizontalCursor();
399 }
426 }
400 break;
427 break;
401 case SqpApplication::PlotsCursorMode::Cross:
428 case SqpApplication::PlotsCursorMode::Cross:
402 if (&processedGraph == graphWidget) {
429 if (&processedGraph == graphWidget) {
403 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
430 processedGraph.addVerticalCursorAtViewportPosition(graphPosition.x());
404 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
431 processedGraph.addHorizontalCursorAtViewportPosition(graphPosition.y());
405 }
432 }
406 else {
433 else {
407 processedGraph.removeHorizontalCursor();
434 processedGraph.removeHorizontalCursor();
408 processedGraph.removeVerticalCursor();
435 processedGraph.removeVerticalCursor();
409 }
436 }
410 break;
437 break;
411 case SqpApplication::PlotsCursorMode::NoCursor:
438 case SqpApplication::PlotsCursorMode::NoCursor:
412 processedGraph.removeHorizontalCursor();
439 processedGraph.removeHorizontalCursor();
413 processedGraph.removeVerticalCursor();
440 processedGraph.removeVerticalCursor();
414 break;
441 break;
415 }
442 }
416
443
417
444
418 });
445 });
419 }
446 }
420
447
421 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
448 void VisualizationZoneWidget::notifyMouseLeaveGraph(VisualizationGraphWidget *graphWidget)
422 {
449 {
423 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
450 processGraphs(*ui->dragDropContainer->layout(), [](VisualizationGraphWidget &processedGraph) {
424 processedGraph.removeHorizontalCursor();
451 processedGraph.removeHorizontalCursor();
425 processedGraph.removeVerticalCursor();
452 processedGraph.removeVerticalCursor();
426 });
453 });
427 }
454 }
428
455
429 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
456 void VisualizationZoneWidget::closeEvent(QCloseEvent *event)
430 {
457 {
431 // Closes graphs in the zone
458 // Closes graphs in the zone
432 processGraphs(*ui->dragDropContainer->layout(),
459 processGraphs(*ui->dragDropContainer->layout(),
433 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
460 [](VisualizationGraphWidget &graphWidget) { graphWidget.close(); });
434
461
435 // Delete synchronization group from variable controller
462 // Delete synchronization group from variable controller
436 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
463 QMetaObject::invokeMethod(&sqpApp->variableController(), "onRemoveSynchronizationGroupId",
437 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
464 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
438
465
439 QWidget::closeEvent(event);
466 QWidget::closeEvent(event);
440 }
467 }
441
468
442 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
469 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
443 {
470 {
444 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
471 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
445 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
472 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
446 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
473 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
447 }
474 }
448
475
449 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
476 void VisualizationZoneWidget::onVariableAboutToBeRemoved(std::shared_ptr<Variable> variable)
450 {
477 {
451 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
478 QMetaObject::invokeMethod(&sqpApp->variableController(), "desynchronize", Qt::QueuedConnection,
452 Q_ARG(std::shared_ptr<Variable>, variable),
479 Q_ARG(std::shared_ptr<Variable>, variable),
453 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
480 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
454 }
481 }
455
482
456 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
483 void VisualizationZoneWidget::dropMimeData(int index, const QMimeData *mimeData)
457 {
484 {
458 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
485 if (mimeData->hasFormat(MIME_TYPE_GRAPH)) {
459 impl->dropGraph(index, this);
486 impl->dropGraph(index, this);
460 }
487 }
461 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
488 else if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
462 auto variables = sqpApp->variableController().variables(
489 auto variables = sqpApp->variableController().variables(
463 Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
490 Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
464 impl->dropVariables(variables, index, this);
491 impl->dropVariables(variables, index, this);
465 }
492 }
466 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
493 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
467 auto products = sqpApp->dataSourceController().productsDataForMimeData(
494 auto products = sqpApp->dataSourceController().productsDataForMimeData(
468 mimeData->data(MIME_TYPE_PRODUCT_LIST));
495 mimeData->data(MIME_TYPE_PRODUCT_LIST));
469 impl->dropProducts(products, index, this);
496 impl->dropProducts(products, index, this);
470 }
497 }
471 else {
498 else {
472 qCWarning(LOG_VisualizationZoneWidget())
499 qCWarning(LOG_VisualizationZoneWidget())
473 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
500 << tr("VisualizationZoneWidget::dropMimeData, unknown MIME data received.");
474 }
501 }
475 }
502 }
476
503
477 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
504 void VisualizationZoneWidget::dropMimeDataOnGraph(VisualizationDragWidget *dragWidget,
478 const QMimeData *mimeData)
505 const QMimeData *mimeData)
479 {
506 {
480 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
507 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(dragWidget);
481 if (!graphWidget) {
508 if (!graphWidget) {
482 qCWarning(LOG_VisualizationZoneWidget())
509 qCWarning(LOG_VisualizationZoneWidget())
483 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
510 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, dropping in an unknown widget, "
484 "drop aborted");
511 "drop aborted");
485 Q_ASSERT(false);
512 Q_ASSERT(false);
486 return;
513 return;
487 }
514 }
488
515
489 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
516 if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) {
490 auto variables = sqpApp->variableController().variables(
517 auto variables = sqpApp->variableController().variables(
491 Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
518 Variable::variablesIDs(mimeData->data(MIME_TYPE_VARIABLE_LIST)));
492 for (const auto &var : variables) {
519 for (const auto &var : variables) {
493 graphWidget->addVariable(var, graphWidget->graphRange());
520 graphWidget->addVariable(var, graphWidget->graphRange());
494 }
521 }
495 }
522 }
496 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
523 else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) {
497 auto products = sqpApp->dataSourceController().productsDataForMimeData(
524 auto products = sqpApp->dataSourceController().productsDataForMimeData(
498 mimeData->data(MIME_TYPE_PRODUCT_LIST));
525 mimeData->data(MIME_TYPE_PRODUCT_LIST));
499
526
500 auto context = new QObject{this};
527 auto context = new QObject{this};
501 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
528 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
502 [this, graphWidget, context](auto variable) {
529 [this, graphWidget, context](auto variable) {
503 graphWidget->addVariable(variable, graphWidget->graphRange());
530 graphWidget->addVariable(variable, graphWidget->graphRange());
504 delete context; // removes the connection
531 delete context; // removes the connection
505 },
532 },
506 Qt::QueuedConnection);
533 Qt::QueuedConnection);
507
534
508 auto productData = products.first().toHash();
535 auto productData = products.first().toHash();
509 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
536 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
510 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
537 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
511 }
538 }
512 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
539 else if (mimeData->hasFormat(MIME_TYPE_TIME_RANGE)) {
513 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
540 auto range = TimeController::timeRangeForMimeData(mimeData->data(MIME_TYPE_TIME_RANGE));
514 graphWidget->setGraphRange(range);
541 graphWidget->setGraphRange(range);
515 }
542 }
516 else {
543 else {
517 qCWarning(LOG_VisualizationZoneWidget())
544 qCWarning(LOG_VisualizationZoneWidget())
518 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
545 << tr("VisualizationZoneWidget::dropMimeDataOnGraph, unknown MIME data received.");
519 }
546 }
520 }
547 }
521
548
522 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
549 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropGraph(
523 int index, VisualizationZoneWidget *zoneWidget)
550 int index, VisualizationZoneWidget *zoneWidget)
524 {
551 {
525 auto &helper = sqpApp->dragDropGuiController();
552 auto &helper = sqpApp->dragDropGuiController();
526
553
527 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
554 auto graphWidget = qobject_cast<VisualizationGraphWidget *>(helper.getCurrentDragWidget());
528 if (!graphWidget) {
555 if (!graphWidget) {
529 qCWarning(LOG_VisualizationZoneWidget())
556 qCWarning(LOG_VisualizationZoneWidget())
530 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
557 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the dropped graph is not "
531 "found or invalid.");
558 "found or invalid.");
532 Q_ASSERT(false);
559 Q_ASSERT(false);
533 return;
560 return;
534 }
561 }
535
562
536 auto parentDragDropContainer
563 auto parentDragDropContainer
537 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
564 = qobject_cast<VisualizationDragDropContainer *>(graphWidget->parentWidget());
538 if (!parentDragDropContainer) {
565 if (!parentDragDropContainer) {
539 qCWarning(LOG_VisualizationZoneWidget())
566 qCWarning(LOG_VisualizationZoneWidget())
540 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
567 << tr("VisualizationZoneWidget::dropGraph, drop aborted, the parent container of "
541 "the dropped graph is not found.");
568 "the dropped graph is not found.");
542 Q_ASSERT(false);
569 Q_ASSERT(false);
543 return;
570 return;
544 }
571 }
545
572
546 const auto &variables = graphWidget->variables();
573 const auto &variables = graphWidget->variables();
547
574
548 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.empty()) {
575 if (parentDragDropContainer != zoneWidget->ui->dragDropContainer && !variables.empty()) {
549 // The drop didn't occur in the same zone
576 // The drop didn't occur in the same zone
550
577
551 // Abort the requests for the variables (if any)
578 // Abort the requests for the variables (if any)
552 // Commented, because it's not sure if it's needed or not
579 // Commented, because it's not sure if it's needed or not
553 // for (const auto& var : variables)
580 // for (const auto& var : variables)
554 //{
581 //{
555 // sqpApp->variableController().onAbortProgressRequested(var);
582 // sqpApp->variableController().onAbortProgressRequested(var);
556 //}
583 //}
557
584
558 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
585 auto previousParentZoneWidget = graphWidget->parentZoneWidget();
559 auto nbGraph = parentDragDropContainer->countDragWidget();
586 auto nbGraph = parentDragDropContainer->countDragWidget();
560 if (nbGraph == 1) {
587 if (nbGraph == 1) {
561 // This is the only graph in the previous zone, close the zone
588 // This is the only graph in the previous zone, close the zone
562 helper.delayedCloseWidget(previousParentZoneWidget);
589 helper.delayedCloseWidget(previousParentZoneWidget);
563 }
590 }
564 else {
591 else {
565 // Close the graph
592 // Close the graph
566 helper.delayedCloseWidget(graphWidget);
593 helper.delayedCloseWidget(graphWidget);
567 }
594 }
568
595
569 // Creates the new graph in the zone
596 // Creates the new graph in the zone
570 auto newGraphWidget = zoneWidget->createGraph(variables, index);
597 auto newGraphWidget = zoneWidget->createGraph(variables, index);
571 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
598 newGraphWidget->addSelectionZones(graphWidget->selectionZoneRanges());
572 }
599 }
573 else {
600 else {
574 // The drop occurred in the same zone or the graph is empty
601 // The drop occurred in the same zone or the graph is empty
575 // Simple move of the graph, no variable operation associated
602 // Simple move of the graph, no variable operation associated
576 parentDragDropContainer->layout()->removeWidget(graphWidget);
603 parentDragDropContainer->layout()->removeWidget(graphWidget);
577
604
578 if (variables.empty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
605 if (variables.empty() && parentDragDropContainer != zoneWidget->ui->dragDropContainer) {
579 // The graph is empty and dropped in a different zone.
606 // The graph is empty and dropped in a different zone.
580 // Take the range of the first graph in the zone (if existing).
607 // Take the range of the first graph in the zone (if existing).
581 auto layout = zoneWidget->ui->dragDropContainer->layout();
608 auto layout = zoneWidget->ui->dragDropContainer->layout();
582 if (layout->count() > 0) {
609 if (layout->count() > 0) {
583 if (auto visualizationGraphWidget
610 if (auto visualizationGraphWidget
584 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
611 = qobject_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
585 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
612 graphWidget->setGraphRange(visualizationGraphWidget->graphRange());
586 }
613 }
587 }
614 }
588 }
615 }
589
616
590 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
617 zoneWidget->ui->dragDropContainer->insertDragWidget(index, graphWidget);
591 }
618 }
592 }
619 }
593
620
594 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
621 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropVariables(
595 const std::vector<std::shared_ptr<Variable> > &variables, int index,
622 const std::vector<std::shared_ptr<Variable> > &variables, int index,
596 VisualizationZoneWidget *zoneWidget)
623 VisualizationZoneWidget *zoneWidget)
597 {
624 {
598 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
625 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
599 // compatible variable here
626 // compatible variable here
600 if (variables.size() > 1) {
627 if (variables.size() > 1) {
601 return;
628 return;
602 }
629 }
603 zoneWidget->createGraph(variables, index);
630 zoneWidget->createGraph(variables, index);
604 }
631 }
605
632
606 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
633 void VisualizationZoneWidget::VisualizationZoneWidgetPrivate::dropProducts(
607 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
634 const QVariantList &productsData, int index, VisualizationZoneWidget *zoneWidget)
608 {
635 {
609 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
636 // Note: the AcceptMimeDataFunction (set on the drop container) ensure there is a single and
610 // compatible variable here
637 // compatible variable here
611 if (productsData.count() != 1) {
638 if (productsData.count() != 1) {
612 qCWarning(LOG_VisualizationZoneWidget())
639 qCWarning(LOG_VisualizationZoneWidget())
613 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
640 << tr("VisualizationTabWidget::dropProducts, dropping multiple products, operation "
614 "aborted.");
641 "aborted.");
615 return;
642 return;
616 }
643 }
617
644
618 auto context = new QObject{zoneWidget};
645 auto context = new QObject{zoneWidget};
619 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
646 connect(&sqpApp->variableController(), &VariableController2::variableAdded, context,
620 [this, index, zoneWidget, context](auto variable) {
647 [this, index, zoneWidget, context](auto variable) {
621 zoneWidget->createGraph(variable, index);
648 zoneWidget->createGraph(variable, index);
622 delete context; // removes the connection
649 delete context; // removes the connection
623 },
650 },
624 Qt::QueuedConnection);
651 Qt::QueuedConnection);
625
652
626 auto productData = productsData.first().toHash();
653 auto productData = productsData.first().toHash();
627 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
654 QMetaObject::invokeMethod(&sqpApp->dataSourceController(), "requestVariable",
628 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
655 Qt::QueuedConnection, Q_ARG(QVariantHash, productData));
629 }
656 }
@@ -1,8 +1,5
1 <RCC>
1 <RCC>
2 <qresource prefix="/">
2 <qresource prefix="/">
3 <file>samples/AmdaSample.json</file>
4 <file>samples/AmdaSampleV2.json</file>
5 <file>samples/AmdaSampleV3.json</file>
6 <file>samples/amda_tree.json</file>
3 <file>samples/amda_tree.json</file>
7 </qresource>
4 </qresource>
8 </RCC>
5 </RCC>
General Comments 0
You need to be logged in to leave comments. Login now