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