##// END OF EJS Templates
Selection of stacked zone via a dialog box
trabillard -
r1120:a02153d618e2
parent child
Show More
@@ -0,0 +1,30
1 #ifndef SCIQLOP_VISUALIZATIONMULTIZONESELECTIONDIALOG_H
2 #define SCIQLOP_VISUALIZATIONMULTIZONESELECTIONDIALOG_H
3
4 #include <Common/spimpl.h>
5 #include <QDialog>
6
7 namespace Ui {
8 class VisualizationMultiZoneSelectionDialog;
9 }
10
11 class VisualizationSelectionZoneItem;
12
13 class VisualizationMultiZoneSelectionDialog : public QDialog {
14 Q_OBJECT
15
16 public:
17 explicit VisualizationMultiZoneSelectionDialog(QWidget *parent = 0);
18 ~VisualizationMultiZoneSelectionDialog();
19
20 void setZones(const QVector<VisualizationSelectionZoneItem *> &zones);
21 QMap<VisualizationSelectionZoneItem *, bool> selectedZones() const;
22
23 private:
24 Ui::VisualizationMultiZoneSelectionDialog *ui;
25
26 class VisualizationMultiZoneSelectionDialogPrivate;
27 spimpl::unique_impl_ptr<VisualizationMultiZoneSelectionDialogPrivate> impl;
28 };
29
30 #endif // SCIQLOP_VISUALIZATIONMULTIZONESELECTIONDIALOG_H
@@ -0,0 +1,69
1 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
2 #include "ui_VisualizationMultiZoneSelectionDialog.h"
3
4 #include "Common/DateUtils.h"
5 #include "Visualization/VisualizationSelectionZoneItem.h"
6
7 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss");
8
9 struct VisualizationMultiZoneSelectionDialog::VisualizationMultiZoneSelectionDialogPrivate {
10 QVector<VisualizationSelectionZoneItem *> m_Zones;
11 };
12
13 VisualizationMultiZoneSelectionDialog::VisualizationMultiZoneSelectionDialog(QWidget *parent)
14 : QDialog(parent, Qt::Tool),
15 ui(new Ui::VisualizationMultiZoneSelectionDialog),
16 impl{spimpl::make_unique_impl<VisualizationMultiZoneSelectionDialogPrivate>()}
17 {
18 ui->setupUi(this);
19
20 connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
21 &VisualizationMultiZoneSelectionDialog::accept);
22 connect(ui->buttonBox, &QDialogButtonBox::rejected, this,
23 &VisualizationMultiZoneSelectionDialog::reject);
24 }
25
26 VisualizationMultiZoneSelectionDialog::~VisualizationMultiZoneSelectionDialog()
27 {
28 delete ui;
29 }
30
31 void VisualizationMultiZoneSelectionDialog::setZones(
32 const QVector<VisualizationSelectionZoneItem *> &zones)
33 {
34 impl->m_Zones = zones;
35
36 // Sorts the zones to display them in temporal order
37 std::sort(impl->m_Zones.begin(), impl->m_Zones.end(), [](auto zone1, auto zone2) {
38 return zone1->range().m_TStart < zone2->range().m_TStart;
39 });
40
41 // Adds the zones in the listwidget
42 for (auto zone : impl->m_Zones) {
43 auto name = zone->name();
44 if (!name.isEmpty()) {
45 name += tr(": ");
46 }
47
48 auto range = zone->range();
49 name += DateUtils::dateTime(range.m_TStart).toString(DATETIME_FORMAT);
50 name += " - ";
51 name += DateUtils::dateTime(range.m_TEnd).toString(DATETIME_FORMAT);
52
53 auto item = new QListWidgetItem(name, ui->listWidget);
54 item->setSelected(zone->selected());
55 }
56 }
57
58 QMap<VisualizationSelectionZoneItem *, bool>
59 VisualizationMultiZoneSelectionDialog::selectedZones() const
60 {
61 QMap<VisualizationSelectionZoneItem *, bool> selectedZones;
62
63 for (auto i = 0; i < ui->listWidget->count(); ++i) {
64 auto item = ui->listWidget->item(i);
65 selectedZones[impl->m_Zones[i]] = item->isSelected();
66 }
67
68 return selectedZones;
69 }
@@ -0,0 +1,47
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
3 <class>VisualizationMultiZoneSelectionDialog</class>
4 <widget class="QDialog" name="VisualizationMultiZoneSelectionDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>270</width>
10 <height>175</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>Select...</string>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <property name="leftMargin">
18 <number>0</number>
19 </property>
20 <property name="topMargin">
21 <number>0</number>
22 </property>
23 <property name="rightMargin">
24 <number>0</number>
25 </property>
26 <property name="bottomMargin">
27 <number>0</number>
28 </property>
29 <item>
30 <widget class="QListWidget" name="listWidget">
31 <property name="selectionMode">
32 <enum>QAbstractItemView::ExtendedSelection</enum>
33 </property>
34 </widget>
35 </item>
36 <item>
37 <widget class="QDialogButtonBox" name="buttonBox">
38 <property name="standardButtons">
39 <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
40 </property>
41 </widget>
42 </item>
43 </layout>
44 </widget>
45 <resources/>
46 <connections/>
47 </ui>
@@ -1,64 +1,68
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
1 #ifndef SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
2 #define SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5 #include <Data/SqpRange.h>
5 #include <Data/SqpRange.h>
6 #include <Visualization/qcustomplot.h>
6 #include <Visualization/qcustomplot.h>
7
7
8 class VisualizationGraphWidget;
8 class VisualizationGraphWidget;
9
9
10 class VisualizationSelectionZoneItem : public QCPItemRect {
10 class VisualizationSelectionZoneItem : public QCPItemRect {
11
11
12 public:
12 public:
13 VisualizationSelectionZoneItem(QCustomPlot *plot);
13 VisualizationSelectionZoneItem(QCustomPlot *plot);
14 virtual ~VisualizationSelectionZoneItem();
14 virtual ~VisualizationSelectionZoneItem();
15
15
16 VisualizationGraphWidget *parentGraphWidget() const noexcept;
16 VisualizationGraphWidget *parentGraphWidget() const noexcept;
17
17
18 void setName(const QString &name);
18 void setName(const QString &name);
19 QString name() const;
19 QString name() const;
20
20
21 SqpRange range() const;
21 SqpRange range() const;
22 void setRange(double tstart, double tend);
22 void setRange(double tstart, double tend);
23 void setStart(double tstart);
23 void setStart(double tstart);
24 void setEnd(double tend);
24 void setEnd(double tend);
25
25
26 void setColor(const QColor &color);
26 void setColor(const QColor &color);
27
27
28 void setEditionEnabled(bool value);
28 void setEditionEnabled(bool value);
29 bool isEditionEnabled() const;
29 bool isEditionEnabled() const;
30
30
31 /// Moves the item at the top of its QCPLayer. It will then receive the mouse events if multiple
32 /// items are stacked on top of each others.
33 void moveToTop();
34
31 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
35 Qt::CursorShape curshorShapeForPosition(const QPoint &position) const;
32 void setHovered(bool value);
36 void setHovered(bool value);
33
37
34 /// Sets the zones which should be moved or reisized together with this zone
38 /// Sets the zones which should be moved or reisized together with this zone
35 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
39 void setAssociatedEditedZones(const QVector<VisualizationSelectionZoneItem *> &associatedZones);
36
40
37 /// Align the specified zones with this one, vertically with the left border
41 /// Align the specified zones with this one, vertically with the left border
38 bool alignZonesVerticallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
42 bool alignZonesVerticallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
39 bool allowResize);
43 bool allowResize);
40 /// Align the specified zones with this one, vertically with the right border
44 /// Align the specified zones with this one, vertically with the right border
41 bool alignZonesVerticallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
45 bool alignZonesVerticallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
42 bool allowResize);
46 bool allowResize);
43 /// Align the specified zones with this one, temporally with the left border
47 /// Align the specified zones with this one, temporally with the left border
44 bool alignZonesTemporallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
48 bool alignZonesTemporallyOnLeft(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
45 bool allowResize);
49 bool allowResize);
46 /// Align the specified zones with this one, temporally with the right border
50 /// Align the specified zones with this one, temporally with the right border
47 bool alignZonesTemporallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
51 bool alignZonesTemporallyOnRight(const QVector<VisualizationSelectionZoneItem *> &zonesToAlign,
48 bool allowResize);
52 bool allowResize);
49
53
50 protected:
54 protected:
51 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
55 void mousePressEvent(QMouseEvent *event, const QVariant &details) override;
52 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
56 void mouseMoveEvent(QMouseEvent *event, const QPointF &startPos) override;
53 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
57 void mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos) override;
54
58
55 void resizeLeft(double pixelDiff);
59 void resizeLeft(double pixelDiff);
56 void resizeRight(double pixelDiff);
60 void resizeRight(double pixelDiff);
57 void move(double pixelDiff);
61 void move(double pixelDiff);
58
62
59 private:
63 private:
60 class VisualizationSelectionZoneItemPrivate;
64 class VisualizationSelectionZoneItemPrivate;
61 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
65 spimpl::unique_impl_ptr<VisualizationSelectionZoneItemPrivate> impl;
62 };
66 };
63
67
64 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
68 #endif // SCIQLOP_VISUALIZATIONSELECTIONZONEITEM_H
@@ -1,107 +1,110
1
1
2 gui_moc_headers = [
2 gui_moc_headers = [
3 'include/DataSource/DataSourceWidget.h',
3 'include/DataSource/DataSourceWidget.h',
4 'include/Settings/SqpSettingsDialog.h',
4 'include/Settings/SqpSettingsDialog.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
6 'include/SidePane/SqpSidePane.h',
6 'include/SidePane/SqpSidePane.h',
7 'include/SqpApplication.h',
7 'include/SqpApplication.h',
8 'include/DragAndDrop/DragDropScroller.h',
8 'include/DragAndDrop/DragDropScroller.h',
9 'include/DragAndDrop/DragDropTabSwitcher.h',
9 'include/DragAndDrop/DragDropTabSwitcher.h',
10 'include/TimeWidget/TimeWidget.h',
10 'include/TimeWidget/TimeWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
11 'include/Variable/VariableInspectorWidget.h',
12 'include/Variable/RenameVariableDialog.h',
12 'include/Variable/RenameVariableDialog.h',
13 'include/Visualization/qcustomplot.h',
13 'include/Visualization/qcustomplot.h',
14 'include/Visualization/VisualizationGraphWidget.h',
14 'include/Visualization/VisualizationGraphWidget.h',
15 'include/Visualization/VisualizationTabWidget.h',
15 'include/Visualization/VisualizationTabWidget.h',
16 'include/Visualization/VisualizationWidget.h',
16 'include/Visualization/VisualizationWidget.h',
17 'include/Visualization/VisualizationZoneWidget.h',
17 'include/Visualization/VisualizationZoneWidget.h',
18 'include/Visualization/VisualizationDragDropContainer.h',
18 'include/Visualization/VisualizationDragDropContainer.h',
19 'include/Visualization/VisualizationDragWidget.h',
19 'include/Visualization/VisualizationDragWidget.h',
20 'include/Visualization/ColorScaleEditor.h',
20 'include/Visualization/ColorScaleEditor.h',
21 'include/Visualization/SelectionZoneAction.h'
21 'include/Visualization/SelectionZoneAction.h',
22 'include/Visualization/VisualizationMultiZoneSelectionDialog.h'
22 ]
23 ]
23
24
24 gui_ui_files = [
25 gui_ui_files = [
25 'ui/DataSource/DataSourceWidget.ui',
26 'ui/DataSource/DataSourceWidget.ui',
26 'ui/Settings/SqpSettingsDialog.ui',
27 'ui/Settings/SqpSettingsDialog.ui',
27 'ui/Settings/SqpSettingsGeneralWidget.ui',
28 'ui/Settings/SqpSettingsGeneralWidget.ui',
28 'ui/SidePane/SqpSidePane.ui',
29 'ui/SidePane/SqpSidePane.ui',
29 'ui/TimeWidget/TimeWidget.ui',
30 'ui/TimeWidget/TimeWidget.ui',
30 'ui/Variable/VariableInspectorWidget.ui',
31 'ui/Variable/VariableInspectorWidget.ui',
31 'ui/Variable/RenameVariableDialog.ui',
32 'ui/Variable/RenameVariableDialog.ui',
32 'ui/Variable/VariableMenuHeaderWidget.ui',
33 'ui/Variable/VariableMenuHeaderWidget.ui',
33 'ui/Visualization/VisualizationGraphWidget.ui',
34 'ui/Visualization/VisualizationGraphWidget.ui',
34 'ui/Visualization/VisualizationTabWidget.ui',
35 'ui/Visualization/VisualizationTabWidget.ui',
35 'ui/Visualization/VisualizationWidget.ui',
36 'ui/Visualization/VisualizationWidget.ui',
36 'ui/Visualization/VisualizationZoneWidget.ui',
37 'ui/Visualization/VisualizationZoneWidget.ui',
37 'ui/Visualization/ColorScaleEditor.ui'
38 'ui/Visualization/ColorScaleEditor.ui',
39 'ui/Visualization/VisualizationMultiZoneSelectionDialog.ui'
38 ]
40 ]
39
41
40 gui_qresources = ['resources/sqpguiresources.qrc']
42 gui_qresources = ['resources/sqpguiresources.qrc']
41
43
42 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
44 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
43 ui_files : gui_ui_files,
45 ui_files : gui_ui_files,
44 qresources : gui_qresources)
46 qresources : gui_qresources)
45
47
46 gui_sources = [
48 gui_sources = [
47 'src/SqpApplication.cpp',
49 'src/SqpApplication.cpp',
48 'src/DragAndDrop/DragDropHelper.cpp',
50 'src/DragAndDrop/DragDropHelper.cpp',
49 'src/DragAndDrop/DragDropScroller.cpp',
51 'src/DragAndDrop/DragDropScroller.cpp',
50 'src/DragAndDrop/DragDropTabSwitcher.cpp',
52 'src/DragAndDrop/DragDropTabSwitcher.cpp',
51 'src/Common/ColorUtils.cpp',
53 'src/Common/ColorUtils.cpp',
52 'src/Common/VisualizationDef.cpp',
54 'src/Common/VisualizationDef.cpp',
53 'src/DataSource/DataSourceTreeWidgetItem.cpp',
55 'src/DataSource/DataSourceTreeWidgetItem.cpp',
54 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
56 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
55 'src/DataSource/DataSourceWidget.cpp',
57 'src/DataSource/DataSourceWidget.cpp',
56 'src/DataSource/DataSourceTreeWidget.cpp',
58 'src/DataSource/DataSourceTreeWidget.cpp',
57 'src/Settings/SqpSettingsDialog.cpp',
59 'src/Settings/SqpSettingsDialog.cpp',
58 'src/Settings/SqpSettingsGeneralWidget.cpp',
60 'src/Settings/SqpSettingsGeneralWidget.cpp',
59 'src/SidePane/SqpSidePane.cpp',
61 'src/SidePane/SqpSidePane.cpp',
60 'src/TimeWidget/TimeWidget.cpp',
62 'src/TimeWidget/TimeWidget.cpp',
61 'src/Variable/VariableInspectorWidget.cpp',
63 'src/Variable/VariableInspectorWidget.cpp',
62 'src/Variable/VariableInspectorTableView.cpp',
64 'src/Variable/VariableInspectorTableView.cpp',
63 'src/Variable/VariableMenuHeaderWidget.cpp',
65 'src/Variable/VariableMenuHeaderWidget.cpp',
64 'src/Variable/RenameVariableDialog.cpp',
66 'src/Variable/RenameVariableDialog.cpp',
65 'src/Visualization/VisualizationGraphHelper.cpp',
67 'src/Visualization/VisualizationGraphHelper.cpp',
66 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
68 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
67 'src/Visualization/VisualizationGraphWidget.cpp',
69 'src/Visualization/VisualizationGraphWidget.cpp',
68 'src/Visualization/VisualizationTabWidget.cpp',
70 'src/Visualization/VisualizationTabWidget.cpp',
69 'src/Visualization/VisualizationWidget.cpp',
71 'src/Visualization/VisualizationWidget.cpp',
70 'src/Visualization/VisualizationZoneWidget.cpp',
72 'src/Visualization/VisualizationZoneWidget.cpp',
71 'src/Visualization/qcustomplot.cpp',
73 'src/Visualization/qcustomplot.cpp',
72 'src/Visualization/QCustomPlotSynchronizer.cpp',
74 'src/Visualization/QCustomPlotSynchronizer.cpp',
73 'src/Visualization/operations/FindVariableOperation.cpp',
75 'src/Visualization/operations/FindVariableOperation.cpp',
74 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
76 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
75 'src/Visualization/operations/MenuBuilder.cpp',
77 'src/Visualization/operations/MenuBuilder.cpp',
76 'src/Visualization/operations/RemoveVariableOperation.cpp',
78 'src/Visualization/operations/RemoveVariableOperation.cpp',
77 'src/Visualization/operations/RescaleAxeOperation.cpp',
79 'src/Visualization/operations/RescaleAxeOperation.cpp',
78 'src/Visualization/VisualizationDragDropContainer.cpp',
80 'src/Visualization/VisualizationDragDropContainer.cpp',
79 'src/Visualization/VisualizationDragWidget.cpp',
81 'src/Visualization/VisualizationDragWidget.cpp',
80 'src/Visualization/AxisRenderingUtils.cpp',
82 'src/Visualization/AxisRenderingUtils.cpp',
81 'src/Visualization/PlottablesRenderingUtils.cpp',
83 'src/Visualization/PlottablesRenderingUtils.cpp',
82 'src/Visualization/MacScrollBarStyle.cpp',
84 'src/Visualization/MacScrollBarStyle.cpp',
83 'src/Visualization/VisualizationCursorItem.cpp',
85 'src/Visualization/VisualizationCursorItem.cpp',
84 'src/Visualization/ColorScaleEditor.cpp',
86 'src/Visualization/ColorScaleEditor.cpp',
85 'src/Visualization/SqpColorScale.cpp',
87 'src/Visualization/SqpColorScale.cpp',
86 'src/Visualization/QCPColorMapIterator.cpp',
88 'src/Visualization/QCPColorMapIterator.cpp',
87 'src/Visualization/VisualizationSelectionZoneItem.cpp',
89 'src/Visualization/VisualizationSelectionZoneItem.cpp',
88 'src/Visualization/VisualizationSelectionZoneManager.cpp',
90 'src/Visualization/VisualizationSelectionZoneManager.cpp',
89 'src/Visualization/SelectionZoneAction.cpp',
91 'src/Visualization/SelectionZoneAction.cpp',
90 'src/Visualization/ActionsGuiController.cpp',
92 'src/Visualization/ActionsGuiController.cpp',
91 'src/Visualization/VisualizationActionManager.cpp'
93 'src/Visualization/VisualizationActionManager.cpp',
94 'src/Visualization/VisualizationMultiZoneSelectionDialog.cpp'
92 ]
95 ]
93
96
94 gui_inc = include_directories(['include'])
97 gui_inc = include_directories(['include'])
95
98
96 sciqlop_gui_lib = library('sciqlopgui',
99 sciqlop_gui_lib = library('sciqlopgui',
97 gui_sources,
100 gui_sources,
98 gui_moc_files,
101 gui_moc_files,
99 include_directories : [gui_inc],
102 include_directories : [gui_inc],
100 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
103 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
101 install : true
104 install : true
102 )
105 )
103
106
104 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
107 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
105 include_directories : gui_inc,
108 include_directories : gui_inc,
106 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
109 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
107
110
@@ -1,946 +1,1004
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationMultiZoneSelectionDialog.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
11 #include "Visualization/VisualizationZoneWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
12 #include "ui_VisualizationGraphWidget.h"
12
13
13 #include <Actions/ActionsGuiController.h>
14 #include <Actions/ActionsGuiController.h>
14 #include <Common/MimeTypesDef.h>
15 #include <Common/MimeTypesDef.h>
15 #include <Data/ArrayData.h>
16 #include <Data/ArrayData.h>
16 #include <Data/IDataSeries.h>
17 #include <Data/IDataSeries.h>
17 #include <Data/SpectrogramSeries.h>
18 #include <Data/SpectrogramSeries.h>
18 #include <DragAndDrop/DragDropGuiController.h>
19 #include <DragAndDrop/DragDropGuiController.h>
19 #include <Settings/SqpSettingsDefs.h>
20 #include <Settings/SqpSettingsDefs.h>
20 #include <SqpApplication.h>
21 #include <SqpApplication.h>
21 #include <Time/TimeController.h>
22 #include <Time/TimeController.h>
22 #include <Variable/Variable.h>
23 #include <Variable/Variable.h>
23 #include <Variable/VariableController.h>
24 #include <Variable/VariableController.h>
24
25
25 #include <unordered_map>
26 #include <unordered_map>
26
27
27 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
28
29
29 namespace {
30 namespace {
30
31
31 /// Key pressed to enable drag&drop in all modes
32 /// Key pressed to enable drag&drop in all modes
32 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
33
34
34 /// Key pressed to enable zoom on horizontal axis
35 /// Key pressed to enable zoom on horizontal axis
35 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
36
37
37 /// Key pressed to enable zoom on vertical axis
38 /// Key pressed to enable zoom on vertical axis
38 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
39
40
40 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
41 const auto PAN_SPEED = 5;
42 const auto PAN_SPEED = 5;
42
43
43 /// Key pressed to enable a calibration pan
44 /// Key pressed to enable a calibration pan
44 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
45
46
46 /// Key pressed to enable multi selection of selection zones
47 /// Key pressed to enable multi selection of selection zones
47 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
48
49
49 /// Minimum size for the zoom box, in percentage of the axis range
50 /// Minimum size for the zoom box, in percentage of the axis range
50 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51 const auto ZOOM_BOX_MIN_SIZE = 0.8;
51
52
52 /// Format of the dates appearing in the label of a cursor
53 /// 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");
54 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
54
55
55 } // namespace
56 } // namespace
56
57
57 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
58
59
59 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 explicit VisualizationGraphWidgetPrivate(const QString &name)
60 : m_Name{name},
61 : m_Name{name},
61 m_DoAcquisition{true},
62 m_DoAcquisition{true},
62 m_IsCalibration{false},
63 m_IsCalibration{false},
63 m_RenderingDelegate{nullptr}
64 m_RenderingDelegate{nullptr}
64 {
65 {
65 }
66 }
66
67
67 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
68 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
68 const SqpRange &range)
69 const SqpRange &range)
69 {
70 {
70 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
71 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
71
72
72 // Prevents that data has changed to update rendering
73 // Prevents that data has changed to update rendering
73 m_RenderingDelegate->onPlotUpdated();
74 m_RenderingDelegate->onPlotUpdated();
74 }
75 }
75
76
76 QString m_Name;
77 QString m_Name;
77 // 1 variable -> n qcpplot
78 // 1 variable -> n qcpplot
78 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
79 bool m_DoAcquisition;
80 bool m_DoAcquisition;
80 bool m_IsCalibration;
81 bool m_IsCalibration;
81 /// Delegate used to attach rendering features to the plot
82 /// Delegate used to attach rendering features to the plot
82 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
83
84
84 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QCPItemRect *m_DrawingZoomRect = nullptr;
85 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
86
87
87 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
88 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
89
90
90 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
91 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
92 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
93
94
94 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
95
96
96 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
97 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
97 {
98 {
98 removeDrawingRect(plot);
99 removeDrawingRect(plot);
99
100
100 auto axisPos = posToAxisPos(pos, plot);
101 auto axisPos = posToAxisPos(pos, plot);
101
102
102 m_DrawingZoomRect = new QCPItemRect{&plot};
103 m_DrawingZoomRect = new QCPItemRect{&plot};
103 QPen p;
104 QPen p;
104 p.setWidth(2);
105 p.setWidth(2);
105 m_DrawingZoomRect->setPen(p);
106 m_DrawingZoomRect->setPen(p);
106
107
107 m_DrawingZoomRect->topLeft->setCoords(axisPos);
108 m_DrawingZoomRect->topLeft->setCoords(axisPos);
108 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
109 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
109 }
110 }
110
111
111 void removeDrawingRect(QCustomPlot &plot)
112 void removeDrawingRect(QCustomPlot &plot)
112 {
113 {
113 if (m_DrawingZoomRect) {
114 if (m_DrawingZoomRect) {
114 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
115 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
115 m_DrawingZoomRect = nullptr;
116 m_DrawingZoomRect = nullptr;
116 plot.replot(QCustomPlot::rpQueuedReplot);
117 plot.replot(QCustomPlot::rpQueuedReplot);
117 }
118 }
118 }
119 }
119
120
120 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
121 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
121 {
122 {
122 endDrawingZone(graph);
123 endDrawingZone(graph);
123
124
124 auto axisPos = posToAxisPos(pos, graph->plot());
125 auto axisPos = posToAxisPos(pos, graph->plot());
125
126
126 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
127 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
127 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
128 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
128 m_DrawingZone->setEditionEnabled(false);
129 m_DrawingZone->setEditionEnabled(false);
129 }
130 }
130
131
131 void endDrawingZone(VisualizationGraphWidget *graph)
132 void endDrawingZone(VisualizationGraphWidget *graph)
132 {
133 {
133 if (m_DrawingZone) {
134 if (m_DrawingZone) {
134 auto drawingZoneRange = m_DrawingZone->range();
135 auto drawingZoneRange = m_DrawingZone->range();
135 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
136 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
136 m_DrawingZone->setEditionEnabled(true);
137 m_DrawingZone->setEditionEnabled(true);
137 addSelectionZone(m_DrawingZone);
138 addSelectionZone(m_DrawingZone);
138 }
139 }
139 else {
140 else {
140 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
141 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
141 }
142 }
142
143
143 graph->plot().replot(QCustomPlot::rpQueuedReplot);
144 graph->plot().replot(QCustomPlot::rpQueuedReplot);
144 m_DrawingZone = nullptr;
145 m_DrawingZone = nullptr;
145 }
146 }
146 }
147 }
147
148
148 void setSelectionZonesEditionEnabled(bool value)
149 void setSelectionZonesEditionEnabled(bool value)
149 {
150 {
150 for (auto s : m_SelectionZones) {
151 for (auto s : m_SelectionZones) {
151 s->setEditionEnabled(value);
152 s->setEditionEnabled(value);
152 }
153 }
153 }
154 }
154
155
155 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
156 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
156
157
157 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
158 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
158 const QCustomPlot &plot) const
159 const QCustomPlot &plot) const
159 {
160 {
160 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
161 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
161 auto minDistanceToZone = -1;
162 auto minDistanceToZone = -1;
162 for (auto zone : m_SelectionZones) {
163 for (auto zone : m_SelectionZones) {
163 auto distanceToZone = zone->selectTest(pos, false);
164 auto distanceToZone = zone->selectTest(pos, false);
164 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
165 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
165 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
166 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
166 selectionZoneItemUnderCursor = zone;
167 selectionZoneItemUnderCursor = zone;
167 }
168 }
168 }
169 }
169
170
170 return selectionZoneItemUnderCursor;
171 return selectionZoneItemUnderCursor;
171 }
172 }
172
173
174 QVector<VisualizationSelectionZoneItem *> selectionZonesAt(const QPoint &pos,
175 const QCustomPlot &plot) const
176 {
177 QVector<VisualizationSelectionZoneItem *> zones;
178 for (auto zone : m_SelectionZones) {
179 auto distanceToZone = zone->selectTest(pos, false);
180 if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
181 zones << zone;
182 }
183 }
184
185 return zones;
186 }
187
188 void moveSelectionZoneOnTop(VisualizationSelectionZoneItem *zone, QCustomPlot &plot)
189 {
190 if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) {
191 zone->moveToTop();
192 m_SelectionZones.removeAll(zone);
193 m_SelectionZones.append(zone);
194 }
195 }
196
173 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
197 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
174 {
198 {
175 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
199 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
176 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
200 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
177 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
201 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
178 }
202 }
179
203
180 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
204 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
181 {
205 {
182 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
206 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
183 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
207 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
184 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
208 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
185 }
209 }
186 };
210 };
187
211
188 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
212 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
189 : VisualizationDragWidget{parent},
213 : VisualizationDragWidget{parent},
190 ui{new Ui::VisualizationGraphWidget},
214 ui{new Ui::VisualizationGraphWidget},
191 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
215 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
192 {
216 {
193 ui->setupUi(this);
217 ui->setupUi(this);
194
218
195 // 'Close' options : widget is deleted when closed
219 // 'Close' options : widget is deleted when closed
196 setAttribute(Qt::WA_DeleteOnClose);
220 setAttribute(Qt::WA_DeleteOnClose);
197
221
198 // Set qcpplot properties :
222 // Set qcpplot properties :
199 // - zoom is enabled
223 // - zoom is enabled
200 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
224 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
201 ui->widget->setInteractions(QCP::iRangeZoom);
225 ui->widget->setInteractions(QCP::iRangeZoom);
202 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
226 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
203
227
204 // The delegate must be initialized after the ui as it uses the plot
228 // The delegate must be initialized after the ui as it uses the plot
205 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
229 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
206
230
207 // Init the cursors
231 // Init the cursors
208 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
232 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
209 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
233 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
210 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
234 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
211 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
235 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
212
236
213 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
237 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
214 connect(ui->widget, &QCustomPlot::mouseRelease, this,
238 connect(ui->widget, &QCustomPlot::mouseRelease, this,
215 &VisualizationGraphWidget::onMouseRelease);
239 &VisualizationGraphWidget::onMouseRelease);
216 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
240 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
217 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
241 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
218 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
242 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
219 &VisualizationGraphWidget::onMouseDoubleClick);
243 &VisualizationGraphWidget::onMouseDoubleClick);
220 connect(
244 connect(
221 ui->widget->xAxis,
245 ui->widget->xAxis,
222 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
246 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
223 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
247 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
224
248
225 // Activates menu when right clicking on the graph
249 // Activates menu when right clicking on the graph
226 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
250 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
227 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
251 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
228 &VisualizationGraphWidget::onGraphMenuRequested);
252 &VisualizationGraphWidget::onGraphMenuRequested);
229
253
230 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
254 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
231 &VariableController::onRequestDataLoading);
255 &VariableController::onRequestDataLoading);
232
256
233 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
257 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
234 &VisualizationGraphWidget::onUpdateVarDisplaying);
258 &VisualizationGraphWidget::onUpdateVarDisplaying);
235
259
236 #ifdef Q_OS_MAC
260 #ifdef Q_OS_MAC
237 plot().setPlottingHint(QCP::phFastPolylines, true);
261 plot().setPlottingHint(QCP::phFastPolylines, true);
238 #endif
262 #endif
239 }
263 }
240
264
241
265
242 VisualizationGraphWidget::~VisualizationGraphWidget()
266 VisualizationGraphWidget::~VisualizationGraphWidget()
243 {
267 {
244 delete ui;
268 delete ui;
245 }
269 }
246
270
247 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
271 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
248 {
272 {
249 auto parent = parentWidget();
273 auto parent = parentWidget();
250 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
274 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
251 parent = parent->parentWidget();
275 parent = parent->parentWidget();
252 }
276 }
253
277
254 return qobject_cast<VisualizationZoneWidget *>(parent);
278 return qobject_cast<VisualizationZoneWidget *>(parent);
255 }
279 }
256
280
257 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
281 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
258 {
282 {
259 auto parent = parentWidget();
283 auto parent = parentWidget();
260 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
284 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
261 parent = parent->parentWidget();
285 parent = parent->parentWidget();
262 }
286 }
263
287
264 return qobject_cast<VisualizationWidget *>(parent);
288 return qobject_cast<VisualizationWidget *>(parent);
265 }
289 }
266
290
267 void VisualizationGraphWidget::enableAcquisition(bool enable)
291 void VisualizationGraphWidget::enableAcquisition(bool enable)
268 {
292 {
269 impl->m_DoAcquisition = enable;
293 impl->m_DoAcquisition = enable;
270 }
294 }
271
295
272 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
296 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
273 {
297 {
274 // Uses delegate to create the qcpplot components according to the variable
298 // Uses delegate to create the qcpplot components according to the variable
275 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
299 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
276
300
277 if (auto dataSeries = variable->dataSeries()) {
301 if (auto dataSeries = variable->dataSeries()) {
278 // Set axes properties according to the units of the data series
302 // Set axes properties according to the units of the data series
279 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
303 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
280
304
281 // Sets rendering properties for the new plottables
305 // Sets rendering properties for the new plottables
282 // Warning: this method must be called after setAxesProperties(), as it can access to some
306 // Warning: this method must be called after setAxesProperties(), as it can access to some
283 // axes properties that have to be initialized
307 // axes properties that have to be initialized
284 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
308 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
285 }
309 }
286
310
287 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
311 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
288
312
289 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
313 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
290
314
291 this->enableAcquisition(false);
315 this->enableAcquisition(false);
292 this->setGraphRange(range);
316 this->setGraphRange(range);
293 this->enableAcquisition(true);
317 this->enableAcquisition(true);
294
318
295 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
319 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
296
320
297 emit variableAdded(variable);
321 emit variableAdded(variable);
298 }
322 }
299
323
300 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
324 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
301 {
325 {
302 // Each component associated to the variable :
326 // Each component associated to the variable :
303 // - is removed from qcpplot (which deletes it)
327 // - is removed from qcpplot (which deletes it)
304 // - is no longer referenced in the map
328 // - is no longer referenced in the map
305 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
329 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
306 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
330 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
307 emit variableAboutToBeRemoved(variable);
331 emit variableAboutToBeRemoved(variable);
308
332
309 auto &plottablesMap = variableIt->second;
333 auto &plottablesMap = variableIt->second;
310
334
311 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
335 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
312 plottableIt != plottableEnd;) {
336 plottableIt != plottableEnd;) {
313 ui->widget->removePlottable(plottableIt->second);
337 ui->widget->removePlottable(plottableIt->second);
314 plottableIt = plottablesMap.erase(plottableIt);
338 plottableIt = plottablesMap.erase(plottableIt);
315 }
339 }
316
340
317 impl->m_VariableToPlotMultiMap.erase(variableIt);
341 impl->m_VariableToPlotMultiMap.erase(variableIt);
318 }
342 }
319
343
320 // Updates graph
344 // Updates graph
321 ui->widget->replot();
345 ui->widget->replot();
322 }
346 }
323
347
324 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
348 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
325 {
349 {
326 auto variables = QList<std::shared_ptr<Variable> >{};
350 auto variables = QList<std::shared_ptr<Variable> >{};
327 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
351 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
328 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
352 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
329 variables << it->first;
353 variables << it->first;
330 }
354 }
331
355
332 return variables;
356 return variables;
333 }
357 }
334
358
335 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
359 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
336 {
360 {
337 if (!variable) {
361 if (!variable) {
338 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
362 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
339 return;
363 return;
340 }
364 }
341
365
342 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
366 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
343 }
367 }
344
368
345 SqpRange VisualizationGraphWidget::graphRange() const noexcept
369 SqpRange VisualizationGraphWidget::graphRange() const noexcept
346 {
370 {
347 auto graphRange = ui->widget->xAxis->range();
371 auto graphRange = ui->widget->xAxis->range();
348 return SqpRange{graphRange.lower, graphRange.upper};
372 return SqpRange{graphRange.lower, graphRange.upper};
349 }
373 }
350
374
351 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
375 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
352 {
376 {
353 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
377 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
354 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
378 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
355 ui->widget->replot();
379 ui->widget->replot();
356 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
380 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
357 }
381 }
358
382
359 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
383 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
360 {
384 {
361 QVector<SqpRange> ranges;
385 QVector<SqpRange> ranges;
362 for (auto zone : impl->m_SelectionZones) {
386 for (auto zone : impl->m_SelectionZones) {
363 ranges << zone->range();
387 ranges << zone->range();
364 }
388 }
365
389
366 return ranges;
390 return ranges;
367 }
391 }
368
392
369 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
393 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
370 {
394 {
371 for (const auto &range : ranges) {
395 for (const auto &range : ranges) {
372 // note: ownership is transfered to QCustomPlot
396 // note: ownership is transfered to QCustomPlot
373 auto zone = new VisualizationSelectionZoneItem(&plot());
397 auto zone = new VisualizationSelectionZoneItem(&plot());
374 zone->setRange(range.m_TStart, range.m_TEnd);
398 zone->setRange(range.m_TStart, range.m_TEnd);
375 impl->addSelectionZone(zone);
399 impl->addSelectionZone(zone);
376 }
400 }
377
401
378 plot().replot(QCustomPlot::rpQueuedReplot);
402 plot().replot(QCustomPlot::rpQueuedReplot);
379 }
403 }
380
404
381 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
405 void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem *selectionZone)
382 {
406 {
383 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
407 parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false);
384
408
385 if (impl->m_HoveredZone == selectionZone) {
409 if (impl->m_HoveredZone == selectionZone) {
386 impl->m_HoveredZone = nullptr;
410 impl->m_HoveredZone = nullptr;
387 setCursor(Qt::ArrowCursor);
411 setCursor(Qt::ArrowCursor);
388 }
412 }
389
413
390 impl->m_SelectionZones.removeAll(selectionZone);
414 impl->m_SelectionZones.removeAll(selectionZone);
391 plot().removeItem(selectionZone);
415 plot().removeItem(selectionZone);
392 plot().replot(QCustomPlot::rpQueuedReplot);
416 plot().replot(QCustomPlot::rpQueuedReplot);
393 }
417 }
394
418
395 void VisualizationGraphWidget::undoZoom()
419 void VisualizationGraphWidget::undoZoom()
396 {
420 {
397 auto zoom = impl->m_ZoomStack.pop();
421 auto zoom = impl->m_ZoomStack.pop();
398 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
422 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
399 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
423 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
400
424
401 axisX->setRange(zoom.first);
425 axisX->setRange(zoom.first);
402 axisY->setRange(zoom.second);
426 axisY->setRange(zoom.second);
403
427
404 plot().replot(QCustomPlot::rpQueuedReplot);
428 plot().replot(QCustomPlot::rpQueuedReplot);
405 }
429 }
406
430
407 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
431 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
408 {
432 {
409 if (visitor) {
433 if (visitor) {
410 visitor->visit(this);
434 visitor->visit(this);
411 }
435 }
412 else {
436 else {
413 qCCritical(LOG_VisualizationGraphWidget())
437 qCCritical(LOG_VisualizationGraphWidget())
414 << tr("Can't visit widget : the visitor is null");
438 << tr("Can't visit widget : the visitor is null");
415 }
439 }
416 }
440 }
417
441
418 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
442 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
419 {
443 {
420 auto isSpectrogram = [](const auto &variable) {
444 auto isSpectrogram = [](const auto &variable) {
421 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
445 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
422 };
446 };
423
447
424 // - A spectrogram series can't be dropped on graph with existing plottables
448 // - A spectrogram series can't be dropped on graph with existing plottables
425 // - No data series can be dropped on graph with existing spectrogram series
449 // - No data series can be dropped on graph with existing spectrogram series
426 return isSpectrogram(variable)
450 return isSpectrogram(variable)
427 ? impl->m_VariableToPlotMultiMap.empty()
451 ? impl->m_VariableToPlotMultiMap.empty()
428 : std::none_of(
452 : std::none_of(
429 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
453 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
430 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
454 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
431 }
455 }
432
456
433 bool VisualizationGraphWidget::contains(const Variable &variable) const
457 bool VisualizationGraphWidget::contains(const Variable &variable) const
434 {
458 {
435 // Finds the variable among the keys of the map
459 // Finds the variable among the keys of the map
436 auto variablePtr = &variable;
460 auto variablePtr = &variable;
437 auto findVariable
461 auto findVariable
438 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
462 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
439
463
440 auto end = impl->m_VariableToPlotMultiMap.cend();
464 auto end = impl->m_VariableToPlotMultiMap.cend();
441 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
465 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
442 return it != end;
466 return it != end;
443 }
467 }
444
468
445 QString VisualizationGraphWidget::name() const
469 QString VisualizationGraphWidget::name() const
446 {
470 {
447 return impl->m_Name;
471 return impl->m_Name;
448 }
472 }
449
473
450 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
474 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
451 {
475 {
452 auto mimeData = new QMimeData;
476 auto mimeData = new QMimeData;
453
477
454 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
478 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
455 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
479 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
456 && selectionZoneItemUnderCursor) {
480 && selectionZoneItemUnderCursor) {
457 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
481 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
458 selectionZoneItemUnderCursor->range()));
482 selectionZoneItemUnderCursor->range()));
459 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
483 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
460 selectionZoneItemUnderCursor->range()));
484 selectionZoneItemUnderCursor->range()));
461 }
485 }
462 else {
486 else {
463 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
487 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
464
488
465 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
489 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
466 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
490 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
467 }
491 }
468
492
469 return mimeData;
493 return mimeData;
470 }
494 }
471
495
472 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
496 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
473 {
497 {
474 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
498 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
475 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
499 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
476 && selectionZoneItemUnderCursor) {
500 && selectionZoneItemUnderCursor) {
477
501
478 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
502 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
479 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
503 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
480
504
481 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
505 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
482 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
506 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
483 .toSize();
507 .toSize();
484
508
485 auto pixmap = QPixmap(zoneSize);
509 auto pixmap = QPixmap(zoneSize);
486 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
510 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
487
511
488 return pixmap;
512 return pixmap;
489 }
513 }
490
514
491 return QPixmap();
515 return QPixmap();
492 }
516 }
493
517
494 bool VisualizationGraphWidget::isDragAllowed() const
518 bool VisualizationGraphWidget::isDragAllowed() const
495 {
519 {
496 return true;
520 return true;
497 }
521 }
498
522
499 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
523 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
500 {
524 {
501 if (highlighted) {
525 if (highlighted) {
502 plot().setBackground(QBrush(QColor("#BBD5EE")));
526 plot().setBackground(QBrush(QColor("#BBD5EE")));
503 }
527 }
504 else {
528 else {
505 plot().setBackground(QBrush(Qt::white));
529 plot().setBackground(QBrush(Qt::white));
506 }
530 }
507
531
508 plot().update();
532 plot().update();
509 }
533 }
510
534
511 void VisualizationGraphWidget::addVerticalCursor(double time)
535 void VisualizationGraphWidget::addVerticalCursor(double time)
512 {
536 {
513 impl->m_VerticalCursor->setPosition(time);
537 impl->m_VerticalCursor->setPosition(time);
514 impl->m_VerticalCursor->setVisible(true);
538 impl->m_VerticalCursor->setVisible(true);
515
539
516 auto text
540 auto text
517 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
541 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
518 impl->m_VerticalCursor->setLabelText(text);
542 impl->m_VerticalCursor->setLabelText(text);
519 }
543 }
520
544
521 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
545 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
522 {
546 {
523 impl->m_VerticalCursor->setAbsolutePosition(position);
547 impl->m_VerticalCursor->setAbsolutePosition(position);
524 impl->m_VerticalCursor->setVisible(true);
548 impl->m_VerticalCursor->setVisible(true);
525
549
526 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
550 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
527 auto text
551 auto text
528 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
552 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
529 impl->m_VerticalCursor->setLabelText(text);
553 impl->m_VerticalCursor->setLabelText(text);
530 }
554 }
531
555
532 void VisualizationGraphWidget::removeVerticalCursor()
556 void VisualizationGraphWidget::removeVerticalCursor()
533 {
557 {
534 impl->m_VerticalCursor->setVisible(false);
558 impl->m_VerticalCursor->setVisible(false);
535 plot().replot(QCustomPlot::rpQueuedReplot);
559 plot().replot(QCustomPlot::rpQueuedReplot);
536 }
560 }
537
561
538 void VisualizationGraphWidget::addHorizontalCursor(double value)
562 void VisualizationGraphWidget::addHorizontalCursor(double value)
539 {
563 {
540 impl->m_HorizontalCursor->setPosition(value);
564 impl->m_HorizontalCursor->setPosition(value);
541 impl->m_HorizontalCursor->setVisible(true);
565 impl->m_HorizontalCursor->setVisible(true);
542 impl->m_HorizontalCursor->setLabelText(QString::number(value));
566 impl->m_HorizontalCursor->setLabelText(QString::number(value));
543 }
567 }
544
568
545 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
569 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
546 {
570 {
547 impl->m_HorizontalCursor->setAbsolutePosition(position);
571 impl->m_HorizontalCursor->setAbsolutePosition(position);
548 impl->m_HorizontalCursor->setVisible(true);
572 impl->m_HorizontalCursor->setVisible(true);
549
573
550 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
574 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
551 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
575 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
552 }
576 }
553
577
554 void VisualizationGraphWidget::removeHorizontalCursor()
578 void VisualizationGraphWidget::removeHorizontalCursor()
555 {
579 {
556 impl->m_HorizontalCursor->setVisible(false);
580 impl->m_HorizontalCursor->setVisible(false);
557 plot().replot(QCustomPlot::rpQueuedReplot);
581 plot().replot(QCustomPlot::rpQueuedReplot);
558 }
582 }
559
583
560 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
584 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
561 {
585 {
562 Q_UNUSED(event);
586 Q_UNUSED(event);
563
587
564 // Prevents that all variables will be removed from graph when it will be closed
588 // Prevents that all variables will be removed from graph when it will be closed
565 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
589 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
566 emit variableAboutToBeRemoved(variableEntry.first);
590 emit variableAboutToBeRemoved(variableEntry.first);
567 }
591 }
568 }
592 }
569
593
570 void VisualizationGraphWidget::enterEvent(QEvent *event)
594 void VisualizationGraphWidget::enterEvent(QEvent *event)
571 {
595 {
572 Q_UNUSED(event);
596 Q_UNUSED(event);
573 impl->m_RenderingDelegate->showGraphOverlay(true);
597 impl->m_RenderingDelegate->showGraphOverlay(true);
574 }
598 }
575
599
576 void VisualizationGraphWidget::leaveEvent(QEvent *event)
600 void VisualizationGraphWidget::leaveEvent(QEvent *event)
577 {
601 {
578 Q_UNUSED(event);
602 Q_UNUSED(event);
579 impl->m_RenderingDelegate->showGraphOverlay(false);
603 impl->m_RenderingDelegate->showGraphOverlay(false);
580
604
581 if (auto parentZone = parentZoneWidget()) {
605 if (auto parentZone = parentZoneWidget()) {
582 parentZone->notifyMouseLeaveGraph(this);
606 parentZone->notifyMouseLeaveGraph(this);
583 }
607 }
584 else {
608 else {
585 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
609 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
586 }
610 }
587
611
588 if (impl->m_HoveredZone) {
612 if (impl->m_HoveredZone) {
589 impl->m_HoveredZone->setHovered(false);
613 impl->m_HoveredZone->setHovered(false);
590 impl->m_HoveredZone = nullptr;
614 impl->m_HoveredZone = nullptr;
591 }
615 }
592 }
616 }
593
617
594 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
618 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
595 {
619 {
596 return *ui->widget;
620 return *ui->widget;
597 }
621 }
598
622
599 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
623 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
600 {
624 {
601 QMenu graphMenu{};
625 QMenu graphMenu{};
602
626
603 // Iterates on variables (unique keys)
627 // Iterates on variables (unique keys)
604 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
628 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
605 end = impl->m_VariableToPlotMultiMap.cend();
629 end = impl->m_VariableToPlotMultiMap.cend();
606 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
630 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
607 // 'Remove variable' action
631 // 'Remove variable' action
608 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
632 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
609 [ this, var = it->first ]() { removeVariable(var); });
633 [ this, var = it->first ]() { removeVariable(var); });
610 }
634 }
611
635
612 if (!impl->m_ZoomStack.isEmpty()) {
636 if (!impl->m_ZoomStack.isEmpty()) {
613 if (!graphMenu.isEmpty()) {
637 if (!graphMenu.isEmpty()) {
614 graphMenu.addSeparator();
638 graphMenu.addSeparator();
615 }
639 }
616
640
617 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
641 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
618 }
642 }
619
643
620 // Selection Zone Actions
644 // Selection Zone Actions
621 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
645 auto selectionZoneItem = impl->selectionZoneAt(pos, plot());
622 if (selectionZoneItem) {
646 if (selectionZoneItem) {
623 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
647 auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems();
624 selectedItems.removeAll(selectionZoneItem);
648 selectedItems.removeAll(selectionZoneItem);
625 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
649 selectedItems.prepend(selectionZoneItem); // Put the current selection zone first
626
650
627 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
651 auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions();
628 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
652 if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) {
629 graphMenu.addSeparator();
653 graphMenu.addSeparator();
630 }
654 }
631
655
632 QHash<QString, QMenu *> subMenus;
656 QHash<QString, QMenu *> subMenus;
633 QHash<QString, bool> subMenusEnabled;
657 QHash<QString, bool> subMenusEnabled;
634
658
635 for (auto zoneAction : zoneActions) {
659 for (auto zoneAction : zoneActions) {
636
660
637 auto isEnabled = zoneAction->isEnabled(selectedItems);
661 auto isEnabled = zoneAction->isEnabled(selectedItems);
638
662
639 auto menu = &graphMenu;
663 auto menu = &graphMenu;
640 for (auto subMenuName : zoneAction->subMenuList()) {
664 for (auto subMenuName : zoneAction->subMenuList()) {
641 if (!subMenus.contains(subMenuName)) {
665 if (!subMenus.contains(subMenuName)) {
642 menu = menu->addMenu(subMenuName);
666 menu = menu->addMenu(subMenuName);
643 subMenus[subMenuName] = menu;
667 subMenus[subMenuName] = menu;
644 subMenusEnabled[subMenuName] = isEnabled;
668 subMenusEnabled[subMenuName] = isEnabled;
645 }
669 }
646 else {
670 else {
647 menu = subMenus.value(subMenuName);
671 menu = subMenus.value(subMenuName);
648 if (isEnabled) {
672 if (isEnabled) {
649 // The sub menu is enabled if at least one of its actions is enabled
673 // The sub menu is enabled if at least one of its actions is enabled
650 subMenusEnabled[subMenuName] = true;
674 subMenusEnabled[subMenuName] = true;
651 }
675 }
652 }
676 }
653 }
677 }
654
678
655 auto action = menu->addAction(zoneAction->name());
679 auto action = menu->addAction(zoneAction->name());
656 action->setEnabled(isEnabled);
680 action->setEnabled(isEnabled);
657 action->setShortcut(zoneAction->displayedShortcut());
681 action->setShortcut(zoneAction->displayedShortcut());
658 QObject::connect(action, &QAction::triggered,
682 QObject::connect(action, &QAction::triggered,
659 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
683 [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); });
660 }
684 }
661
685
662 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
686 for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) {
663 it.value()->setEnabled(subMenusEnabled[it.key()]);
687 it.value()->setEnabled(subMenusEnabled[it.key()]);
664 }
688 }
665 }
689 }
666
690
667 if (!graphMenu.isEmpty()) {
691 if (!graphMenu.isEmpty()) {
668 graphMenu.exec(QCursor::pos());
692 graphMenu.exec(QCursor::pos());
669 }
693 }
670 }
694 }
671
695
672 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
696 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
673 {
697 {
674 qCDebug(LOG_VisualizationGraphWidget())
698 qCDebug(LOG_VisualizationGraphWidget())
675 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
699 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
676 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
700 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
677
701
678 auto graphRange = SqpRange{t1.lower, t1.upper};
702 auto graphRange = SqpRange{t1.lower, t1.upper};
679 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
703 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
680
704
681 if (impl->m_DoAcquisition) {
705 if (impl->m_DoAcquisition) {
682 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
706 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
683
707
684 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
708 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
685 end = impl->m_VariableToPlotMultiMap.end();
709 end = impl->m_VariableToPlotMultiMap.end();
686 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
710 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
687 variableUnderGraphVector.push_back(it->first);
711 variableUnderGraphVector.push_back(it->first);
688 }
712 }
689 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
713 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
690 !impl->m_IsCalibration);
714 !impl->m_IsCalibration);
691
715
692 if (!impl->m_IsCalibration) {
716 if (!impl->m_IsCalibration) {
693 qCDebug(LOG_VisualizationGraphWidget())
717 qCDebug(LOG_VisualizationGraphWidget())
694 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
718 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
695 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
719 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
696 emit synchronize(graphRange, oldGraphRange);
720 emit synchronize(graphRange, oldGraphRange);
697 }
721 }
698 }
722 }
699
723
700 auto pos = mapFromGlobal(QCursor::pos());
724 auto pos = mapFromGlobal(QCursor::pos());
701 auto axisPos = impl->posToAxisPos(pos, plot());
725 auto axisPos = impl->posToAxisPos(pos, plot());
702 if (auto parentZone = parentZoneWidget()) {
726 if (auto parentZone = parentZoneWidget()) {
703 if (impl->pointIsInAxisRect(axisPos, plot())) {
727 if (impl->pointIsInAxisRect(axisPos, plot())) {
704 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
728 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
705 }
729 }
706 else {
730 else {
707 parentZone->notifyMouseLeaveGraph(this);
731 parentZone->notifyMouseLeaveGraph(this);
708 }
732 }
709 }
733 }
710 else {
734 else {
711 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
735 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
712 }
736 }
713 }
737 }
714
738
715 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
739 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
716 {
740 {
717 impl->m_RenderingDelegate->onMouseDoubleClick(event);
741 impl->m_RenderingDelegate->onMouseDoubleClick(event);
718 }
742 }
719
743
720 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
744 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
721 {
745 {
722 // Handles plot rendering when mouse is moving
746 // Handles plot rendering when mouse is moving
723 impl->m_RenderingDelegate->onMouseMove(event);
747 impl->m_RenderingDelegate->onMouseMove(event);
724
748
725 auto axisPos = impl->posToAxisPos(event->pos(), plot());
749 auto axisPos = impl->posToAxisPos(event->pos(), plot());
726
750
727 // Zoom box and zone drawing
751 // Zoom box and zone drawing
728 if (impl->m_DrawingZoomRect) {
752 if (impl->m_DrawingZoomRect) {
729 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
753 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
730 }
754 }
731 else if (impl->m_DrawingZone) {
755 else if (impl->m_DrawingZone) {
732 impl->m_DrawingZone->setEnd(axisPos.x());
756 impl->m_DrawingZone->setEnd(axisPos.x());
733 }
757 }
734
758
735 // Cursor
759 // Cursor
736 if (auto parentZone = parentZoneWidget()) {
760 if (auto parentZone = parentZoneWidget()) {
737 if (impl->pointIsInAxisRect(axisPos, plot())) {
761 if (impl->pointIsInAxisRect(axisPos, plot())) {
738 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
762 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
739 }
763 }
740 else {
764 else {
741 parentZone->notifyMouseLeaveGraph(this);
765 parentZone->notifyMouseLeaveGraph(this);
742 }
766 }
743 }
767 }
744 else {
768 else {
745 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
769 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
746 }
770 }
747
771
748 // Search for the selection zone under the mouse
772 // Search for the selection zone under the mouse
749 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
773 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
750 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
774 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
751 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
775 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
752
776
753 // Sets the appropriate cursor shape
777 // Sets the appropriate cursor shape
754 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
778 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
755 setCursor(cursorShape);
779 setCursor(cursorShape);
756
780
757 // Manages the hovered zone
781 // Manages the hovered zone
758 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
782 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
759 if (impl->m_HoveredZone) {
783 if (impl->m_HoveredZone) {
760 impl->m_HoveredZone->setHovered(false);
784 impl->m_HoveredZone->setHovered(false);
761 }
785 }
762 selectionZoneItemUnderCursor->setHovered(true);
786 selectionZoneItemUnderCursor->setHovered(true);
763 impl->m_HoveredZone = selectionZoneItemUnderCursor;
787 impl->m_HoveredZone = selectionZoneItemUnderCursor;
764 plot().replot(QCustomPlot::rpQueuedReplot);
788 plot().replot(QCustomPlot::rpQueuedReplot);
765 }
789 }
766 }
790 }
767 else {
791 else {
768 // There is no zone under the mouse or the interaction mode is not "selection zones"
792 // There is no zone under the mouse or the interaction mode is not "selection zones"
769 if (impl->m_HoveredZone) {
793 if (impl->m_HoveredZone) {
770 impl->m_HoveredZone->setHovered(false);
794 impl->m_HoveredZone->setHovered(false);
771 impl->m_HoveredZone = nullptr;
795 impl->m_HoveredZone = nullptr;
772 }
796 }
773
797
774 setCursor(Qt::ArrowCursor);
798 setCursor(Qt::ArrowCursor);
775 }
799 }
776
800
777 impl->m_HasMovedMouse = true;
801 impl->m_HasMovedMouse = true;
778 VisualizationDragWidget::mouseMoveEvent(event);
802 VisualizationDragWidget::mouseMoveEvent(event);
779 }
803 }
780
804
781 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
805 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
782 {
806 {
783 auto value = event->angleDelta().x() + event->angleDelta().y();
807 auto value = event->angleDelta().x() + event->angleDelta().y();
784 if (value != 0) {
808 if (value != 0) {
785
809
786 auto direction = value > 0 ? 1.0 : -1.0;
810 auto direction = value > 0 ? 1.0 : -1.0;
787 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
811 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
788 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
812 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
789 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
813 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
790
814
791 auto zoomOrientations = QFlags<Qt::Orientation>{};
815 auto zoomOrientations = QFlags<Qt::Orientation>{};
792 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
816 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
793 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
817 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
794
818
795 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
819 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
796
820
797 if (!isZoomX && !isZoomY) {
821 if (!isZoomX && !isZoomY) {
798 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
822 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
799 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
823 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
800
824
801 axis->setRange(axis->range() + diff);
825 axis->setRange(axis->range() + diff);
802
826
803 if (plot().noAntialiasingOnDrag()) {
827 if (plot().noAntialiasingOnDrag()) {
804 plot().setNotAntialiasedElements(QCP::aeAll);
828 plot().setNotAntialiasedElements(QCP::aeAll);
805 }
829 }
806
830
807 plot().replot(QCustomPlot::rpQueuedReplot);
831 plot().replot(QCustomPlot::rpQueuedReplot);
808 }
832 }
809 }
833 }
810 }
834 }
811
835
812 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
836 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
813 {
837 {
814 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
838 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
815 auto isSelectionZoneMode
839 auto isSelectionZoneMode
816 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
840 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
817 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
841 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
818
842
819 if (!isDragDropClick && isLeftClick) {
843 if (!isDragDropClick && isLeftClick) {
820 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
844 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
821 // Starts a zoom box
845 // Starts a zoom box
822 impl->startDrawingRect(event->pos(), plot());
846 impl->startDrawingRect(event->pos(), plot());
823 }
847 }
824 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
848 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
825 // Starts a new selection zone
849 // Starts a new selection zone
826 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
850 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
827 if (!zoneAtPos) {
851 if (!zoneAtPos) {
828 impl->startDrawingZone(event->pos(), this);
852 impl->startDrawingZone(event->pos(), this);
829 }
853 }
830 }
854 }
831 }
855 }
832
856
833 // Allows mouse panning only in default mode
857 // Allows mouse panning only in default mode
834 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
858 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
835 == SqpApplication::PlotsInteractionMode::None
859 == SqpApplication::PlotsInteractionMode::None
836 && !isDragDropClick);
860 && !isDragDropClick);
837
861
838 // Allows zone edition only in selection zone mode without drag&drop
862 // Allows zone edition only in selection zone mode without drag&drop
839 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
863 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
840
864
841 // Selection / Deselection
865 // Selection / Deselection
842 if (isSelectionZoneMode) {
866 if (isSelectionZoneMode) {
843 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
867 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
844 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
868 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
845
869
846
870
847 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
871 if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected()
848 && !isMultiSelectionClick) {
872 && !isMultiSelectionClick) {
849 parentVisualizationWidget()->selectionZoneManager().select(
873 parentVisualizationWidget()->selectionZoneManager().select(
850 {selectionZoneItemUnderCursor});
874 {selectionZoneItemUnderCursor});
851 }
875 }
852 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
876 else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) {
853 parentVisualizationWidget()->selectionZoneManager().clearSelection();
877 parentVisualizationWidget()->selectionZoneManager().clearSelection();
854 }
878 }
855 else {
879 else {
856 // No selection change
880 // No selection change
857 }
881 }
858
882
859 if (selectionZoneItemUnderCursor && isLeftClick) {
883 if (selectionZoneItemUnderCursor && isLeftClick) {
860 selectionZoneItemUnderCursor->setAssociatedEditedZones(
884 selectionZoneItemUnderCursor->setAssociatedEditedZones(
861 parentVisualizationWidget()->selectionZoneManager().selectedItems());
885 parentVisualizationWidget()->selectionZoneManager().selectedItems());
862 }
886 }
863 }
887 }
864
888
865
889
866 impl->m_HasMovedMouse = false;
890 impl->m_HasMovedMouse = false;
867 VisualizationDragWidget::mousePressEvent(event);
891 VisualizationDragWidget::mousePressEvent(event);
868 }
892 }
869
893
870 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
894 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
871 {
895 {
872 if (impl->m_DrawingZoomRect) {
896 if (impl->m_DrawingZoomRect) {
873
897
874 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
898 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
875 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
899 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
876
900
877 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
901 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
878 impl->m_DrawingZoomRect->bottomRight->coords().x()};
902 impl->m_DrawingZoomRect->bottomRight->coords().x()};
879
903
880 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
904 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
881 impl->m_DrawingZoomRect->bottomRight->coords().y()};
905 impl->m_DrawingZoomRect->bottomRight->coords().y()};
882
906
883 impl->removeDrawingRect(plot());
907 impl->removeDrawingRect(plot());
884
908
885 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
909 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
886 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
910 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
887 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
911 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
888 axisX->setRange(newAxisXRange);
912 axisX->setRange(newAxisXRange);
889 axisY->setRange(newAxisYRange);
913 axisY->setRange(newAxisYRange);
890
914
891 plot().replot(QCustomPlot::rpQueuedReplot);
915 plot().replot(QCustomPlot::rpQueuedReplot);
892 }
916 }
893 }
917 }
894
918
895 impl->endDrawingZone(this);
919 impl->endDrawingZone(this);
896
920
897 impl->m_IsCalibration = false;
921 impl->m_IsCalibration = false;
898
922
899 // Selection / Deselection
923 // Selection / Deselection
900 auto isSelectionZoneMode
924 auto isSelectionZoneMode
901 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
925 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
902 if (isSelectionZoneMode) {
926 if (isSelectionZoneMode) {
903 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
927 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
904 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
928 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
905 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
929 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton
906 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
930 && !impl->m_HasMovedMouse) {
907 parentVisualizationWidget()->selectionZoneManager().select(
931
908 {selectionZoneItemUnderCursor});
932 auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot());
933 if (zonesUnderCursor.count() > 1) {
934 // There are multiple zones under the mouse.
935 // Performs the selection with a selection dialog.
936 VisualizationMultiZoneSelectionDialog dialog{this};
937 dialog.setZones(zonesUnderCursor);
938 dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20)));
939 dialog.activateWindow();
940 dialog.raise();
941 if (dialog.exec() == QDialog::Accepted) {
942 auto selection = dialog.selectedZones();
943
944 if (!isMultiSelectionClick) {
945 parentVisualizationWidget()->selectionZoneManager().clearSelection();
946 }
947
948 for (auto it = selection.cbegin(); it != selection.cend(); ++it) {
949 auto zone = it.key();
950 auto isSelected = it.value();
951 parentVisualizationWidget()->selectionZoneManager().setSelected(zone,
952 isSelected);
953
954 if (isSelected) {
955 // Puts the zone on top of the stack so it can be moved or resized
956 impl->moveSelectionZoneOnTop(zone, plot());
957 }
958 }
959 }
909 }
960 }
910 else if (!impl->m_HasMovedMouse) {
961 else {
911 parentVisualizationWidget()->selectionZoneManager().setSelected(
962 if (!isMultiSelectionClick) {
912 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
963 parentVisualizationWidget()->selectionZoneManager().select(
913 || event->button() == Qt::RightButton);
964 {selectionZoneItemUnderCursor});
965 impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot());
966 }
967 else {
968 parentVisualizationWidget()->selectionZoneManager().setSelected(
969 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
970 || event->button() == Qt::RightButton);
971 }
914 }
972 }
915 }
973 }
916 else {
974 else {
917 // No selection change
975 // No selection change
918 }
976 }
919 }
977 }
920 }
978 }
921
979
922 void VisualizationGraphWidget::onDataCacheVariableUpdated()
980 void VisualizationGraphWidget::onDataCacheVariableUpdated()
923 {
981 {
924 auto graphRange = ui->widget->xAxis->range();
982 auto graphRange = ui->widget->xAxis->range();
925 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
983 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
926
984
927 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
985 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
928 auto variable = variableEntry.first;
986 auto variable = variableEntry.first;
929 qCDebug(LOG_VisualizationGraphWidget())
987 qCDebug(LOG_VisualizationGraphWidget())
930 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
988 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
931 qCDebug(LOG_VisualizationGraphWidget())
989 qCDebug(LOG_VisualizationGraphWidget())
932 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
990 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
933 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
991 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
934 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
992 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
935 }
993 }
936 }
994 }
937 }
995 }
938
996
939 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
997 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
940 const SqpRange &range)
998 const SqpRange &range)
941 {
999 {
942 auto it = impl->m_VariableToPlotMultiMap.find(variable);
1000 auto it = impl->m_VariableToPlotMultiMap.find(variable);
943 if (it != impl->m_VariableToPlotMultiMap.end()) {
1001 if (it != impl->m_VariableToPlotMultiMap.end()) {
944 impl->updateData(it->second, variable->dataSeries(), range);
1002 impl->updateData(it->second, variable->dataSeries(), range);
945 }
1003 }
946 }
1004 }
@@ -1,433 +1,442
1 #include "Visualization/VisualizationSelectionZoneItem.h"
1 #include "Visualization/VisualizationSelectionZoneItem.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/VisualizationGraphWidget.h"
3 #include "Visualization/VisualizationSelectionZoneManager.h"
3 #include "Visualization/VisualizationSelectionZoneManager.h"
4 #include "Visualization/VisualizationWidget.h"
4 #include "Visualization/VisualizationWidget.h"
5
5
6 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
6 const QString &DEFAULT_COLOR = QStringLiteral("#E79D41");
7
7
8 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
8 struct VisualizationSelectionZoneItem::VisualizationSelectionZoneItemPrivate {
9
9
10 QCustomPlot *m_Plot;
10 QCustomPlot *m_Plot;
11 double m_T1 = 0;
11 double m_T1 = 0;
12 double m_T2 = 0;
12 double m_T2 = 0;
13 QColor m_Color;
13 QColor m_Color;
14
14
15 bool m_IsEditionEnabled = true;
15 bool m_IsEditionEnabled = true;
16 double m_MovedOrinalT1 = 0;
16 double m_MovedOrinalT1 = 0;
17 double m_MovedOrinalT2 = 0;
17 double m_MovedOrinalT2 = 0;
18
18
19 QCPItemStraightLine *m_LeftLine;
19 QCPItemStraightLine *m_LeftLine;
20 QCPItemStraightLine *m_RightLine;
20 QCPItemStraightLine *m_RightLine;
21 QCPItemText *m_NameLabelItem = nullptr;
21 QCPItemText *m_NameLabelItem = nullptr;
22
22
23 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
23 enum class EditionMode { NoEdition, ResizeLeft, ResizeRight, Move };
24 EditionMode m_CurrentEditionMode;
24 EditionMode m_CurrentEditionMode;
25
25
26 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
26 QVector<VisualizationSelectionZoneItem *> m_AssociatedEditedZones;
27
27
28 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
28 VisualizationSelectionZoneItemPrivate(QCustomPlot *plot)
29 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
29 : m_Plot(plot), m_Color(Qt::blue), m_CurrentEditionMode(EditionMode::NoEdition)
30 {
30 {
31 }
31 }
32
32
33 void updatePosition(VisualizationSelectionZoneItem *item)
33 void updatePosition(VisualizationSelectionZoneItem *item)
34 {
34 {
35 item->topLeft->setCoords(m_T1, 0);
35 item->topLeft->setCoords(m_T1, 0);
36 item->bottomRight->setCoords(m_T2, 1);
36 item->bottomRight->setCoords(m_T2, 1);
37 }
37 }
38
38
39 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
39 EditionMode getEditionMode(const QPoint &pos, const VisualizationSelectionZoneItem *zoneItem)
40 {
40 {
41 auto distanceLeft = m_LeftLine->selectTest(pos, false);
41 auto distanceLeft = m_LeftLine->selectTest(pos, false);
42 auto distanceRight = m_RightLine->selectTest(pos, false);
42 auto distanceRight = m_RightLine->selectTest(pos, false);
43 auto distance = zoneItem->selectTest(pos, false);
43 auto distance = zoneItem->selectTest(pos, false);
44
44
45 if (distanceRight <= distance) {
45 if (distanceRight <= distance) {
46 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
46 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight;
47 }
47 }
48 else if (distanceLeft <= distance) {
48 else if (distanceLeft <= distance) {
49 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
49 return VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft;
50 }
50 }
51
51
52 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
52 return VisualizationSelectionZoneItemPrivate::EditionMode::Move;
53 }
53 }
54
54
55 double pixelSizeToAxisXSize(double pixels)
55 double pixelSizeToAxisXSize(double pixels)
56 {
56 {
57 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
57 auto axis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
58 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
58 return axis->pixelToCoord(pixels) - axis->pixelToCoord(0);
59 }
59 }
60
60
61 bool alignZones(VisualizationSelectionZoneItem *referenceZone,
61 bool alignZones(VisualizationSelectionZoneItem *referenceZone,
62 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
62 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool alignOnLeft,
63 bool allowResize, bool vertically)
63 bool allowResize, bool vertically)
64 {
64 {
65 auto result = false;
65 auto result = false;
66
66
67 auto referenceTime
67 auto referenceTime
68 = alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
68 = alignOnLeft ? referenceZone->range().m_TStart : referenceZone->range().m_TEnd;
69
69
70 auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
70 auto referenceBottomAxis = m_Plot->axisRect()->axis(QCPAxis::atBottom);
71 auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
71 auto referenceVerticalPosition = referenceBottomAxis->coordToPixel(referenceTime);
72
72
73 for (auto otherZone : zonesToAlign) {
73 for (auto otherZone : zonesToAlign) {
74
74
75 auto otherZoneRange = otherZone->range();
75 auto otherZoneRange = otherZone->range();
76 auto newZoneStart = otherZoneRange.m_TStart;
76 auto newZoneStart = otherZoneRange.m_TStart;
77 auto newZoneEnd = otherZoneRange.m_TEnd;
77 auto newZoneEnd = otherZoneRange.m_TEnd;
78
78
79 auto alignedTime = referenceTime;
79 auto alignedTime = referenceTime;
80 if (vertically) {
80 if (vertically) {
81 auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
81 auto otherZoneAxis = otherZone->parentPlot()->axisRect()->axis(QCPAxis::atBottom);
82 alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
82 alignedTime = otherZoneAxis->pixelToCoord(referenceVerticalPosition);
83 }
83 }
84
84
85 if (alignOnLeft) {
85 if (alignOnLeft) {
86 newZoneStart = alignedTime;
86 newZoneStart = alignedTime;
87 if (!allowResize) {
87 if (!allowResize) {
88 newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
88 newZoneEnd = alignedTime + (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
89 }
89 }
90 }
90 }
91 else { // align on right
91 else { // align on right
92 newZoneEnd = alignedTime;
92 newZoneEnd = alignedTime;
93 if (!allowResize) {
93 if (!allowResize) {
94 newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
94 newZoneStart = alignedTime - (otherZoneRange.m_TEnd - otherZoneRange.m_TStart);
95 }
95 }
96 }
96 }
97
97
98 if (newZoneStart < newZoneEnd) {
98 if (newZoneStart < newZoneEnd) {
99 result = true;
99 result = true;
100 otherZone->setRange(newZoneStart, newZoneEnd);
100 otherZone->setRange(newZoneStart, newZoneEnd);
101 otherZone->parentPlot()->replot();
101 otherZone->parentPlot()->replot();
102 }
102 }
103 }
103 }
104
104
105 return result;
105 return result;
106 }
106 }
107 };
107 };
108
108
109 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
109 VisualizationSelectionZoneItem::VisualizationSelectionZoneItem(QCustomPlot *plot)
110 : QCPItemRect(plot),
110 : QCPItemRect(plot),
111 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
111 impl{spimpl::make_unique_impl<VisualizationSelectionZoneItemPrivate>(plot)}
112 {
112 {
113 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
113 topLeft->setTypeX(QCPItemPosition::ptPlotCoords);
114 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
114 topLeft->setTypeY(QCPItemPosition::ptAxisRectRatio);
115 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
115 bottomRight->setTypeX(QCPItemPosition::ptPlotCoords);
116 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
116 bottomRight->setTypeY(QCPItemPosition::ptAxisRectRatio);
117 setSelectable(false);
117 setSelectable(false);
118
118
119 impl->m_RightLine = new QCPItemStraightLine(plot);
119 impl->m_RightLine = new QCPItemStraightLine(plot);
120 impl->m_RightLine->point1->setParentAnchor(topRight);
120 impl->m_RightLine->point1->setParentAnchor(topRight);
121 impl->m_RightLine->point2->setParentAnchor(bottomRight);
121 impl->m_RightLine->point2->setParentAnchor(bottomRight);
122 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
122 impl->m_RightLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
123 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
123 impl->m_RightLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
124 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
124 impl->m_RightLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
125 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
125 impl->m_RightLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
126 impl->m_RightLine->setSelectable(false);
126 impl->m_RightLine->setSelectable(false);
127
127
128 impl->m_LeftLine = new QCPItemStraightLine(plot);
128 impl->m_LeftLine = new QCPItemStraightLine(plot);
129 impl->m_LeftLine->point1->setParentAnchor(topLeft);
129 impl->m_LeftLine->point1->setParentAnchor(topLeft);
130 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
130 impl->m_LeftLine->point2->setParentAnchor(bottomLeft);
131 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
131 impl->m_LeftLine->point1->setTypeX(QCPItemPosition::ptAbsolute);
132 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
132 impl->m_LeftLine->point1->setTypeY(QCPItemPosition::ptAbsolute);
133 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
133 impl->m_LeftLine->point2->setTypeX(QCPItemPosition::ptAbsolute);
134 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
134 impl->m_LeftLine->point2->setTypeY(QCPItemPosition::ptAbsolute);
135 impl->m_LeftLine->setSelectable(false);
135 impl->m_LeftLine->setSelectable(false);
136
136
137 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
137 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_RightLine,
138 &QCPItemStraightLine::setSelected);
138 &QCPItemStraightLine::setSelected);
139 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
139 connect(this, &VisualizationSelectionZoneItem::selectionChanged, impl->m_LeftLine,
140 &QCPItemStraightLine::setSelected);
140 &QCPItemStraightLine::setSelected);
141
141
142 setColor(QColor(DEFAULT_COLOR));
142 setColor(QColor(DEFAULT_COLOR));
143 }
143 }
144
144
145 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
145 VisualizationSelectionZoneItem::~VisualizationSelectionZoneItem()
146 {
146 {
147 impl->m_Plot->removeItem(impl->m_RightLine);
147 impl->m_Plot->removeItem(impl->m_RightLine);
148 impl->m_Plot->removeItem(impl->m_LeftLine);
148 impl->m_Plot->removeItem(impl->m_LeftLine);
149 }
149 }
150
150
151 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
151 VisualizationGraphWidget *VisualizationSelectionZoneItem::parentGraphWidget() const noexcept
152 {
152 {
153 auto parent = impl->m_Plot->parentWidget();
153 auto parent = impl->m_Plot->parentWidget();
154 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
154 while (parent != nullptr && !qobject_cast<VisualizationGraphWidget *>(parent)) {
155 parent = parent->parentWidget();
155 parent = parent->parentWidget();
156 }
156 }
157
157
158 return qobject_cast<VisualizationGraphWidget *>(parent);
158 return qobject_cast<VisualizationGraphWidget *>(parent);
159 }
159 }
160
160
161 void VisualizationSelectionZoneItem::setName(const QString &name)
161 void VisualizationSelectionZoneItem::setName(const QString &name)
162 {
162 {
163 if (name.isEmpty() && impl->m_NameLabelItem) {
163 if (name.isEmpty() && impl->m_NameLabelItem) {
164 impl->m_Plot->removeItem(impl->m_NameLabelItem);
164 impl->m_Plot->removeItem(impl->m_NameLabelItem);
165 impl->m_NameLabelItem = nullptr;
165 impl->m_NameLabelItem = nullptr;
166 }
166 }
167 else if (!impl->m_NameLabelItem) {
167 else if (!impl->m_NameLabelItem) {
168 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
168 impl->m_NameLabelItem = new QCPItemText(impl->m_Plot);
169 impl->m_NameLabelItem->setText(name);
169 impl->m_NameLabelItem->setText(name);
170 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
170 impl->m_NameLabelItem->setPositionAlignment(Qt::AlignHCenter | Qt::AlignTop);
171 impl->m_NameLabelItem->setColor(impl->m_Color);
171 impl->m_NameLabelItem->setColor(impl->m_Color);
172 impl->m_NameLabelItem->position->setParentAnchor(top);
172 impl->m_NameLabelItem->position->setParentAnchor(top);
173 }
173 }
174 }
174 }
175
175
176 QString VisualizationSelectionZoneItem::name() const
176 QString VisualizationSelectionZoneItem::name() const
177 {
177 {
178 if (!impl->m_NameLabelItem) {
178 if (!impl->m_NameLabelItem) {
179 return QString();
179 return QString();
180 }
180 }
181
181
182 return impl->m_NameLabelItem->text();
182 return impl->m_NameLabelItem->text();
183 }
183 }
184
184
185 SqpRange VisualizationSelectionZoneItem::range() const
185 SqpRange VisualizationSelectionZoneItem::range() const
186 {
186 {
187 SqpRange range;
187 SqpRange range;
188 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
188 range.m_TStart = impl->m_T1 <= impl->m_T2 ? impl->m_T1 : impl->m_T2;
189 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
189 range.m_TEnd = impl->m_T1 > impl->m_T2 ? impl->m_T1 : impl->m_T2;
190 return range;
190 return range;
191 }
191 }
192
192
193 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
193 void VisualizationSelectionZoneItem::setRange(double tstart, double tend)
194 {
194 {
195 impl->m_T1 = tstart;
195 impl->m_T1 = tstart;
196 impl->m_T2 = tend;
196 impl->m_T2 = tend;
197 impl->updatePosition(this);
197 impl->updatePosition(this);
198 }
198 }
199
199
200 void VisualizationSelectionZoneItem::setStart(double tstart)
200 void VisualizationSelectionZoneItem::setStart(double tstart)
201 {
201 {
202 impl->m_T1 = tstart;
202 impl->m_T1 = tstart;
203 impl->updatePosition(this);
203 impl->updatePosition(this);
204 }
204 }
205
205
206 void VisualizationSelectionZoneItem::setEnd(double tend)
206 void VisualizationSelectionZoneItem::setEnd(double tend)
207 {
207 {
208 impl->m_T2 = tend;
208 impl->m_T2 = tend;
209 impl->updatePosition(this);
209 impl->updatePosition(this);
210 }
210 }
211
211
212 void VisualizationSelectionZoneItem::setColor(const QColor &color)
212 void VisualizationSelectionZoneItem::setColor(const QColor &color)
213 {
213 {
214 impl->m_Color = color;
214 impl->m_Color = color;
215
215
216 auto brushColor = color;
216 auto brushColor = color;
217 brushColor.setAlpha(80);
217 brushColor.setAlpha(80);
218 setBrush(QBrush(brushColor));
218 setBrush(QBrush(brushColor));
219 setPen(QPen(Qt::NoPen));
219 setPen(QPen(Qt::NoPen));
220
220
221 auto selectedBrushColor = brushColor;
221 auto selectedBrushColor = brushColor;
222 selectedBrushColor.setAlpha(150);
222 selectedBrushColor.setAlpha(150);
223 setSelectedBrush(QBrush(selectedBrushColor));
223 setSelectedBrush(QBrush(selectedBrushColor));
224 setSelectedPen(QPen(Qt::NoPen));
224 setSelectedPen(QPen(Qt::NoPen));
225
225
226 auto linePen = QPen(color);
226 auto linePen = QPen(color);
227 linePen.setStyle(Qt::SolidLine);
227 linePen.setStyle(Qt::SolidLine);
228 linePen.setWidth(4);
228 linePen.setWidth(4);
229
229
230 auto selectedLinePen = linePen;
230 auto selectedLinePen = linePen;
231 selectedLinePen.setColor(color.darker(120));
231 selectedLinePen.setColor(color.darker(120));
232 selectedLinePen.setWidth(4);
232 selectedLinePen.setWidth(4);
233
233
234 impl->m_LeftLine->setPen(linePen);
234 impl->m_LeftLine->setPen(linePen);
235 impl->m_RightLine->setPen(linePen);
235 impl->m_RightLine->setPen(linePen);
236
236
237 impl->m_LeftLine->setSelectedPen(selectedLinePen);
237 impl->m_LeftLine->setSelectedPen(selectedLinePen);
238 impl->m_RightLine->setSelectedPen(selectedLinePen);
238 impl->m_RightLine->setSelectedPen(selectedLinePen);
239 }
239 }
240
240
241 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
241 void VisualizationSelectionZoneItem::setEditionEnabled(bool value)
242 {
242 {
243 impl->m_IsEditionEnabled = value;
243 impl->m_IsEditionEnabled = value;
244 setSelectable(value);
244 setSelectable(value);
245 if (!value) {
245 if (!value) {
246 setSelected(false);
246 setSelected(false);
247 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
247 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
248 }
248 }
249 }
249 }
250
250
251 bool VisualizationSelectionZoneItem::isEditionEnabled() const
251 bool VisualizationSelectionZoneItem::isEditionEnabled() const
252 {
252 {
253 return impl->m_IsEditionEnabled;
253 return impl->m_IsEditionEnabled;
254 }
254 }
255
255
256 void VisualizationSelectionZoneItem::moveToTop()
257 {
258 moveToLayer(layer(), false);
259 }
260
256 Qt::CursorShape
261 Qt::CursorShape
257 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
262 VisualizationSelectionZoneItem::curshorShapeForPosition(const QPoint &position) const
258 {
263 {
259 auto mode = impl->m_CurrentEditionMode
264 auto mode = impl->m_CurrentEditionMode
260 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
265 == VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition
261 ? impl->getEditionMode(position, this)
266 ? impl->getEditionMode(position, this)
262 : impl->m_CurrentEditionMode;
267 : impl->m_CurrentEditionMode;
263 switch (mode) {
268 switch (mode) {
264 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
269 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
265 return Qt::SizeAllCursor;
270 return Qt::SizeAllCursor;
266 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
271 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
267 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
272 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight: // fallthrough
268 return Qt::SizeHorCursor;
273 return Qt::SizeHorCursor;
269 default:
274 default:
270 return Qt::ArrowCursor;
275 return Qt::ArrowCursor;
271 }
276 }
272 }
277 }
273
278
274 void VisualizationSelectionZoneItem::setHovered(bool value)
279 void VisualizationSelectionZoneItem::setHovered(bool value)
275 {
280 {
276 if (value) {
281 if (value) {
277 auto linePen = impl->m_LeftLine->pen();
282 auto linePen = impl->m_LeftLine->pen();
278 linePen.setStyle(Qt::DotLine);
283 linePen.setStyle(Qt::DotLine);
279 linePen.setWidth(3);
284 linePen.setWidth(3);
280
285
281 auto selectedLinePen = impl->m_LeftLine->selectedPen();
286 auto selectedLinePen = impl->m_LeftLine->selectedPen();
282 ;
287 ;
283 selectedLinePen.setStyle(Qt::DotLine);
288 selectedLinePen.setStyle(Qt::DotLine);
284 selectedLinePen.setWidth(3);
289 selectedLinePen.setWidth(3);
285
290
286 impl->m_LeftLine->setPen(linePen);
291 impl->m_LeftLine->setPen(linePen);
287 impl->m_RightLine->setPen(linePen);
292 impl->m_RightLine->setPen(linePen);
288
293
289 impl->m_LeftLine->setSelectedPen(selectedLinePen);
294 impl->m_LeftLine->setSelectedPen(selectedLinePen);
290 impl->m_RightLine->setSelectedPen(selectedLinePen);
295 impl->m_RightLine->setSelectedPen(selectedLinePen);
291 }
296 }
292 else {
297 else {
293 setColor(impl->m_Color);
298 setColor(impl->m_Color);
294 }
299 }
295 }
300 }
296
301
297 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
302 void VisualizationSelectionZoneItem::setAssociatedEditedZones(
298 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
303 const QVector<VisualizationSelectionZoneItem *> &associatedZones)
299 {
304 {
300 impl->m_AssociatedEditedZones = associatedZones;
305 impl->m_AssociatedEditedZones = associatedZones;
301 impl->m_AssociatedEditedZones.removeAll(this);
306 impl->m_AssociatedEditedZones.removeAll(this);
302 }
307 }
303
308
304 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
309 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnLeft(
305 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
310 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
306 {
311 {
307 return impl->alignZones(this, zonesToAlign, true, allowResize, true);
312 return impl->alignZones(this, zonesToAlign, true, allowResize, true);
308 }
313 }
309
314
310 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
315 bool VisualizationSelectionZoneItem::alignZonesVerticallyOnRight(
311 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
316 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
312 {
317 {
313 return impl->alignZones(this, zonesToAlign, false, allowResize, true);
318 return impl->alignZones(this, zonesToAlign, false, allowResize, true);
314 }
319 }
315
320
316 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
321 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnLeft(
317 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
322 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
318 {
323 {
319 return impl->alignZones(this, zonesToAlign, true, allowResize, false);
324 return impl->alignZones(this, zonesToAlign, true, allowResize, false);
320 }
325 }
321
326
322 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
327 bool VisualizationSelectionZoneItem::alignZonesTemporallyOnRight(
323 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
328 const QVector<VisualizationSelectionZoneItem *> &zonesToAlign, bool allowResize)
324 {
329 {
325 return impl->alignZones(this, zonesToAlign, false, allowResize, false);
330 return impl->alignZones(this, zonesToAlign, false, allowResize, false);
326 }
331 }
327
332
328 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
333 void VisualizationSelectionZoneItem::mousePressEvent(QMouseEvent *event, const QVariant &details)
329 {
334 {
335 Q_UNUSED(details);
336
330 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
337 if (isEditionEnabled() && event->button() == Qt::LeftButton) {
331 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
338 impl->m_CurrentEditionMode = impl->getEditionMode(event->pos(), this);
332
339
333 impl->m_MovedOrinalT1 = impl->m_T1;
340 impl->m_MovedOrinalT1 = impl->m_T1;
334 impl->m_MovedOrinalT2 = impl->m_T2;
341 impl->m_MovedOrinalT2 = impl->m_T2;
335 for (auto associatedZone : impl->m_AssociatedEditedZones) {
342 for (auto associatedZone : impl->m_AssociatedEditedZones) {
336 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
343 associatedZone->impl->m_MovedOrinalT1 = associatedZone->impl->m_T1;
337 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
344 associatedZone->impl->m_MovedOrinalT2 = associatedZone->impl->m_T2;
338 }
345 }
339 }
346 }
340 else {
347 else {
341 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
348 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
342 event->ignore();
349 event->ignore();
343 }
350 }
344 }
351 }
345
352
346 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
353 void VisualizationSelectionZoneItem::mouseMoveEvent(QMouseEvent *event, const QPointF &startPos)
347 {
354 {
348 if (isEditionEnabled()) {
355 if (isEditionEnabled()) {
349 if (!selected()) {
356 if (!selected()) {
350 // Force the item to be selected during the edition
357 // Force the item to be selected during the edition
351 parentGraphWidget()->parentVisualizationWidget()->selectionZoneManager().setSelected(
358 parentGraphWidget()->parentVisualizationWidget()->selectionZoneManager().setSelected(
352 this, true);
359 this, true);
353 }
360 }
354
361
355 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
362 auto axis = impl->m_Plot->axisRect()->axis(QCPAxis::atBottom);
356 auto pixelDiff = event->pos().x() - startPos.x();
363 auto pixelDiff = event->pos().x() - startPos.x();
357 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
364 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
358
365
359 switch (impl->m_CurrentEditionMode) {
366 switch (impl->m_CurrentEditionMode) {
360 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
367 case VisualizationSelectionZoneItemPrivate::EditionMode::Move:
361 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
368 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
362 for (auto associatedZone : impl->m_AssociatedEditedZones) {
369 for (auto associatedZone : impl->m_AssociatedEditedZones) {
363 associatedZone->move(pixelDiff);
370 associatedZone->move(pixelDiff);
364 }
371 }
365 break;
372 break;
366 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
373 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeLeft:
367 setStart(impl->m_MovedOrinalT1 + diff);
374 setStart(impl->m_MovedOrinalT1 + diff);
368 for (auto associatedZone : impl->m_AssociatedEditedZones) {
375 for (auto associatedZone : impl->m_AssociatedEditedZones) {
369 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
376 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
370 ? associatedZone->resizeLeft(pixelDiff)
377 ? associatedZone->resizeLeft(pixelDiff)
371 : associatedZone->resizeRight(pixelDiff);
378 : associatedZone->resizeRight(pixelDiff);
372 }
379 }
373 break;
380 break;
374 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
381 case VisualizationSelectionZoneItemPrivate::EditionMode::ResizeRight:
375 setEnd(impl->m_MovedOrinalT2 + diff);
382 setEnd(impl->m_MovedOrinalT2 + diff);
376 for (auto associatedZone : impl->m_AssociatedEditedZones) {
383 for (auto associatedZone : impl->m_AssociatedEditedZones) {
377 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
384 impl->m_MovedOrinalT1 < impl->m_MovedOrinalT2
378 ? associatedZone->resizeRight(pixelDiff)
385 ? associatedZone->resizeRight(pixelDiff)
379 : associatedZone->resizeLeft(pixelDiff);
386 : associatedZone->resizeLeft(pixelDiff);
380 }
387 }
381 break;
388 break;
382 default:
389 default:
383 break;
390 break;
384 }
391 }
385
392
386 for (auto associatedZone : impl->m_AssociatedEditedZones) {
393 for (auto associatedZone : impl->m_AssociatedEditedZones) {
387 associatedZone->parentPlot()->replot();
394 associatedZone->parentPlot()->replot();
388 }
395 }
389 }
396 }
390 else {
397 else {
391 event->ignore();
398 event->ignore();
392 }
399 }
393 }
400 }
394
401
395 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
402 void VisualizationSelectionZoneItem::mouseReleaseEvent(QMouseEvent *event, const QPointF &startPos)
396 {
403 {
404 Q_UNUSED(startPos);
405
397 if (isEditionEnabled()) {
406 if (isEditionEnabled()) {
398 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
407 impl->m_CurrentEditionMode = VisualizationSelectionZoneItemPrivate::EditionMode::NoEdition;
399 }
408 }
400 else {
409 else {
401 event->ignore();
410 event->ignore();
402 }
411 }
403
412
404 impl->m_AssociatedEditedZones.clear();
413 impl->m_AssociatedEditedZones.clear();
405 }
414 }
406
415
407 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
416 void VisualizationSelectionZoneItem::resizeLeft(double pixelDiff)
408 {
417 {
409 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
418 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
410 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
419 if (impl->m_MovedOrinalT1 <= impl->m_MovedOrinalT2) {
411 setStart(impl->m_MovedOrinalT1 + diff);
420 setStart(impl->m_MovedOrinalT1 + diff);
412 }
421 }
413 else {
422 else {
414 setEnd(impl->m_MovedOrinalT2 + diff);
423 setEnd(impl->m_MovedOrinalT2 + diff);
415 }
424 }
416 }
425 }
417
426
418 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
427 void VisualizationSelectionZoneItem::resizeRight(double pixelDiff)
419 {
428 {
420 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
429 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
421 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
430 if (impl->m_MovedOrinalT1 > impl->m_MovedOrinalT2) {
422 setStart(impl->m_MovedOrinalT1 + diff);
431 setStart(impl->m_MovedOrinalT1 + diff);
423 }
432 }
424 else {
433 else {
425 setEnd(impl->m_MovedOrinalT2 + diff);
434 setEnd(impl->m_MovedOrinalT2 + diff);
426 }
435 }
427 }
436 }
428
437
429 void VisualizationSelectionZoneItem::move(double pixelDiff)
438 void VisualizationSelectionZoneItem::move(double pixelDiff)
430 {
439 {
431 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
440 auto diff = impl->pixelSizeToAxisXSize(pixelDiff);
432 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
441 setRange(impl->m_MovedOrinalT1 + diff, impl->m_MovedOrinalT2 + diff);
433 }
442 }
@@ -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(QCustomPlot::rpQueuedReplot);
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(QCustomPlot::rpQueuedReplot);
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 }
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