##// END OF EJS Templates
Add action to remove the selected zone with the "del" buttons
trabillard -
r1117:eff9e479c5d5
parent child
Show More
@@ -1,58 +1,63
1 #ifndef SCIQLOP_SELECTIONZONEACTION_H
1 #ifndef SCIQLOP_SELECTIONZONEACTION_H
2 #define SCIQLOP_SELECTIONZONEACTION_H
2 #define SCIQLOP_SELECTIONZONEACTION_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5
5
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <QObject>
7 #include <QObject>
8
8
9 #include <functional>
9 #include <functional>
10
10
11 class VisualizationSelectionZoneItem;
11 class VisualizationSelectionZoneItem;
12
12
13 Q_DECLARE_LOGGING_CATEGORY(LOG_SelectionZoneAction)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_SelectionZoneAction)
14
14
15 /**
15 /**
16 * @brief The SelectionZoneAction class represents an action on a selection zone in the
16 * @brief The SelectionZoneAction class represents an action on a selection zone in the
17 * visualization.
17 * visualization.
18 *
18 *
19 * The action is a function that will be executed when the slot execute() is called.
19 * The action is a function that will be executed when the slot execute() is called.
20 */
20 */
21 class SelectionZoneAction : public QObject {
21 class SelectionZoneAction : public QObject {
22
22
23 Q_OBJECT
23 Q_OBJECT
24
24
25 public:
25 public:
26 /// Signature of the function associated to the action
26 /// Signature of the function associated to the action
27 using ExecuteFunction
27 using ExecuteFunction
28 = std::function<void(const QVector<VisualizationSelectionZoneItem *> &item)>;
28 = std::function<void(const QVector<VisualizationSelectionZoneItem *> &item)>;
29
29
30 using EnableFunction
30 using EnableFunction
31 = std::function<bool(const QVector<VisualizationSelectionZoneItem *> &item)>;
31 = std::function<bool(const QVector<VisualizationSelectionZoneItem *> &item)>;
32
32
33 /**
33 /**
34 * @param name the name of the action, displayed to the user
34 * @param name the name of the action, displayed to the user
35 * @param fun the function that will be called when the action is executed
35 * @param fun the function that will be called when the action is executed
36 * @sa execute()
36 * @sa execute()
37 */
37 */
38 explicit SelectionZoneAction(const QString &name, ExecuteFunction fun);
38 explicit SelectionZoneAction(const QString &name, ExecuteFunction fun);
39
39
40 /// Sets the function which determine if the action should be enabled or disabled
40 /// Sets the function which determine if the action should be enabled or disabled
41 void setEnableFunction(EnableFunction fun);
41 void setEnableFunction(EnableFunction fun);
42
42
43 /// Sets the shortcut displayed by the action.
44 /// Note: The shortcut is only displayed and not active because it is not permanently stored
45 void setDisplayedShortcut(const QKeySequence &shortcut);
46 QKeySequence displayedShortcut() const;
47
43 /// The name of the action
48 /// The name of the action
44 QString name() const noexcept;
49 QString name() const noexcept;
45
50
46 public slots:
51 public slots:
47 /// Executes the action
52 /// Executes the action
48 void execute(const QVector<VisualizationSelectionZoneItem *> &item);
53 void execute(const QVector<VisualizationSelectionZoneItem *> &item);
49
54
50 /// Returns true if the action is enabled
55 /// Returns true if the action is enabled
51 bool isEnabled(const QVector<VisualizationSelectionZoneItem *> &item);
56 bool isEnabled(const QVector<VisualizationSelectionZoneItem *> &item);
52
57
53 private:
58 private:
54 class SelectionZoneActionPrivate;
59 class SelectionZoneActionPrivate;
55 spimpl::unique_impl_ptr<SelectionZoneActionPrivate> impl;
60 spimpl::unique_impl_ptr<SelectionZoneActionPrivate> impl;
56 };
61 };
57
62
58 #endif // SCIQLOP_SELECTIONZONEACTION_H
63 #endif // SCIQLOP_SELECTIONZONEACTION_H
@@ -1,41 +1,52
1 #include <Actions/SelectionZoneAction.h>
1 #include <Actions/SelectionZoneAction.h>
2 #include <Visualization/VisualizationSelectionZoneItem.h>
2 #include <Visualization/VisualizationSelectionZoneItem.h>
3
3
4 Q_LOGGING_CATEGORY(LOG_SelectionZoneAction, "SelectionZoneAction")
4 Q_LOGGING_CATEGORY(LOG_SelectionZoneAction, "SelectionZoneAction")
5
5
6 struct SelectionZoneAction::SelectionZoneActionPrivate {
6 struct SelectionZoneAction::SelectionZoneActionPrivate {
7 explicit SelectionZoneActionPrivate(const QString &name,
7 explicit SelectionZoneActionPrivate(const QString &name,
8 SelectionZoneAction::ExecuteFunction fun)
8 SelectionZoneAction::ExecuteFunction fun)
9 : m_Name{name}, m_Fun{std::move(fun)}
9 : m_Name{name}, m_Fun{std::move(fun)}
10 {
10 {
11 }
11 }
12
12
13 QString m_Name;
13 QString m_Name;
14 QKeySequence m_DisplayedShortcut;
14 SelectionZoneAction::ExecuteFunction m_Fun;
15 SelectionZoneAction::ExecuteFunction m_Fun;
15 SelectionZoneAction::EnableFunction m_EnableFun = [](auto zones) { return true; };
16 SelectionZoneAction::EnableFunction m_EnableFun = [](auto zones) { return true; };
16 };
17 };
17
18
18 SelectionZoneAction::SelectionZoneAction(const QString &name, ExecuteFunction fun)
19 SelectionZoneAction::SelectionZoneAction(const QString &name, ExecuteFunction fun)
19 : impl{spimpl::make_unique_impl<SelectionZoneActionPrivate>(name, std::move(fun))}
20 : impl{spimpl::make_unique_impl<SelectionZoneActionPrivate>(name, std::move(fun))}
20 {
21 {
21 }
22 }
22
23
23 void SelectionZoneAction::setEnableFunction(EnableFunction fun)
24 void SelectionZoneAction::setEnableFunction(EnableFunction fun)
24 {
25 {
25 impl->m_EnableFun = std::move(fun);
26 impl->m_EnableFun = std::move(fun);
26 }
27 }
27
28
29 void SelectionZoneAction::setDisplayedShortcut(const QKeySequence &shortcut)
30 {
31 impl->m_DisplayedShortcut = shortcut;
32 }
33
34 QKeySequence SelectionZoneAction::displayedShortcut() const
35 {
36 return impl->m_DisplayedShortcut;
37 }
38
28 QString SelectionZoneAction::name() const noexcept
39 QString SelectionZoneAction::name() const noexcept
29 {
40 {
30 return impl->m_Name;
41 return impl->m_Name;
31 }
42 }
32
43
33 void SelectionZoneAction::execute(const QVector<VisualizationSelectionZoneItem *> &item)
44 void SelectionZoneAction::execute(const QVector<VisualizationSelectionZoneItem *> &item)
34 {
45 {
35 impl->m_Fun(item);
46 impl->m_Fun(item);
36 }
47 }
37
48
38 bool SelectionZoneAction::isEnabled(const QVector<VisualizationSelectionZoneItem *> &item)
49 bool SelectionZoneAction::isEnabled(const QVector<VisualizationSelectionZoneItem *> &item)
39 {
50 {
40 return impl->m_EnableFun(item);
51 return impl->m_EnableFun(item);
41 }
52 }
@@ -1,107 +1,109
1 #include "Visualization/VisualizationActionManager.h"
1 #include "Visualization/VisualizationActionManager.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationSelectionZoneItem.h"
3 #include "Visualization/VisualizationSelectionZoneItem.h"
4
4
5 #include <Actions/ActionsGuiController.h>
5 #include <Actions/ActionsGuiController.h>
6 #include <SqpApplication.h>
6 #include <SqpApplication.h>
7
7
8 VisualizationActionManager::VisualizationActionManager() {}
8 VisualizationActionManager::VisualizationActionManager() {}
9
9
10 void VisualizationActionManager::installSelectionZoneActions()
10 void VisualizationActionManager::installSelectionZoneActions()
11 {
11 {
12 auto &actionController = sqpApp->actionsGuiController();
12 auto &actionController = sqpApp->actionsGuiController();
13
13
14 actionController.addSectionZoneAction("Remove Selected Zone(s)", [](auto zones) {
14 auto removeZonesAction
15 for (auto selectionZone : zones) {
15 = actionController.addSectionZoneAction("Remove Selected Zone(s)", [](auto zones) {
16 if (auto graph = selectionZone->parentGraphWidget()) {
16 for (auto selectionZone : zones) {
17 graph->removeSelectionZone(selectionZone);
17 if (auto graph = selectionZone->parentGraphWidget()) {
18 }
18 graph->removeSelectionZone(selectionZone);
19 }
19 }
20 });
20 }
21 });
22 removeZonesAction->setDisplayedShortcut(QKeySequence::Delete);
21
23
22 auto alignEnableFuntion = [](auto items) { return items.count() > 1; };
24 auto alignEnableFuntion = [](auto items) { return items.count() > 1; };
23
25
24 // Vertical alignment actions
26 // Vertical alignment actions
25 auto alignLeftAction
27 auto alignLeftAction
26 = actionController.addSectionZoneAction("Align Vertically / Left", [](auto zones) {
28 = actionController.addSectionZoneAction("Align Vertically / Left", [](auto zones) {
27 Q_ASSERT(zones.count() > 1);
29 Q_ASSERT(zones.count() > 1);
28 auto ref = zones.takeFirst();
30 auto ref = zones.takeFirst();
29 ref->alignZonesVerticallyOnLeft(zones, false);
31 ref->alignZonesVerticallyOnLeft(zones, false);
30 });
32 });
31 alignLeftAction->setEnableFunction(alignEnableFuntion);
33 alignLeftAction->setEnableFunction(alignEnableFuntion);
32
34
33 auto alignLeftBorderAction
35 auto alignLeftBorderAction
34 = actionController.addSectionZoneAction("Align Vertically / Left Borders", [](auto zones) {
36 = actionController.addSectionZoneAction("Align Vertically / Left Borders", [](auto zones) {
35 Q_ASSERT(zones.count() > 1);
37 Q_ASSERT(zones.count() > 1);
36 auto ref = zones.takeFirst();
38 auto ref = zones.takeFirst();
37 ref->alignZonesVerticallyOnLeft(zones, true);
39 ref->alignZonesVerticallyOnLeft(zones, true);
38 });
40 });
39 alignLeftBorderAction->setEnableFunction(alignEnableFuntion);
41 alignLeftBorderAction->setEnableFunction(alignEnableFuntion);
40
42
41 auto alignRightAction
43 auto alignRightAction
42 = actionController.addSectionZoneAction("Align Vertically / Right", [](auto zones) {
44 = actionController.addSectionZoneAction("Align Vertically / Right", [](auto zones) {
43 Q_ASSERT(zones.count() > 1);
45 Q_ASSERT(zones.count() > 1);
44 auto ref = zones.takeFirst();
46 auto ref = zones.takeFirst();
45 ref->alignZonesVerticallyOnRight(zones, false);
47 ref->alignZonesVerticallyOnRight(zones, false);
46 });
48 });
47 alignRightAction->setEnableFunction(alignEnableFuntion);
49 alignRightAction->setEnableFunction(alignEnableFuntion);
48
50
49 auto alignRightBorderAction
51 auto alignRightBorderAction
50 = actionController.addSectionZoneAction("Align Vertically / Right Borders", [](auto zones) {
52 = actionController.addSectionZoneAction("Align Vertically / Right Borders", [](auto zones) {
51 Q_ASSERT(zones.count() > 1);
53 Q_ASSERT(zones.count() > 1);
52 auto ref = zones.takeFirst();
54 auto ref = zones.takeFirst();
53 ref->alignZonesVerticallyOnRight(zones, true);
55 ref->alignZonesVerticallyOnRight(zones, true);
54 });
56 });
55 alignRightBorderAction->setEnableFunction(alignEnableFuntion);
57 alignRightBorderAction->setEnableFunction(alignEnableFuntion);
56
58
57 auto alignLeftAndRightAction = actionController.addSectionZoneAction(
59 auto alignLeftAndRightAction = actionController.addSectionZoneAction(
58 "Align Vertically / Left and Right", [](auto zones) {
60 "Align Vertically / Left and Right", [](auto zones) {
59 Q_ASSERT(zones.count() > 1);
61 Q_ASSERT(zones.count() > 1);
60 auto ref = zones.takeFirst();
62 auto ref = zones.takeFirst();
61 ref->alignZonesVerticallyOnLeft(zones, false);
63 ref->alignZonesVerticallyOnLeft(zones, false);
62 ref->alignZonesVerticallyOnRight(zones, true);
64 ref->alignZonesVerticallyOnRight(zones, true);
63 });
65 });
64 alignLeftAndRightAction->setEnableFunction(alignEnableFuntion);
66 alignLeftAndRightAction->setEnableFunction(alignEnableFuntion);
65
67
66 // Temporal alignment actions
68 // Temporal alignment actions
67 auto alignLeftTemporallyAction
69 auto alignLeftTemporallyAction
68 = actionController.addSectionZoneAction("Align Temporally / Left", [](auto zones) {
70 = actionController.addSectionZoneAction("Align Temporally / Left", [](auto zones) {
69 Q_ASSERT(zones.count() > 1);
71 Q_ASSERT(zones.count() > 1);
70 auto ref = zones.takeFirst();
72 auto ref = zones.takeFirst();
71 ref->alignZonesTemporallyOnLeft(zones, false);
73 ref->alignZonesTemporallyOnLeft(zones, false);
72 });
74 });
73 alignLeftTemporallyAction->setEnableFunction(alignEnableFuntion);
75 alignLeftTemporallyAction->setEnableFunction(alignEnableFuntion);
74
76
75 auto alignLeftBorderTemporallyAction
77 auto alignLeftBorderTemporallyAction
76 = actionController.addSectionZoneAction("Align Temporally / Left Borders", [](auto zones) {
78 = actionController.addSectionZoneAction("Align Temporally / Left Borders", [](auto zones) {
77 Q_ASSERT(zones.count() > 1);
79 Q_ASSERT(zones.count() > 1);
78 auto ref = zones.takeFirst();
80 auto ref = zones.takeFirst();
79 ref->alignZonesTemporallyOnLeft(zones, true);
81 ref->alignZonesTemporallyOnLeft(zones, true);
80 });
82 });
81 alignLeftBorderTemporallyAction->setEnableFunction(alignEnableFuntion);
83 alignLeftBorderTemporallyAction->setEnableFunction(alignEnableFuntion);
82
84
83 auto alignRightTemporallyAction
85 auto alignRightTemporallyAction
84 = actionController.addSectionZoneAction("Align Temporally / Right", [](auto zones) {
86 = actionController.addSectionZoneAction("Align Temporally / Right", [](auto zones) {
85 Q_ASSERT(zones.count() > 1);
87 Q_ASSERT(zones.count() > 1);
86 auto ref = zones.takeFirst();
88 auto ref = zones.takeFirst();
87 ref->alignZonesTemporallyOnRight(zones, false);
89 ref->alignZonesTemporallyOnRight(zones, false);
88 });
90 });
89 alignRightTemporallyAction->setEnableFunction(alignEnableFuntion);
91 alignRightTemporallyAction->setEnableFunction(alignEnableFuntion);
90
92
91 auto alignRightBorderTemporallyAction
93 auto alignRightBorderTemporallyAction
92 = actionController.addSectionZoneAction("Align Temporally / Right Borders", [](auto zones) {
94 = actionController.addSectionZoneAction("Align Temporally / Right Borders", [](auto zones) {
93 Q_ASSERT(zones.count() > 1);
95 Q_ASSERT(zones.count() > 1);
94 auto ref = zones.takeFirst();
96 auto ref = zones.takeFirst();
95 ref->alignZonesTemporallyOnRight(zones, true);
97 ref->alignZonesTemporallyOnRight(zones, true);
96 });
98 });
97 alignRightBorderTemporallyAction->setEnableFunction(alignEnableFuntion);
99 alignRightBorderTemporallyAction->setEnableFunction(alignEnableFuntion);
98
100
99 auto alignLeftAndRightTemporallyAction = actionController.addSectionZoneAction(
101 auto alignLeftAndRightTemporallyAction = actionController.addSectionZoneAction(
100 "Align Temporally / Left and Right", [](auto zones) {
102 "Align Temporally / Left and Right", [](auto zones) {
101 Q_ASSERT(zones.count() > 1);
103 Q_ASSERT(zones.count() > 1);
102 auto ref = zones.takeFirst();
104 auto ref = zones.takeFirst();
103 ref->alignZonesTemporallyOnLeft(zones, false);
105 ref->alignZonesTemporallyOnLeft(zones, false);
104 ref->alignZonesTemporallyOnRight(zones, true);
106 ref->alignZonesTemporallyOnRight(zones, true);
105 });
107 });
106 alignLeftAndRightTemporallyAction->setEnableFunction(alignEnableFuntion);
108 alignLeftAndRightTemporallyAction->setEnableFunction(alignEnableFuntion);
107 }
109 }
@@ -1,904 +1,911
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationWidget.h"
9 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
12
12
13 #include <Actions/ActionsGuiController.h>
13 #include <Actions/ActionsGuiController.h>
14 #include <Common/MimeTypesDef.h>
14 #include <Common/MimeTypesDef.h>
15 #include <Data/ArrayData.h>
15 #include <Data/ArrayData.h>
16 #include <Data/IDataSeries.h>
16 #include <Data/IDataSeries.h>
17 #include <Data/SpectrogramSeries.h>
17 #include <Data/SpectrogramSeries.h>
18 #include <DragAndDrop/DragDropGuiController.h>
18 #include <DragAndDrop/DragDropGuiController.h>
19 #include <Settings/SqpSettingsDefs.h>
19 #include <Settings/SqpSettingsDefs.h>
20 #include <SqpApplication.h>
20 #include <SqpApplication.h>
21 #include <Time/TimeController.h>
21 #include <Time/TimeController.h>
22 #include <Variable/Variable.h>
22 #include <Variable/Variable.h>
23 #include <Variable/VariableController.h>
23 #include <Variable/VariableController.h>
24
24
25 #include <unordered_map>
25 #include <unordered_map>
26
26
27 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
27 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28
28
29 namespace {
29 namespace {
30
30
31 /// Key pressed to enable drag&drop in all modes
31 /// Key pressed to enable drag&drop in all modes
32 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
32 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33
33
34 /// Key pressed to enable zoom on horizontal axis
34 /// Key pressed to enable zoom on horizontal axis
35 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
35 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36
36
37 /// Key pressed to enable zoom on vertical axis
37 /// Key pressed to enable zoom on vertical axis
38 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
38 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39
39
40 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
40 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 const auto PAN_SPEED = 5;
41 const auto PAN_SPEED = 5;
42
42
43 /// Key pressed to enable a calibration pan
43 /// Key pressed to enable a calibration pan
44 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
44 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45
45
46 /// Key pressed to enable multi selection of selection zones
46 /// Key pressed to enable multi selection of selection zones
47 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
47 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48
48
49 /// Minimum size for the zoom box, in percentage of the axis range
49 /// Minimum size for the zoom box, in percentage of the axis range
50 const auto ZOOM_BOX_MIN_SIZE = 0.8;
50 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51
51
52 /// Format of the dates appearing in the label of a cursor
52 /// Format of the dates appearing in the label of a cursor
53 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
53 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
54
54
55 } // namespace
55 } // namespace
56
56
57 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
57 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58
58
59 explicit VisualizationGraphWidgetPrivate(const QString &name)
59 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 : m_Name{name},
60 : m_Name{name},
61 m_DoAcquisition{true},
61 m_DoAcquisition{true},
62 m_IsCalibration{false},
62 m_IsCalibration{false},
63 m_RenderingDelegate{nullptr}
63 m_RenderingDelegate{nullptr}
64 {
64 {
65 }
65 }
66
66
67 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
67 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
68 const SqpRange &range)
68 const SqpRange &range)
69 {
69 {
70 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
70 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
71
71
72 // Prevents that data has changed to update rendering
72 // Prevents that data has changed to update rendering
73 m_RenderingDelegate->onPlotUpdated();
73 m_RenderingDelegate->onPlotUpdated();
74 }
74 }
75
75
76 QString m_Name;
76 QString m_Name;
77 // 1 variable -> n qcpplot
77 // 1 variable -> n qcpplot
78 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
78 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 bool m_DoAcquisition;
79 bool m_DoAcquisition;
80 bool m_IsCalibration;
80 bool m_IsCalibration;
81 /// Delegate used to attach rendering features to the plot
81 /// Delegate used to attach rendering features to the plot
82 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
82 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83
83
84 QCPItemRect *m_DrawingZoomRect = nullptr;
84 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
85 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86
86
87 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
87 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89
89
90 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
90 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
91 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
92 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93
93
94 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
94 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95
95
96 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
96 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
97 {
97 {
98 removeDrawingRect(plot);
98 removeDrawingRect(plot);
99
99
100 auto axisPos = posToAxisPos(pos, plot);
100 auto axisPos = posToAxisPos(pos, plot);
101
101
102 m_DrawingZoomRect = new QCPItemRect{&plot};
102 m_DrawingZoomRect = new QCPItemRect{&plot};
103 QPen p;
103 QPen p;
104 p.setWidth(2);
104 p.setWidth(2);
105 m_DrawingZoomRect->setPen(p);
105 m_DrawingZoomRect->setPen(p);
106
106
107 m_DrawingZoomRect->topLeft->setCoords(axisPos);
107 m_DrawingZoomRect->topLeft->setCoords(axisPos);
108 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
108 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
109 }
109 }
110
110
111 void removeDrawingRect(QCustomPlot &plot)
111 void removeDrawingRect(QCustomPlot &plot)
112 {
112 {
113 if (m_DrawingZoomRect) {
113 if (m_DrawingZoomRect) {
114 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
114 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
115 m_DrawingZoomRect = nullptr;
115 m_DrawingZoomRect = nullptr;
116 plot.replot(QCustomPlot::rpQueuedReplot);
116 plot.replot(QCustomPlot::rpQueuedReplot);
117 }
117 }
118 }
118 }
119
119
120 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
120 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
121 {
121 {
122 endDrawingZone(graph);
122 endDrawingZone(graph);
123
123
124 auto axisPos = posToAxisPos(pos, graph->plot());
124 auto axisPos = posToAxisPos(pos, graph->plot());
125
125
126 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
126 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
127 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
127 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
128 m_DrawingZone->setEditionEnabled(false);
128 m_DrawingZone->setEditionEnabled(false);
129 }
129 }
130
130
131 void endDrawingZone(VisualizationGraphWidget *graph)
131 void endDrawingZone(VisualizationGraphWidget *graph)
132 {
132 {
133 if (m_DrawingZone) {
133 if (m_DrawingZone) {
134 auto drawingZoneRange = m_DrawingZone->range();
134 auto drawingZoneRange = m_DrawingZone->range();
135 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
135 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
136 m_DrawingZone->setEditionEnabled(true);
136 m_DrawingZone->setEditionEnabled(true);
137 addSelectionZone(m_DrawingZone);
137 addSelectionZone(m_DrawingZone);
138 }
138 }
139 else {
139 else {
140 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
140 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
141 }
141 }
142
142
143 graph->plot().replot(QCustomPlot::rpQueuedReplot);
143 graph->plot().replot(QCustomPlot::rpQueuedReplot);
144 m_DrawingZone = nullptr;
144 m_DrawingZone = nullptr;
145 }
145 }
146 }
146 }
147
147
148 void setSelectionZonesEditionEnabled(bool value)
148 void setSelectionZonesEditionEnabled(bool value)
149 {
149 {
150 for (auto s : m_SelectionZones) {
150 for (auto s : m_SelectionZones) {
151 s->setEditionEnabled(value);
151 s->setEditionEnabled(value);
152 }
152 }
153 }
153 }
154
154
155 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
155 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
156
156
157 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
157 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
158 const QCustomPlot &plot) const
158 const QCustomPlot &plot) const
159 {
159 {
160 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
160 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
161 auto minDistanceToZone = -1;
161 auto minDistanceToZone = -1;
162 for (auto zone : m_SelectionZones) {
162 for (auto zone : m_SelectionZones) {
163 auto distanceToZone = zone->selectTest(pos, false);
163 auto distanceToZone = zone->selectTest(pos, false);
164 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
164 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
165 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
165 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
166 selectionZoneItemUnderCursor = zone;
166 selectionZoneItemUnderCursor = zone;
167 }
167 }
168 }
168 }
169
169
170 return selectionZoneItemUnderCursor;
170 return selectionZoneItemUnderCursor;
171 }
171 }
172
172
173 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
173 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
174 {
174 {
175 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
175 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
176 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
176 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
177 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
177 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
178 }
178 }
179
179
180 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
180 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
181 {
181 {
182 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
182 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
183 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
183 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
184 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
184 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
185 }
185 }
186 };
186 };
187
187
188 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
188 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
189 : VisualizationDragWidget{parent},
189 : VisualizationDragWidget{parent},
190 ui{new Ui::VisualizationGraphWidget},
190 ui{new Ui::VisualizationGraphWidget},
191 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
191 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
192 {
192 {
193 ui->setupUi(this);
193 ui->setupUi(this);
194
194
195 // 'Close' options : widget is deleted when closed
195 // 'Close' options : widget is deleted when closed
196 setAttribute(Qt::WA_DeleteOnClose);
196 setAttribute(Qt::WA_DeleteOnClose);
197
197
198 // Set qcpplot properties :
198 // Set qcpplot properties :
199 // - zoom is enabled
199 // - zoom is enabled
200 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
200 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
201 ui->widget->setInteractions(QCP::iRangeZoom);
201 ui->widget->setInteractions(QCP::iRangeZoom);
202 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
202 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
203
203
204 // The delegate must be initialized after the ui as it uses the plot
204 // The delegate must be initialized after the ui as it uses the plot
205 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
205 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
206
206
207 // Init the cursors
207 // Init the cursors
208 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
208 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
209 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
209 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
210 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
210 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
211 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
211 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
212
212
213 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
213 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
214 connect(ui->widget, &QCustomPlot::mouseRelease, this,
214 connect(ui->widget, &QCustomPlot::mouseRelease, this,
215 &VisualizationGraphWidget::onMouseRelease);
215 &VisualizationGraphWidget::onMouseRelease);
216 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
216 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
217 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
217 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
218 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
218 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
219 &VisualizationGraphWidget::onMouseDoubleClick);
219 &VisualizationGraphWidget::onMouseDoubleClick);
220 connect(
220 connect(
221 ui->widget->xAxis,
221 ui->widget->xAxis,
222 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
222 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
223 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
223 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
224
224
225 // Activates menu when right clicking on the graph
225 // Activates menu when right clicking on the graph
226 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
226 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
227 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
227 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
228 &VisualizationGraphWidget::onGraphMenuRequested);
228 &VisualizationGraphWidget::onGraphMenuRequested);
229
229
230 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
230 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
231 &VariableController::onRequestDataLoading);
231 &VariableController::onRequestDataLoading);
232
232
233 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
233 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
234 &VisualizationGraphWidget::onUpdateVarDisplaying);
234 &VisualizationGraphWidget::onUpdateVarDisplaying);
235
235
236 #ifdef Q_OS_MAC
236 #ifdef Q_OS_MAC
237 plot().setPlottingHint(QCP::phFastPolylines, true);
237 plot().setPlottingHint(QCP::phFastPolylines, true);
238 #endif
238 #endif
239 }
239 }
240
240
241
241
242 VisualizationGraphWidget::~VisualizationGraphWidget()
242 VisualizationGraphWidget::~VisualizationGraphWidget()
243 {
243 {
244 delete ui;
244 delete ui;
245 }
245 }
246
246
247 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
247 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
248 {
248 {
249 auto parent = parentWidget();
249 auto parent = parentWidget();
250 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
250 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
251 parent = parent->parentWidget();
251 parent = parent->parentWidget();
252 }
252 }
253
253
254 return qobject_cast<VisualizationZoneWidget *>(parent);
254 return qobject_cast<VisualizationZoneWidget *>(parent);
255 }
255 }
256
256
257 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
257 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
258 {
258 {
259 auto parent = parentWidget();
259 auto parent = parentWidget();
260 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
260 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
261 parent = parent->parentWidget();
261 parent = parent->parentWidget();
262 }
262 }
263
263
264 return qobject_cast<VisualizationWidget *>(parent);
264 return qobject_cast<VisualizationWidget *>(parent);
265 }
265 }
266
266
267 void VisualizationGraphWidget::enableAcquisition(bool enable)
267 void VisualizationGraphWidget::enableAcquisition(bool enable)
268 {
268 {
269 impl->m_DoAcquisition = enable;
269 impl->m_DoAcquisition = enable;
270 }
270 }
271
271
272 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
272 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
273 {
273 {
274 // Uses delegate to create the qcpplot components according to the variable
274 // Uses delegate to create the qcpplot components according to the variable
275 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
275 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
276
276
277 if (auto dataSeries = variable->dataSeries()) {
277 if (auto dataSeries = variable->dataSeries()) {
278 // Set axes properties according to the units of the data series
278 // Set axes properties according to the units of the data series
279 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
279 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
280
280
281 // Sets rendering properties for the new plottables
281 // Sets rendering properties for the new plottables
282 // Warning: this method must be called after setAxesProperties(), as it can access to some
282 // Warning: this method must be called after setAxesProperties(), as it can access to some
283 // axes properties that have to be initialized
283 // axes properties that have to be initialized
284 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
284 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
285 }
285 }
286
286
287 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
287 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
288
288
289 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
289 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
290
290
291 this->enableAcquisition(false);
291 this->enableAcquisition(false);
292 this->setGraphRange(range);
292 this->setGraphRange(range);
293 this->enableAcquisition(true);
293 this->enableAcquisition(true);
294
294
295 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
295 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
296
296
297 emit variableAdded(variable);
297 emit variableAdded(variable);
298 }
298 }
299
299
300 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
300 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
301 {
301 {
302 // Each component associated to the variable :
302 // Each component associated to the variable :
303 // - is removed from qcpplot (which deletes it)
303 // - is removed from qcpplot (which deletes it)
304 // - is no longer referenced in the map
304 // - is no longer referenced in the map
305 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
305 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
306 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
306 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
307 emit variableAboutToBeRemoved(variable);
307 emit variableAboutToBeRemoved(variable);
308
308
309 auto &plottablesMap = variableIt->second;
309 auto &plottablesMap = variableIt->second;
310
310
311 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
311 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
312 plottableIt != plottableEnd;) {
312 plottableIt != plottableEnd;) {
313 ui->widget->removePlottable(plottableIt->second);
313 ui->widget->removePlottable(plottableIt->second);
314 plottableIt = plottablesMap.erase(plottableIt);
314 plottableIt = plottablesMap.erase(plottableIt);
315 }
315 }
316
316
317 impl->m_VariableToPlotMultiMap.erase(variableIt);
317 impl->m_VariableToPlotMultiMap.erase(variableIt);
318 }
318 }
319
319
320 // Updates graph
320 // Updates graph
321 ui->widget->replot();
321 ui->widget->replot();
322 }
322 }
323
323
324 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
324 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
325 {
325 {
326 auto variables = QList<std::shared_ptr<Variable> >{};
326 auto variables = QList<std::shared_ptr<Variable> >{};
327 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
327 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
328 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
328 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
329 variables << it->first;
329 variables << it->first;
330 }
330 }
331
331
332 return variables;
332 return variables;
333 }
333 }
334
334
335 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
335 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
336 {
336 {
337 if (!variable) {
337 if (!variable) {
338 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
338 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
339 return;
339 return;
340 }
340 }
341
341
342 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
342 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
343 }
343 }
344
344
345 SqpRange VisualizationGraphWidget::graphRange() const noexcept
345 SqpRange VisualizationGraphWidget::graphRange() const noexcept
346 {
346 {
347 auto graphRange = ui->widget->xAxis->range();
347 auto graphRange = ui->widget->xAxis->range();
348 return SqpRange{graphRange.lower, graphRange.upper};
348 return SqpRange{graphRange.lower, graphRange.upper};
349 }
349 }
350
350
351 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
351 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
352 {
352 {
353 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
353 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
354 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
354 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
355 ui->widget->replot();
355 ui->widget->replot();
356 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
356 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
357 }
357 }
358
358
359 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
359 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
360 {
360 {
361 QVector<SqpRange> ranges;
361 QVector<SqpRange> ranges;
362 for (auto zone : impl->m_SelectionZones) {
362 for (auto zone : impl->m_SelectionZones) {
363 ranges << zone->range();
363 ranges << zone->range();
364 }
364 }
365
365
366 return ranges;
366 return ranges;
367 }
367 }
368
368
369 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
369 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
370 {
370 {
371 for (const auto &range : ranges) {
371 for (const auto &range : ranges) {
372 // note: ownership is transfered to QCustomPlot
372 // note: ownership is transfered to QCustomPlot
373 auto zone = new VisualizationSelectionZoneItem(&plot());
373 auto zone = new VisualizationSelectionZoneItem(&plot());
374 zone->setRange(range.m_TStart, range.m_TEnd);
374 zone->setRange(range.m_TStart, range.m_TEnd);
375 impl->addSelectionZone(zone);
375 impl->addSelectionZone(zone);
376 }
376 }
377
377
378 plot().replot(QCustomPlot::rpQueuedReplot);
378 plot().replot(QCustomPlot::rpQueuedReplot);
379 }
379 }
380
380
381 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
381 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
382 {
382 {
383 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
384
385 if (impl->m_HoveredZone == selectionZone) {
386 impl->m_HoveredZone = nullptr;
387 setCursor(Qt::ArrowCursor);
388 }
389
383 impl->m_SelectionZones.removeAll(selectionZone);
390 impl->m_SelectionZones.removeAll(selectionZone);
384 plot().removeItem(selectionZone);
391 plot().removeItem(selectionZone);
385 plot().replot(QCustomPlot::rpQueuedReplot);
392 plot().replot(QCustomPlot::rpQueuedReplot);
386 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
387 }
393 }
388
394
389 void VisualizationGraphWidget::undoZoom()
395 void VisualizationGraphWidget::undoZoom()
390 {
396 {
391 auto zoom = impl->m_ZoomStack.pop();
397 auto zoom = impl->m_ZoomStack.pop();
392 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
398 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
393 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
399 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
394
400
395 axisX->setRange(zoom.first);
401 axisX->setRange(zoom.first);
396 axisY->setRange(zoom.second);
402 axisY->setRange(zoom.second);
397
403
398 plot().replot(QCustomPlot::rpQueuedReplot);
404 plot().replot(QCustomPlot::rpQueuedReplot);
399 }
405 }
400
406
401 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
407 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
402 {
408 {
403 if (visitor) {
409 if (visitor) {
404 visitor->visit(this);
410 visitor->visit(this);
405 }
411 }
406 else {
412 else {
407 qCCritical(LOG_VisualizationGraphWidget())
413 qCCritical(LOG_VisualizationGraphWidget())
408 << tr("Can't visit widget : the visitor is null");
414 << tr("Can't visit widget : the visitor is null");
409 }
415 }
410 }
416 }
411
417
412 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
418 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
413 {
419 {
414 auto isSpectrogram = [](const auto &variable) {
420 auto isSpectrogram = [](const auto &variable) {
415 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
421 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
416 };
422 };
417
423
418 // - A spectrogram series can't be dropped on graph with existing plottables
424 // - A spectrogram series can't be dropped on graph with existing plottables
419 // - No data series can be dropped on graph with existing spectrogram series
425 // - No data series can be dropped on graph with existing spectrogram series
420 return isSpectrogram(variable)
426 return isSpectrogram(variable)
421 ? impl->m_VariableToPlotMultiMap.empty()
427 ? impl->m_VariableToPlotMultiMap.empty()
422 : std::none_of(
428 : std::none_of(
423 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
429 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
424 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
430 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
425 }
431 }
426
432
427 bool VisualizationGraphWidget::contains(const Variable &variable) const
433 bool VisualizationGraphWidget::contains(const Variable &variable) const
428 {
434 {
429 // Finds the variable among the keys of the map
435 // Finds the variable among the keys of the map
430 auto variablePtr = &variable;
436 auto variablePtr = &variable;
431 auto findVariable
437 auto findVariable
432 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
438 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
433
439
434 auto end = impl->m_VariableToPlotMultiMap.cend();
440 auto end = impl->m_VariableToPlotMultiMap.cend();
435 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
441 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
436 return it != end;
442 return it != end;
437 }
443 }
438
444
439 QString VisualizationGraphWidget::name() const
445 QString VisualizationGraphWidget::name() const
440 {
446 {
441 return impl->m_Name;
447 return impl->m_Name;
442 }
448 }
443
449
444 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
450 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
445 {
451 {
446 auto mimeData = new QMimeData;
452 auto mimeData = new QMimeData;
447
453
448 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
454 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
449 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
455 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
450 && selectionZoneItemUnderCursor) {
456 && selectionZoneItemUnderCursor) {
451 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
457 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
452 selectionZoneItemUnderCursor->range()));
458 selectionZoneItemUnderCursor->range()));
453 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
459 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
454 selectionZoneItemUnderCursor->range()));
460 selectionZoneItemUnderCursor->range()));
455 }
461 }
456 else {
462 else {
457 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
463 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
458
464
459 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
465 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
460 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
466 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
461 }
467 }
462
468
463 return mimeData;
469 return mimeData;
464 }
470 }
465
471
466 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
472 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
467 {
473 {
468 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
474 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
469 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
475 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
470 && selectionZoneItemUnderCursor) {
476 && selectionZoneItemUnderCursor) {
471
477
472 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
478 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
473 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
479 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
474
480
475 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
481 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
476 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
482 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
477 .toSize();
483 .toSize();
478
484
479 auto pixmap = QPixmap(zoneSize);
485 auto pixmap = QPixmap(zoneSize);
480 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
486 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
481
487
482 return pixmap;
488 return pixmap;
483 }
489 }
484
490
485 return QPixmap();
491 return QPixmap();
486 }
492 }
487
493
488 bool VisualizationGraphWidget::isDragAllowed() const
494 bool VisualizationGraphWidget::isDragAllowed() const
489 {
495 {
490 return true;
496 return true;
491 }
497 }
492
498
493 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
499 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
494 {
500 {
495 if (highlighted) {
501 if (highlighted) {
496 plot().setBackground(QBrush(QColor("#BBD5EE")));
502 plot().setBackground(QBrush(QColor("#BBD5EE")));
497 }
503 }
498 else {
504 else {
499 plot().setBackground(QBrush(Qt::white));
505 plot().setBackground(QBrush(Qt::white));
500 }
506 }
501
507
502 plot().update();
508 plot().update();
503 }
509 }
504
510
505 void VisualizationGraphWidget::addVerticalCursor(double time)
511 void VisualizationGraphWidget::addVerticalCursor(double time)
506 {
512 {
507 impl->m_VerticalCursor->setPosition(time);
513 impl->m_VerticalCursor->setPosition(time);
508 impl->m_VerticalCursor->setVisible(true);
514 impl->m_VerticalCursor->setVisible(true);
509
515
510 auto text
516 auto text
511 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
517 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
512 impl->m_VerticalCursor->setLabelText(text);
518 impl->m_VerticalCursor->setLabelText(text);
513 }
519 }
514
520
515 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
521 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
516 {
522 {
517 impl->m_VerticalCursor->setAbsolutePosition(position);
523 impl->m_VerticalCursor->setAbsolutePosition(position);
518 impl->m_VerticalCursor->setVisible(true);
524 impl->m_VerticalCursor->setVisible(true);
519
525
520 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
526 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
521 auto text
527 auto text
522 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
528 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
523 impl->m_VerticalCursor->setLabelText(text);
529 impl->m_VerticalCursor->setLabelText(text);
524 }
530 }
525
531
526 void VisualizationGraphWidget::removeVerticalCursor()
532 void VisualizationGraphWidget::removeVerticalCursor()
527 {
533 {
528 impl->m_VerticalCursor->setVisible(false);
534 impl->m_VerticalCursor->setVisible(false);
529 plot().replot(QCustomPlot::rpQueuedReplot);
535 plot().replot(QCustomPlot::rpQueuedReplot);
530 }
536 }
531
537
532 void VisualizationGraphWidget::addHorizontalCursor(double value)
538 void VisualizationGraphWidget::addHorizontalCursor(double value)
533 {
539 {
534 impl->m_HorizontalCursor->setPosition(value);
540 impl->m_HorizontalCursor->setPosition(value);
535 impl->m_HorizontalCursor->setVisible(true);
541 impl->m_HorizontalCursor->setVisible(true);
536 impl->m_HorizontalCursor->setLabelText(QString::number(value));
542 impl->m_HorizontalCursor->setLabelText(QString::number(value));
537 }
543 }
538
544
539 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
545 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
540 {
546 {
541 impl->m_HorizontalCursor->setAbsolutePosition(position);
547 impl->m_HorizontalCursor->setAbsolutePosition(position);
542 impl->m_HorizontalCursor->setVisible(true);
548 impl->m_HorizontalCursor->setVisible(true);
543
549
544 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
550 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
545 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
551 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
546 }
552 }
547
553
548 void VisualizationGraphWidget::removeHorizontalCursor()
554 void VisualizationGraphWidget::removeHorizontalCursor()
549 {
555 {
550 impl->m_HorizontalCursor->setVisible(false);
556 impl->m_HorizontalCursor->setVisible(false);
551 plot().replot(QCustomPlot::rpQueuedReplot);
557 plot().replot(QCustomPlot::rpQueuedReplot);
552 }
558 }
553
559
554 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
560 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
555 {
561 {
556 Q_UNUSED(event);
562 Q_UNUSED(event);
557
563
558 // Prevents that all variables will be removed from graph when it will be closed
564 // Prevents that all variables will be removed from graph when it will be closed
559 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
565 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
560 emit variableAboutToBeRemoved(variableEntry.first);
566 emit variableAboutToBeRemoved(variableEntry.first);
561 }
567 }
562 }
568 }
563
569
564 void VisualizationGraphWidget::enterEvent(QEvent *event)
570 void VisualizationGraphWidget::enterEvent(QEvent *event)
565 {
571 {
566 Q_UNUSED(event);
572 Q_UNUSED(event);
567 impl->m_RenderingDelegate->showGraphOverlay(true);
573 impl->m_RenderingDelegate->showGraphOverlay(true);
568 }
574 }
569
575
570 void VisualizationGraphWidget::leaveEvent(QEvent *event)
576 void VisualizationGraphWidget::leaveEvent(QEvent *event)
571 {
577 {
572 Q_UNUSED(event);
578 Q_UNUSED(event);
573 impl->m_RenderingDelegate->showGraphOverlay(false);
579 impl->m_RenderingDelegate->showGraphOverlay(false);
574
580
575 if (auto parentZone = parentZoneWidget()) {
581 if (auto parentZone = parentZoneWidget()) {
576 parentZone->notifyMouseLeaveGraph(this);
582 parentZone->notifyMouseLeaveGraph(this);
577 }
583 }
578 else {
584 else {
579 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
585 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
580 }
586 }
581
587
582 if (impl->m_HoveredZone) {
588 if (impl->m_HoveredZone) {
583 impl->m_HoveredZone->setHovered(false);
589 impl->m_HoveredZone->setHovered(false);
584 impl->m_HoveredZone = nullptr;
590 impl->m_HoveredZone = nullptr;
585 }
591 }
586 }
592 }
587
593
588 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
594 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
589 {
595 {
590 return *ui->widget;
596 return *ui->widget;
591 }
597 }
592
598
593 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
599 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
594 {
600 {
595 QMenu graphMenu{};
601 QMenu graphMenu{};
596
602
597 // Iterates on variables (unique keys)
603 // Iterates on variables (unique keys)
598 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
604 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
599 end = impl->m_VariableToPlotMultiMap.cend();
605 end = impl->m_VariableToPlotMultiMap.cend();
600 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
606 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
601 // 'Remove variable' action
607 // 'Remove variable' action
602 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
608 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
603 [ this, var = it->first ]() { removeVariable(var); });
609 [ this, var = it->first ]() { removeVariable(var); });
604 }
610 }
605
611
606 if (!impl->m_ZoomStack.isEmpty()) {
612 if (!impl->m_ZoomStack.isEmpty()) {
607 if (!graphMenu.isEmpty()) {
613 if (!graphMenu.isEmpty()) {
608 graphMenu.addSeparator();
614 graphMenu.addSeparator();
609 }
615 }
610
616
611 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
617 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
612 }
618 }
613
619
614 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
620 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
615 if (selectionZoneItem) {
621 if (selectionZoneItem) {
616 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
622 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
617 selectedItems.removeAll(selectionZoneItem);
623 selectedItems.removeAll(selectionZoneItem);
618 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
624 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
619
625
620 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
626 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
621 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
627 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
622 graphMenu.addSeparator();
628 graphMenu.addSeparator();
623 }
629 }
624
630
625 for (auto zoneAction : zoneActions) {
631 for (auto zoneAction : zoneActions) {
626 auto action = graphMenu.addAction(zoneAction->name());
632 auto action = graphMenu.addAction(zoneAction->name());
627 action->setEnabled(zoneAction->isEnabled(selectedItems));
633 action->setEnabled(zoneAction->isEnabled(selectedItems));
634 action->setShortcut(zoneAction->displayedShortcut());
628 QObject::connect(action, &QAction::triggered,
635 QObject::connect(action, &QAction::triggered,
629 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
636 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
630 }
637 }
631 }
638 }
632
639
633 if (!graphMenu.isEmpty()) {
640 if (!graphMenu.isEmpty()) {
634 graphMenu.exec(QCursor::pos());
641 graphMenu.exec(QCursor::pos());
635 }
642 }
636 }
643 }
637
644
638 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
645 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
639 {
646 {
640 qCDebug(LOG_VisualizationGraphWidget())
647 qCDebug(LOG_VisualizationGraphWidget())
641 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
648 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
642 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
649 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
643
650
644 auto graphRange = SqpRange{t1.lower, t1.upper};
651 auto graphRange = SqpRange{t1.lower, t1.upper};
645 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
652 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
646
653
647 if (impl->m_DoAcquisition) {
654 if (impl->m_DoAcquisition) {
648 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
655 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
649
656
650 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
657 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
651 end = impl->m_VariableToPlotMultiMap.end();
658 end = impl->m_VariableToPlotMultiMap.end();
652 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
659 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
653 variableUnderGraphVector.push_back(it->first);
660 variableUnderGraphVector.push_back(it->first);
654 }
661 }
655 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
662 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
656 !impl->m_IsCalibration);
663 !impl->m_IsCalibration);
657
664
658 if (!impl->m_IsCalibration) {
665 if (!impl->m_IsCalibration) {
659 qCDebug(LOG_VisualizationGraphWidget())
666 qCDebug(LOG_VisualizationGraphWidget())
660 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
667 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
661 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
668 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
662 emit synchronize(graphRange, oldGraphRange);
669 emit synchronize(graphRange, oldGraphRange);
663 }
670 }
664 }
671 }
665
672
666 auto pos = mapFromGlobal(QCursor::pos());
673 auto pos = mapFromGlobal(QCursor::pos());
667 auto axisPos = impl->posToAxisPos(pos, plot());
674 auto axisPos = impl->posToAxisPos(pos, plot());
668 if (auto parentZone = parentZoneWidget()) {
675 if (auto parentZone = parentZoneWidget()) {
669 if (impl->pointIsInAxisRect(axisPos, plot())) {
676 if (impl->pointIsInAxisRect(axisPos, plot())) {
670 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
677 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
671 }
678 }
672 else {
679 else {
673 parentZone->notifyMouseLeaveGraph(this);
680 parentZone->notifyMouseLeaveGraph(this);
674 }
681 }
675 }
682 }
676 else {
683 else {
677 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
684 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
678 }
685 }
679 }
686 }
680
687
681 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
688 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
682 {
689 {
683 impl->m_RenderingDelegate->onMouseDoubleClick(event);
690 impl->m_RenderingDelegate->onMouseDoubleClick(event);
684 }
691 }
685
692
686 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
693 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
687 {
694 {
688 // Handles plot rendering when mouse is moving
695 // Handles plot rendering when mouse is moving
689 impl->m_RenderingDelegate->onMouseMove(event);
696 impl->m_RenderingDelegate->onMouseMove(event);
690
697
691 auto axisPos = impl->posToAxisPos(event->pos(), plot());
698 auto axisPos = impl->posToAxisPos(event->pos(), plot());
692
699
693 // Zoom box and zone drawing
700 // Zoom box and zone drawing
694 if (impl->m_DrawingZoomRect) {
701 if (impl->m_DrawingZoomRect) {
695 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
702 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
696 }
703 }
697 else if (impl->m_DrawingZone) {
704 else if (impl->m_DrawingZone) {
698 impl->m_DrawingZone->setEnd(axisPos.x());
705 impl->m_DrawingZone->setEnd(axisPos.x());
699 }
706 }
700
707
701 // Cursor
708 // Cursor
702 if (auto parentZone = parentZoneWidget()) {
709 if (auto parentZone = parentZoneWidget()) {
703 if (impl->pointIsInAxisRect(axisPos, plot())) {
710 if (impl->pointIsInAxisRect(axisPos, plot())) {
704 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
711 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
705 }
712 }
706 else {
713 else {
707 parentZone->notifyMouseLeaveGraph(this);
714 parentZone->notifyMouseLeaveGraph(this);
708 }
715 }
709 }
716 }
710 else {
717 else {
711 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
718 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
712 }
719 }
713
720
714 // Search for the selection zone under the mouse
721 // Search for the selection zone under the mouse
715 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
722 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
716 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
723 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
717 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
724 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
718
725
719 // Sets the appropriate cursor shape
726 // Sets the appropriate cursor shape
720 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
727 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
721 setCursor(cursorShape);
728 setCursor(cursorShape);
722
729
723 // Manages the hovered zone
730 // Manages the hovered zone
724 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
731 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
725 if (impl->m_HoveredZone) {
732 if (impl->m_HoveredZone) {
726 impl->m_HoveredZone->setHovered(false);
733 impl->m_HoveredZone->setHovered(false);
727 }
734 }
728 selectionZoneItemUnderCursor->setHovered(true);
735 selectionZoneItemUnderCursor->setHovered(true);
729 impl->m_HoveredZone = selectionZoneItemUnderCursor;
736 impl->m_HoveredZone = selectionZoneItemUnderCursor;
730 plot().replot(QCustomPlot::rpQueuedReplot);
737 plot().replot(QCustomPlot::rpQueuedReplot);
731 }
738 }
732 }
739 }
733 else {
740 else {
734 // There is no zone under the mouse or the interaction mode is not "selection zones"
741 // There is no zone under the mouse or the interaction mode is not "selection zones"
735 if (impl->m_HoveredZone) {
742 if (impl->m_HoveredZone) {
736 impl->m_HoveredZone->setHovered(false);
743 impl->m_HoveredZone->setHovered(false);
737 impl->m_HoveredZone = nullptr;
744 impl->m_HoveredZone = nullptr;
738 }
745 }
739
746
740 setCursor(Qt::ArrowCursor);
747 setCursor(Qt::ArrowCursor);
741 }
748 }
742
749
743 impl->m_HasMovedMouse = true;
750 impl->m_HasMovedMouse = true;
744 VisualizationDragWidget::mouseMoveEvent(event);
751 VisualizationDragWidget::mouseMoveEvent(event);
745 }
752 }
746
753
747 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
754 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
748 {
755 {
749 auto value = event->angleDelta().x() + event->angleDelta().y();
756 auto value = event->angleDelta().x() + event->angleDelta().y();
750 if (value != 0) {
757 if (value != 0) {
751
758
752 auto direction = value > 0 ? 1.0 : -1.0;
759 auto direction = value > 0 ? 1.0 : -1.0;
753 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
760 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
754 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
761 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
755 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
762 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
756
763
757 auto zoomOrientations = QFlags<Qt::Orientation>{};
764 auto zoomOrientations = QFlags<Qt::Orientation>{};
758 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
765 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
759 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
766 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
760
767
761 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
768 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
762
769
763 if (!isZoomX && !isZoomY) {
770 if (!isZoomX && !isZoomY) {
764 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
771 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
765 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
772 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
766
773
767 axis->setRange(axis->range() + diff);
774 axis->setRange(axis->range() + diff);
768
775
769 if (plot().noAntialiasingOnDrag()) {
776 if (plot().noAntialiasingOnDrag()) {
770 plot().setNotAntialiasedElements(QCP::aeAll);
777 plot().setNotAntialiasedElements(QCP::aeAll);
771 }
778 }
772
779
773 plot().replot(QCustomPlot::rpQueuedReplot);
780 plot().replot(QCustomPlot::rpQueuedReplot);
774 }
781 }
775 }
782 }
776 }
783 }
777
784
778 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
785 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
779 {
786 {
780 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
787 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
781 auto isSelectionZoneMode
788 auto isSelectionZoneMode
782 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
789 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
783 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
790 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
784
791
785 if (!isDragDropClick && isLeftClick) {
792 if (!isDragDropClick && isLeftClick) {
786 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
793 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
787 // Starts a zoom box
794 // Starts a zoom box
788 impl->startDrawingRect(event->pos(), plot());
795 impl->startDrawingRect(event->pos(), plot());
789 }
796 }
790 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
797 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
791 // Starts a new selection zone
798 // Starts a new selection zone
792 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
799 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
793 if (!zoneAtPos) {
800 if (!zoneAtPos) {
794 impl->startDrawingZone(event->pos(), this);
801 impl->startDrawingZone(event->pos(), this);
795 }
802 }
796 }
803 }
797 }
804 }
798
805
799 // Allows mouse panning only in default mode
806 // Allows mouse panning only in default mode
800 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
807 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
801 == SqpApplication::PlotsInteractionMode::None
808 == SqpApplication::PlotsInteractionMode::None
802 && !isDragDropClick);
809 && !isDragDropClick);
803
810
804 // Allows zone edition only in selection zone mode without drag&drop
811 // Allows zone edition only in selection zone mode without drag&drop
805 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
812 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
806
813
807 // Selection / Deselection
814 // Selection / Deselection
808 if (isSelectionZoneMode) {
815 if (isSelectionZoneMode) {
809 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
816 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
810 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
817 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
811 if (selectionZoneItemUnderCursor && isLeftClick) {
818 if (selectionZoneItemUnderCursor && isLeftClick) {
812 selectionZoneItemUnderCursor->setAssociatedEditedZones(
819 selectionZoneItemUnderCursor->setAssociatedEditedZones(
813 parentVisualizationWidget()->selectionZoneManager().selectedItems());
820 parentVisualizationWidget()->selectionZoneManager().selectedItems());
814 }
821 }
815 else if (!isMultiSelectionClick && isLeftClick) {
822 else if (!isMultiSelectionClick && isLeftClick) {
816 parentVisualizationWidget()->selectionZoneManager().clearSelection();
823 parentVisualizationWidget()->selectionZoneManager().clearSelection();
817 }
824 }
818 else {
825 else {
819 // No selection change
826 // No selection change
820 }
827 }
821 }
828 }
822
829
823
830
824 impl->m_HasMovedMouse = false;
831 impl->m_HasMovedMouse = false;
825 VisualizationDragWidget::mousePressEvent(event);
832 VisualizationDragWidget::mousePressEvent(event);
826 }
833 }
827
834
828 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
835 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
829 {
836 {
830 if (impl->m_DrawingZoomRect) {
837 if (impl->m_DrawingZoomRect) {
831
838
832 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
839 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
833 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
840 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
834
841
835 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
842 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
836 impl->m_DrawingZoomRect->bottomRight->coords().x()};
843 impl->m_DrawingZoomRect->bottomRight->coords().x()};
837
844
838 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
845 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
839 impl->m_DrawingZoomRect->bottomRight->coords().y()};
846 impl->m_DrawingZoomRect->bottomRight->coords().y()};
840
847
841 impl->removeDrawingRect(plot());
848 impl->removeDrawingRect(plot());
842
849
843 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
850 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
844 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
851 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
845 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
852 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
846 axisX->setRange(newAxisXRange);
853 axisX->setRange(newAxisXRange);
847 axisY->setRange(newAxisYRange);
854 axisY->setRange(newAxisYRange);
848
855
849 plot().replot(QCustomPlot::rpQueuedReplot);
856 plot().replot(QCustomPlot::rpQueuedReplot);
850 }
857 }
851 }
858 }
852
859
853 impl->endDrawingZone(this);
860 impl->endDrawingZone(this);
854
861
855 impl->m_IsCalibration = false;
862 impl->m_IsCalibration = false;
856
863
857 // Selection / Deselection
864 // Selection / Deselection
858 auto isSelectionZoneMode
865 auto isSelectionZoneMode
859 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
866 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
860 if (isSelectionZoneMode) {
867 if (isSelectionZoneMode) {
861 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
868 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
862 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
869 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
863 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
870 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
864 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
871 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
865 parentVisualizationWidget()->selectionZoneManager().select(
872 parentVisualizationWidget()->selectionZoneManager().select(
866 {selectionZoneItemUnderCursor});
873 {selectionZoneItemUnderCursor});
867 }
874 }
868 else if (!impl->m_HasMovedMouse) {
875 else if (!impl->m_HasMovedMouse) {
869 parentVisualizationWidget()->selectionZoneManager().setSelected(
876 parentVisualizationWidget()->selectionZoneManager().setSelected(
870 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
877 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
871 || event->button() == Qt::RightButton);
878 || event->button() == Qt::RightButton);
872 }
879 }
873 }
880 }
874 else {
881 else {
875 // No selection change
882 // No selection change
876 }
883 }
877 }
884 }
878 }
885 }
879
886
880 void VisualizationGraphWidget::onDataCacheVariableUpdated()
887 void VisualizationGraphWidget::onDataCacheVariableUpdated()
881 {
888 {
882 auto graphRange = ui->widget->xAxis->range();
889 auto graphRange = ui->widget->xAxis->range();
883 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
890 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
884
891
885 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
892 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
886 auto variable = variableEntry.first;
893 auto variable = variableEntry.first;
887 qCDebug(LOG_VisualizationGraphWidget())
894 qCDebug(LOG_VisualizationGraphWidget())
888 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
895 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
889 qCDebug(LOG_VisualizationGraphWidget())
896 qCDebug(LOG_VisualizationGraphWidget())
890 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
897 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
891 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
898 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
892 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
899 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
893 }
900 }
894 }
901 }
895 }
902 }
896
903
897 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
904 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
898 const SqpRange &range)
905 const SqpRange &range)
899 {
906 {
900 auto it = impl->m_VariableToPlotMultiMap.find(variable);
907 auto it = impl->m_VariableToPlotMultiMap.find(variable);
901 if (it != impl->m_VariableToPlotMultiMap.end()) {
908 if (it != impl->m_VariableToPlotMultiMap.end()) {
902 impl->updateData(it->second, variable->dataSeries(), range);
909 impl->updateData(it->second, variable->dataSeries(), range);
903 }
910 }
904 }
911 }
@@ -1,51 +1,51
1 #include "Visualization/VisualizationSelectionZoneManager.h"
1 #include "Visualization/VisualizationSelectionZoneManager.h"
2 #include "Visualization/VisualizationSelectionZoneItem.h"
2 #include "Visualization/VisualizationSelectionZoneItem.h"
3
3
4 struct VisualizationSelectionZoneManager::VisualizationSelectionZoneManagerPrivate {
4 struct VisualizationSelectionZoneManager::VisualizationSelectionZoneManagerPrivate {
5 QVector<VisualizationSelectionZoneItem *> m_SelectedItems;
5 QVector<VisualizationSelectionZoneItem *> m_SelectedItems;
6 };
6 };
7
7
8 VisualizationSelectionZoneManager::VisualizationSelectionZoneManager()
8 VisualizationSelectionZoneManager::VisualizationSelectionZoneManager()
9 : impl{spimpl::make_unique_impl<VisualizationSelectionZoneManagerPrivate>()}
9 : impl{spimpl::make_unique_impl<VisualizationSelectionZoneManagerPrivate>()}
10 {
10 {
11 }
11 }
12
12
13 void VisualizationSelectionZoneManager::select(
13 void VisualizationSelectionZoneManager::select(
14 const QVector<VisualizationSelectionZoneItem *> &items)
14 const QVector<VisualizationSelectionZoneItem *> &items)
15 {
15 {
16 clearSelection();
16 clearSelection();
17 for (auto item : items) {
17 for (auto item : items) {
18 setSelected(item, true);
18 setSelected(item, true);
19 }
19 }
20 }
20 }
21
21
22 void VisualizationSelectionZoneManager::setSelected(VisualizationSelectionZoneItem *item,
22 void VisualizationSelectionZoneManager::setSelected(VisualizationSelectionZoneItem *item,
23 bool value)
23 bool value)
24 {
24 {
25 if (value != item->selected()) {
25 if (value != item->selected()) {
26 item->setSelected(value);
26 item->setSelected(value);
27 item->parentPlot()->replot();
27 item->parentPlot()->replot(QCustomPlot::rpQueuedReplot);
28 }
28 }
29
29
30 if (!value && impl->m_SelectedItems.contains(item)) {
30 if (!value && impl->m_SelectedItems.contains(item)) {
31 impl->m_SelectedItems.removeAll(item);
31 impl->m_SelectedItems.removeAll(item);
32 }
32 }
33 else if (value) {
33 else if (value) {
34 impl->m_SelectedItems << item;
34 impl->m_SelectedItems << item;
35 }
35 }
36 }
36 }
37
37
38 void VisualizationSelectionZoneManager::clearSelection()
38 void VisualizationSelectionZoneManager::clearSelection()
39 {
39 {
40 for (auto item : impl->m_SelectedItems) {
40 for (auto item : impl->m_SelectedItems) {
41 item->setSelected(false);
41 item->setSelected(false);
42 item->parentPlot()->replot();
42 item->parentPlot()->replot();
43 }
43 }
44
44
45 impl->m_SelectedItems.clear();
45 impl->m_SelectedItems.clear();
46 }
46 }
47
47
48 QVector<VisualizationSelectionZoneItem *> VisualizationSelectionZoneManager::selectedItems() const
48 QVector<VisualizationSelectionZoneItem *> VisualizationSelectionZoneManager::selectedItems() const
49 {
49 {
50 return impl->m_SelectedItems;
50 return impl->m_SelectedItems;
51 }
51 }
@@ -1,201 +1,215
1 #include "Visualization/VisualizationWidget.h"
1 #include "Visualization/VisualizationWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationActionManager.h"
3 #include "Visualization/VisualizationActionManager.h"
4 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationSelectionZoneItem.h"
5 #include "Visualization/VisualizationSelectionZoneManager.h"
6 #include "Visualization/VisualizationSelectionZoneManager.h"
6 #include "Visualization/VisualizationTabWidget.h"
7 #include "Visualization/VisualizationTabWidget.h"
7 #include "Visualization/VisualizationZoneWidget.h"
8 #include "Visualization/VisualizationZoneWidget.h"
8 #include "Visualization/operations/FindVariableOperation.h"
9 #include "Visualization/operations/FindVariableOperation.h"
9 #include "Visualization/operations/GenerateVariableMenuOperation.h"
10 #include "Visualization/operations/GenerateVariableMenuOperation.h"
10 #include "Visualization/operations/RemoveVariableOperation.h"
11 #include "Visualization/operations/RemoveVariableOperation.h"
11 #include "Visualization/operations/RescaleAxeOperation.h"
12 #include "Visualization/operations/RescaleAxeOperation.h"
12 #include "Visualization/qcustomplot.h"
13 #include "Visualization/qcustomplot.h"
13
14
14 #include "ui_VisualizationWidget.h"
15 #include "ui_VisualizationWidget.h"
15
16
16 #include "DragAndDrop/DragDropGuiController.h"
17 #include "DragAndDrop/DragDropGuiController.h"
17 #include "SqpApplication.h"
18 #include "SqpApplication.h"
18
19
19 #include <QToolButton>
20 #include <QToolButton>
20
21
21 #include <memory>
22 #include <memory>
22
23
23 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
24 Q_LOGGING_CATEGORY(LOG_VisualizationWidget, "VisualizationWidget")
24
25
25 struct VisualizationWidget::VisualizationWidgetPrivate {
26 struct VisualizationWidget::VisualizationWidgetPrivate {
26 std::unique_ptr<VisualizationSelectionZoneManager> m_ZoneSelectionManager = nullptr;
27 std::unique_ptr<VisualizationSelectionZoneManager> m_ZoneSelectionManager = nullptr;
27 VisualizationActionManager m_ActionManager;
28 VisualizationActionManager m_ActionManager;
28
29
29 VisualizationWidgetPrivate()
30 VisualizationWidgetPrivate()
30 : m_ZoneSelectionManager(std::make_unique<VisualizationSelectionZoneManager>())
31 : m_ZoneSelectionManager(std::make_unique<VisualizationSelectionZoneManager>())
31 {
32 {
32 }
33 }
33 };
34 };
34
35
35 VisualizationWidget::VisualizationWidget(QWidget *parent)
36 VisualizationWidget::VisualizationWidget(QWidget *parent)
36 : QWidget{parent},
37 : QWidget{parent},
37 ui{new Ui::VisualizationWidget},
38 ui{new Ui::VisualizationWidget},
38 impl{spimpl::make_unique_impl<VisualizationWidgetPrivate>()}
39 impl{spimpl::make_unique_impl<VisualizationWidgetPrivate>()}
39 {
40 {
40 ui->setupUi(this);
41 ui->setupUi(this);
41
42
42 auto addTabViewButton = new QToolButton{ui->tabWidget};
43 auto addTabViewButton = new QToolButton{ui->tabWidget};
43 addTabViewButton->setText(tr("Add View"));
44 addTabViewButton->setText(tr("Add View"));
44 addTabViewButton->setCursor(Qt::ArrowCursor);
45 addTabViewButton->setCursor(Qt::ArrowCursor);
45 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
46 ui->tabWidget->setCornerWidget(addTabViewButton, Qt::TopRightCorner);
46
47
47 auto enableMinimumCornerWidgetSize = [this](bool enable) {
48 auto enableMinimumCornerWidgetSize = [this](bool enable) {
48
49
49 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
50 auto tabViewCornerWidget = ui->tabWidget->cornerWidget();
50 auto width = enable ? tabViewCornerWidget->width() : 0;
51 auto width = enable ? tabViewCornerWidget->width() : 0;
51 auto height = enable ? tabViewCornerWidget->height() : 0;
52 auto height = enable ? tabViewCornerWidget->height() : 0;
52 tabViewCornerWidget->setMinimumHeight(height);
53 tabViewCornerWidget->setMinimumHeight(height);
53 tabViewCornerWidget->setMinimumWidth(width);
54 tabViewCornerWidget->setMinimumWidth(width);
54 ui->tabWidget->setMinimumHeight(height);
55 ui->tabWidget->setMinimumHeight(height);
55 ui->tabWidget->setMinimumWidth(width);
56 ui->tabWidget->setMinimumWidth(width);
56 };
57 };
57
58
58 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
59 auto addTabView = [this, enableMinimumCornerWidgetSize]() {
59 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
60 auto widget = new VisualizationTabWidget{QString{"View %1"}.arg(ui->tabWidget->count() + 1),
60 ui->tabWidget};
61 ui->tabWidget};
61 auto index = ui->tabWidget->addTab(widget, widget->name());
62 auto index = ui->tabWidget->addTab(widget, widget->name());
62 if (ui->tabWidget->count() > 0) {
63 if (ui->tabWidget->count() > 0) {
63 enableMinimumCornerWidgetSize(false);
64 enableMinimumCornerWidgetSize(false);
64 }
65 }
65 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
66 qCInfo(LOG_VisualizationWidget()) << tr("add the tab of index %1").arg(index);
66 };
67 };
67
68
68 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
69 auto removeTabView = [this, enableMinimumCornerWidgetSize](int index) {
69 if (ui->tabWidget->count() == 1) {
70 if (ui->tabWidget->count() == 1) {
70 enableMinimumCornerWidgetSize(true);
71 enableMinimumCornerWidgetSize(true);
71 }
72 }
72
73
73 // Removes widget from tab and closes it
74 // Removes widget from tab and closes it
74 auto widget = ui->tabWidget->widget(index);
75 auto widget = ui->tabWidget->widget(index);
75 ui->tabWidget->removeTab(index);
76 ui->tabWidget->removeTab(index);
76 if (widget) {
77 if (widget) {
77 widget->close();
78 widget->close();
78 }
79 }
79
80
80 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
81 qCInfo(LOG_VisualizationWidget()) << tr("remove the tab of index %1").arg(index);
81
82
82 };
83 };
83
84
84 ui->tabWidget->setTabsClosable(true);
85 ui->tabWidget->setTabsClosable(true);
85
86
86 connect(addTabViewButton, &QToolButton::clicked, addTabView);
87 connect(addTabViewButton, &QToolButton::clicked, addTabView);
87 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
88 connect(ui->tabWidget, &QTabWidget::tabCloseRequested, removeTabView);
88
89
89 sqpApp->dragDropGuiController().addDragDropTabBar(ui->tabWidget->tabBar());
90 sqpApp->dragDropGuiController().addDragDropTabBar(ui->tabWidget->tabBar());
90
91
92 // Actions
91 impl->m_ActionManager.installSelectionZoneActions();
93 impl->m_ActionManager.installSelectionZoneActions();
92
94
95 auto removeZoneAction = new QAction("Remove selected zone(s)");
96 removeZoneAction->setShortcut(QKeySequence::Delete);
97 connect(removeZoneAction, &QAction::triggered, [this]() {
98 auto selection = impl->m_ZoneSelectionManager->selectedItems();
99 for (auto selectionZone : selection) {
100 if (auto graph = selectionZone->parentGraphWidget()) {
101 graph->removeSelectionZone(selectionZone);
102 }
103 }
104 });
105 addAction(removeZoneAction);
106
93 // Adds default tab
107 // Adds default tab
94 addTabView();
108 addTabView();
95 }
109 }
96
110
97 VisualizationWidget::~VisualizationWidget()
111 VisualizationWidget::~VisualizationWidget()
98 {
112 {
99 sqpApp->dragDropGuiController().removeDragDropTabBar(ui->tabWidget->tabBar());
113 sqpApp->dragDropGuiController().removeDragDropTabBar(ui->tabWidget->tabBar());
100 delete ui;
114 delete ui;
101 }
115 }
102
116
103 VisualizationSelectionZoneManager &VisualizationWidget::selectionZoneManager() const
117 VisualizationSelectionZoneManager &VisualizationWidget::selectionZoneManager() const
104 {
118 {
105 return *impl->m_ZoneSelectionManager.get();
119 return *impl->m_ZoneSelectionManager.get();
106 }
120 }
107
121
108 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
122 void VisualizationWidget::accept(IVisualizationWidgetVisitor *visitor)
109 {
123 {
110 if (visitor) {
124 if (visitor) {
111 visitor->visitEnter(this);
125 visitor->visitEnter(this);
112
126
113 // Apply visitor for tab children
127 // Apply visitor for tab children
114 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
128 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
115 // Widgets different from tabs are not visited (no action)
129 // Widgets different from tabs are not visited (no action)
116 if (auto visualizationTabWidget
130 if (auto visualizationTabWidget
117 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
131 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
118 visualizationTabWidget->accept(visitor);
132 visualizationTabWidget->accept(visitor);
119 }
133 }
120 }
134 }
121
135
122 visitor->visitLeave(this);
136 visitor->visitLeave(this);
123 }
137 }
124 else {
138 else {
125 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
139 qCCritical(LOG_VisualizationWidget()) << tr("Can't visit widget : the visitor is null");
126 }
140 }
127 }
141 }
128
142
129 bool VisualizationWidget::canDrop(const Variable &variable) const
143 bool VisualizationWidget::canDrop(const Variable &variable) const
130 {
144 {
131 // The main widget can never accomodate a variable
145 // The main widget can never accomodate a variable
132 Q_UNUSED(variable);
146 Q_UNUSED(variable);
133 return false;
147 return false;
134 }
148 }
135
149
136 bool VisualizationWidget::contains(const Variable &variable) const
150 bool VisualizationWidget::contains(const Variable &variable) const
137 {
151 {
138 Q_UNUSED(variable);
152 Q_UNUSED(variable);
139 return false;
153 return false;
140 }
154 }
141
155
142 QString VisualizationWidget::name() const
156 QString VisualizationWidget::name() const
143 {
157 {
144 return QStringLiteral("MainView");
158 return QStringLiteral("MainView");
145 }
159 }
146
160
147 void VisualizationWidget::attachVariableMenu(
161 void VisualizationWidget::attachVariableMenu(
148 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
162 QMenu *menu, const QVector<std::shared_ptr<Variable> > &variables) noexcept
149 {
163 {
150 // Menu is generated only if there is a single variable
164 // Menu is generated only if there is a single variable
151 if (variables.size() == 1) {
165 if (variables.size() == 1) {
152 if (auto variable = variables.first()) {
166 if (auto variable = variables.first()) {
153 // Gets the containers of the variable
167 // Gets the containers of the variable
154 FindVariableOperation findVariableOperation{variable};
168 FindVariableOperation findVariableOperation{variable};
155 accept(&findVariableOperation);
169 accept(&findVariableOperation);
156 auto variableContainers = findVariableOperation.result();
170 auto variableContainers = findVariableOperation.result();
157
171
158 // Generates the actions that make it possible to visualize the variable
172 // Generates the actions that make it possible to visualize the variable
159 GenerateVariableMenuOperation generateVariableMenuOperation{
173 GenerateVariableMenuOperation generateVariableMenuOperation{
160 menu, variable, std::move(variableContainers)};
174 menu, variable, std::move(variableContainers)};
161 accept(&generateVariableMenuOperation);
175 accept(&generateVariableMenuOperation);
162 }
176 }
163 else {
177 else {
164 qCCritical(LOG_VisualizationWidget()) << tr(
178 qCCritical(LOG_VisualizationWidget()) << tr(
165 "Can't generate the menu relative to the visualization: the variable is null");
179 "Can't generate the menu relative to the visualization: the variable is null");
166 }
180 }
167 }
181 }
168 else {
182 else {
169 qCDebug(LOG_VisualizationWidget())
183 qCDebug(LOG_VisualizationWidget())
170 << tr("No generation of the menu related to the visualization: several variables are "
184 << tr("No generation of the menu related to the visualization: several variables are "
171 "selected");
185 "selected");
172 }
186 }
173 }
187 }
174
188
175 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
189 void VisualizationWidget::onVariableAboutToBeDeleted(std::shared_ptr<Variable> variable) noexcept
176 {
190 {
177 // Calls the operation of removing all references to the variable in the visualization
191 // Calls the operation of removing all references to the variable in the visualization
178 auto removeVariableOperation = RemoveVariableOperation{variable};
192 auto removeVariableOperation = RemoveVariableOperation{variable};
179 accept(&removeVariableOperation);
193 accept(&removeVariableOperation);
180 }
194 }
181
195
182 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
196 void VisualizationWidget::onRangeChanged(std::shared_ptr<Variable> variable,
183 const SqpRange &range) noexcept
197 const SqpRange &range) noexcept
184 {
198 {
185 // Calls the operation of rescaling all graph that contrains variable in the visualization
199 // Calls the operation of rescaling all graph that contrains variable in the visualization
186 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
200 auto rescaleVariableOperation = RescaleAxeOperation{variable, range};
187 accept(&rescaleVariableOperation);
201 accept(&rescaleVariableOperation);
188 }
202 }
189
203
190 void VisualizationWidget::closeEvent(QCloseEvent *event)
204 void VisualizationWidget::closeEvent(QCloseEvent *event)
191 {
205 {
192 // Closes tabs in the widget
206 // Closes tabs in the widget
193 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
207 for (auto i = 0; i < ui->tabWidget->count(); ++i) {
194 if (auto visualizationTabWidget
208 if (auto visualizationTabWidget
195 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
209 = dynamic_cast<VisualizationTabWidget *>(ui->tabWidget->widget(i))) {
196 visualizationTabWidget->close();
210 visualizationTabWidget->close();
197 }
211 }
198 }
212 }
199
213
200 QWidget::closeEvent(event);
214 QWidget::closeEvent(event);
201 }
215 }
General Comments 4
Under Review
author

Auto status change to "Under Review"

Approved

Status change > Approved

Approved

Status change > Approved

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