##// END OF EJS Templates
Fix the close button on the graphs
trabillard -
r1053:1dd1afe40e34
parent child
Show More
@@ -1,353 +1,353
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the SciQLop Software
2 -- This file is a part of the SciQLop Software
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2017, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "MainWindow.h"
22 #include "MainWindow.h"
23 #include "ui_MainWindow.h"
23 #include "ui_MainWindow.h"
24
24
25 #include <DataSource/DataSourceController.h>
25 #include <DataSource/DataSourceController.h>
26 #include <DataSource/DataSourceWidget.h>
26 #include <DataSource/DataSourceWidget.h>
27 #include <Settings/SqpSettingsDialog.h>
27 #include <Settings/SqpSettingsDialog.h>
28 #include <Settings/SqpSettingsGeneralWidget.h>
28 #include <Settings/SqpSettingsGeneralWidget.h>
29 #include <SidePane/SqpSidePane.h>
29 #include <SidePane/SqpSidePane.h>
30 #include <SqpApplication.h>
30 #include <SqpApplication.h>
31 #include <Time/TimeController.h>
31 #include <Time/TimeController.h>
32 #include <TimeWidget/TimeWidget.h>
32 #include <TimeWidget/TimeWidget.h>
33 #include <Variable/Variable.h>
33 #include <Variable/Variable.h>
34 #include <Variable/VariableController.h>
34 #include <Variable/VariableController.h>
35 #include <Visualization/VisualizationController.h>
35 #include <Visualization/VisualizationController.h>
36
36
37 #include <QAction>
37 #include <QAction>
38 #include <QDate>
38 #include <QDate>
39 #include <QDir>
39 #include <QDir>
40 #include <QFileDialog>
40 #include <QFileDialog>
41 #include <QToolBar>
41 #include <QToolBar>
42 #include <QToolButton>
42 #include <QToolButton>
43 #include <memory.h>
43 #include <memory.h>
44
44
45 #include "iostream"
45 #include "iostream"
46
46
47 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
47 Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow")
48
48
49 namespace {
49 namespace {
50 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
50 const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0;
51 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
51 const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1;
52 const auto VIEWPLITTERINDEX = 2;
52 const auto VIEWPLITTERINDEX = 2;
53 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
53 const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3;
54 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
54 const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4;
55 }
55 }
56
56
57 class MainWindow::MainWindowPrivate {
57 class MainWindow::MainWindowPrivate {
58 public:
58 public:
59 explicit MainWindowPrivate(MainWindow *mainWindow)
59 explicit MainWindowPrivate(MainWindow *mainWindow)
60 : m_LastOpenLeftInspectorSize{},
60 : m_LastOpenLeftInspectorSize{},
61 m_LastOpenRightInspectorSize{},
61 m_LastOpenRightInspectorSize{},
62 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
62 m_GeneralSettingsWidget{new SqpSettingsGeneralWidget{mainWindow}},
63 m_SettingsDialog{new SqpSettingsDialog{mainWindow}}
63 m_SettingsDialog{new SqpSettingsDialog{mainWindow}}
64 {
64 {
65 }
65 }
66
66
67 QSize m_LastOpenLeftInspectorSize;
67 QSize m_LastOpenLeftInspectorSize;
68 QSize m_LastOpenRightInspectorSize;
68 QSize m_LastOpenRightInspectorSize;
69 /// General settings widget. MainWindow has the ownership
69 /// General settings widget. MainWindow has the ownership
70 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
70 SqpSettingsGeneralWidget *m_GeneralSettingsWidget;
71 /// Settings dialog. MainWindow has the ownership
71 /// Settings dialog. MainWindow has the ownership
72 SqpSettingsDialog *m_SettingsDialog;
72 SqpSettingsDialog *m_SettingsDialog;
73 };
73 };
74
74
75 MainWindow::MainWindow(QWidget *parent)
75 MainWindow::MainWindow(QWidget *parent)
76 : QMainWindow{parent},
76 : QMainWindow{parent},
77 m_Ui{new Ui::MainWindow},
77 m_Ui{new Ui::MainWindow},
78 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
78 impl{spimpl::make_unique_impl<MainWindowPrivate>(this)}
79 {
79 {
80 m_Ui->setupUi(this);
80 m_Ui->setupUi(this);
81
81
82 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
82 m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false);
83 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
83 m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false);
84
84
85
85
86 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
86 auto leftSidePane = m_Ui->leftInspectorSidePane->sidePane();
87 auto openLeftInspectorAction = new QAction{QIcon{
87 auto openLeftInspectorAction = new QAction{QIcon{
88 ":/icones/previous.png",
88 ":/icones/previous.png",
89 },
89 },
90 tr("Show/hide the left inspector"), this};
90 tr("Show/hide the left inspector"), this};
91
91
92
92
93 auto spacerLeftTop = new QWidget{};
93 auto spacerLeftTop = new QWidget{};
94 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
94 spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
95
95
96 auto spacerLeftBottom = new QWidget{};
96 auto spacerLeftBottom = new QWidget{};
97 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
97 spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
98
98
99 leftSidePane->addWidget(spacerLeftTop);
99 leftSidePane->addWidget(spacerLeftTop);
100 leftSidePane->addAction(openLeftInspectorAction);
100 leftSidePane->addAction(openLeftInspectorAction);
101 leftSidePane->addWidget(spacerLeftBottom);
101 leftSidePane->addWidget(spacerLeftBottom);
102
102
103
103
104 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
104 auto rightSidePane = m_Ui->rightInspectorSidePane->sidePane();
105 auto openRightInspectorAction = new QAction{QIcon{
105 auto openRightInspectorAction = new QAction{QIcon{
106 ":/icones/next.png",
106 ":/icones/next.png",
107 },
107 },
108 tr("Show/hide the right inspector"), this};
108 tr("Show/hide the right inspector"), this};
109
109
110 auto spacerRightTop = new QWidget{};
110 auto spacerRightTop = new QWidget{};
111 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
111 spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
112
112
113 auto spacerRightBottom = new QWidget{};
113 auto spacerRightBottom = new QWidget{};
114 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
114 spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
115
115
116 rightSidePane->addWidget(spacerRightTop);
116 rightSidePane->addWidget(spacerRightTop);
117 rightSidePane->addAction(openRightInspectorAction);
117 rightSidePane->addAction(openRightInspectorAction);
118 rightSidePane->addWidget(spacerRightBottom);
118 rightSidePane->addWidget(spacerRightBottom);
119
119
120 openLeftInspectorAction->setCheckable(true);
120 openLeftInspectorAction->setCheckable(true);
121 openRightInspectorAction->setCheckable(true);
121 openRightInspectorAction->setCheckable(true);
122
122
123 auto openInspector = [this](bool checked, bool right, auto action) {
123 auto openInspector = [this](bool checked, bool right, auto action) {
124
124
125 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
125 action->setIcon(QIcon{(checked xor right) ? ":/icones/next.png" : ":/icones/previous.png"});
126
126
127 auto &lastInspectorSize
127 auto &lastInspectorSize
128 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
128 = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize;
129
129
130 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
130 auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size()
131 : m_Ui->leftMainInspectorWidget->size();
131 : m_Ui->leftMainInspectorWidget->size();
132
132
133 // Update of the last opened geometry
133 // Update of the last opened geometry
134 if (checked) {
134 if (checked) {
135 lastInspectorSize = nextInspectorSize;
135 lastInspectorSize = nextInspectorSize;
136 }
136 }
137
137
138 auto startSize = lastInspectorSize;
138 auto startSize = lastInspectorSize;
139 auto endSize = startSize;
139 auto endSize = startSize;
140 endSize.setWidth(0);
140 endSize.setWidth(0);
141
141
142 auto splitterInspectorIndex
142 auto splitterInspectorIndex
143 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
143 = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX;
144
144
145 auto currentSizes = m_Ui->splitter->sizes();
145 auto currentSizes = m_Ui->splitter->sizes();
146 if (checked) {
146 if (checked) {
147 // adjust sizes individually here, e.g.
147 // adjust sizes individually here, e.g.
148 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
148 currentSizes[splitterInspectorIndex] -= lastInspectorSize.width();
149 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
149 currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width();
150 m_Ui->splitter->setSizes(currentSizes);
150 m_Ui->splitter->setSizes(currentSizes);
151 }
151 }
152 else {
152 else {
153 // adjust sizes individually here, e.g.
153 // adjust sizes individually here, e.g.
154 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
154 currentSizes[splitterInspectorIndex] += lastInspectorSize.width();
155 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
155 currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width();
156 m_Ui->splitter->setSizes(currentSizes);
156 m_Ui->splitter->setSizes(currentSizes);
157 }
157 }
158
158
159 };
159 };
160
160
161
161
162 connect(openLeftInspectorAction, &QAction::triggered,
162 connect(openLeftInspectorAction, &QAction::triggered,
163 [openInspector, openLeftInspectorAction](bool checked) {
163 [openInspector, openLeftInspectorAction](bool checked) {
164 openInspector(checked, false, openLeftInspectorAction);
164 openInspector(checked, false, openLeftInspectorAction);
165 });
165 });
166 connect(openRightInspectorAction, &QAction::triggered,
166 connect(openRightInspectorAction, &QAction::triggered,
167 [openInspector, openRightInspectorAction](bool checked) {
167 [openInspector, openRightInspectorAction](bool checked) {
168 openInspector(checked, true, openRightInspectorAction);
168 openInspector(checked, true, openRightInspectorAction);
169 });
169 });
170
170
171 // //////////////// //
171 // //////////////// //
172 // Menu and Toolbar //
172 // Menu and Toolbar //
173 // //////////////// //
173 // //////////////// //
174 this->menuBar()->addAction(tr("File"));
174 this->menuBar()->addAction(tr("File"));
175 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
175 auto toolsMenu = this->menuBar()->addMenu(tr("Tools"));
176 toolsMenu->addAction(tr("Settings..."), [this]() {
176 toolsMenu->addAction(tr("Settings..."), [this]() {
177 // Loads settings
177 // Loads settings
178 impl->m_SettingsDialog->loadSettings();
178 impl->m_SettingsDialog->loadSettings();
179
179
180 // Open settings dialog and save settings if the dialog is accepted
180 // Open settings dialog and save settings if the dialog is accepted
181 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
181 if (impl->m_SettingsDialog->exec() == QDialog::Accepted) {
182 impl->m_SettingsDialog->saveSettings();
182 impl->m_SettingsDialog->saveSettings();
183 }
183 }
184
184
185 });
185 });
186
186
187 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
187 auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar"));
188
188
189 auto timeWidget = new TimeWidget{};
189 auto timeWidget = new TimeWidget{};
190 mainToolBar->addWidget(timeWidget);
190 mainToolBar->addWidget(timeWidget);
191
191
192 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Pointer", this};
192 auto actionPointerMode = new QAction{QIcon(":/icones/pointer.png"), "Move", this};
193 actionPointerMode->setCheckable(true);
193 actionPointerMode->setCheckable(true);
194 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
194 actionPointerMode->setChecked(sqpApp->plotsInteractionMode()
195 == SqpApplication::PlotsInteractionMode::None);
195 == SqpApplication::PlotsInteractionMode::None);
196 connect(actionPointerMode, &QAction::triggered,
196 connect(actionPointerMode, &QAction::triggered,
197 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
197 []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); });
198
198
199 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
199 auto actionZoomMode = new QAction{QIcon(":/icones/zoom.png"), "Zoom", this};
200 actionZoomMode->setCheckable(true);
200 actionZoomMode->setCheckable(true);
201 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
201 actionZoomMode->setChecked(sqpApp->plotsInteractionMode()
202 == SqpApplication::PlotsInteractionMode::ZoomBox);
202 == SqpApplication::PlotsInteractionMode::ZoomBox);
203 connect(actionZoomMode, &QAction::triggered, []() {
203 connect(actionZoomMode, &QAction::triggered, []() {
204 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
204 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox);
205 });
205 });
206
206
207 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
207 auto actionOrganisationMode = new QAction{QIcon(":/icones/drag.png"), "Organize", this};
208 actionOrganisationMode->setCheckable(true);
208 actionOrganisationMode->setCheckable(true);
209 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
209 actionOrganisationMode->setChecked(sqpApp->plotsInteractionMode()
210 == SqpApplication::PlotsInteractionMode::DragAndDrop);
210 == SqpApplication::PlotsInteractionMode::DragAndDrop);
211 connect(actionOrganisationMode, &QAction::triggered, []() {
211 connect(actionOrganisationMode, &QAction::triggered, []() {
212 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
212 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop);
213 });
213 });
214
214
215 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
215 auto actionZonesMode = new QAction{QIcon(":/icones/rectangle.png"), "Zones", this};
216 actionZonesMode->setCheckable(true);
216 actionZonesMode->setCheckable(true);
217 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
217 actionZonesMode->setChecked(sqpApp->plotsInteractionMode()
218 == SqpApplication::PlotsInteractionMode::SelectionZones);
218 == SqpApplication::PlotsInteractionMode::SelectionZones);
219 connect(actionZonesMode, &QAction::triggered, []() {
219 connect(actionZonesMode, &QAction::triggered, []() {
220 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
220 sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones);
221 });
221 });
222
222
223 auto modeActionGroup = new QActionGroup{this};
223 auto modeActionGroup = new QActionGroup{this};
224 modeActionGroup->addAction(actionZoomMode);
224 modeActionGroup->addAction(actionZoomMode);
225 modeActionGroup->addAction(actionZonesMode);
225 modeActionGroup->addAction(actionZonesMode);
226 modeActionGroup->addAction(actionOrganisationMode);
226 modeActionGroup->addAction(actionOrganisationMode);
227 modeActionGroup->addAction(actionPointerMode);
227 modeActionGroup->addAction(actionPointerMode);
228 modeActionGroup->setExclusive(true);
228 modeActionGroup->setExclusive(true);
229
229
230 mainToolBar->addSeparator();
230 mainToolBar->addSeparator();
231 mainToolBar->addAction(actionPointerMode);
231 mainToolBar->addAction(actionPointerMode);
232 mainToolBar->addAction(actionZoomMode);
232 mainToolBar->addAction(actionZoomMode);
233 mainToolBar->addAction(actionOrganisationMode);
233 mainToolBar->addAction(actionOrganisationMode);
234 mainToolBar->addAction(actionZonesMode);
234 mainToolBar->addAction(actionZonesMode);
235 mainToolBar->addSeparator();
235 mainToolBar->addSeparator();
236
236
237 auto btnCursor = new QToolButton{this};
237 auto btnCursor = new QToolButton{this};
238 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
238 btnCursor->setIcon(QIcon(":/icones/cursor.png"));
239 btnCursor->setText("Cursor");
239 btnCursor->setText("Cursor");
240 btnCursor->setToolTip("Cursor");
240 btnCursor->setToolTip("Cursor");
241 btnCursor->setPopupMode(QToolButton::InstantPopup);
241 btnCursor->setPopupMode(QToolButton::InstantPopup);
242 auto cursorMenu = new QMenu("CursorMenu", this);
242 auto cursorMenu = new QMenu("CursorMenu", this);
243 btnCursor->setMenu(cursorMenu);
243 btnCursor->setMenu(cursorMenu);
244
244
245 auto noCursorAction = cursorMenu->addAction("No Cursor");
245 auto noCursorAction = cursorMenu->addAction("No Cursor");
246 noCursorAction->setCheckable(true);
246 noCursorAction->setCheckable(true);
247 noCursorAction->setChecked(sqpApp->plotsCursorMode()
247 noCursorAction->setChecked(sqpApp->plotsCursorMode()
248 == SqpApplication::PlotsCursorMode::NoCursor);
248 == SqpApplication::PlotsCursorMode::NoCursor);
249 connect(noCursorAction, &QAction::triggered,
249 connect(noCursorAction, &QAction::triggered,
250 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
250 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); });
251
251
252 cursorMenu->addSeparator();
252 cursorMenu->addSeparator();
253 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
253 auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor");
254 verticalCursorAction->setCheckable(true);
254 verticalCursorAction->setCheckable(true);
255 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
255 verticalCursorAction->setChecked(sqpApp->plotsCursorMode()
256 == SqpApplication::PlotsCursorMode::Vertical);
256 == SqpApplication::PlotsCursorMode::Vertical);
257 connect(verticalCursorAction, &QAction::triggered,
257 connect(verticalCursorAction, &QAction::triggered,
258 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
258 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); });
259
259
260 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
260 auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor");
261 temporalCursorAction->setCheckable(true);
261 temporalCursorAction->setCheckable(true);
262 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
262 temporalCursorAction->setChecked(sqpApp->plotsCursorMode()
263 == SqpApplication::PlotsCursorMode::Temporal);
263 == SqpApplication::PlotsCursorMode::Temporal);
264 connect(temporalCursorAction, &QAction::triggered,
264 connect(temporalCursorAction, &QAction::triggered,
265 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
265 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); });
266
266
267 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
267 auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor");
268 horizontalCursorAction->setCheckable(true);
268 horizontalCursorAction->setCheckable(true);
269 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
269 horizontalCursorAction->setChecked(sqpApp->plotsCursorMode()
270 == SqpApplication::PlotsCursorMode::Horizontal);
270 == SqpApplication::PlotsCursorMode::Horizontal);
271 connect(horizontalCursorAction, &QAction::triggered,
271 connect(horizontalCursorAction, &QAction::triggered,
272 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
272 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); });
273
273
274 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
274 auto crossCursorAction = cursorMenu->addAction("Cross Cursor");
275 crossCursorAction->setCheckable(true);
275 crossCursorAction->setCheckable(true);
276 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
276 crossCursorAction->setChecked(sqpApp->plotsCursorMode()
277 == SqpApplication::PlotsCursorMode::Cross);
277 == SqpApplication::PlotsCursorMode::Cross);
278 connect(crossCursorAction, &QAction::triggered,
278 connect(crossCursorAction, &QAction::triggered,
279 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
279 []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); });
280
280
281 mainToolBar->addWidget(btnCursor);
281 mainToolBar->addWidget(btnCursor);
282
282
283 auto cursorModeActionGroup = new QActionGroup{this};
283 auto cursorModeActionGroup = new QActionGroup{this};
284 cursorModeActionGroup->setExclusive(true);
284 cursorModeActionGroup->setExclusive(true);
285 cursorModeActionGroup->addAction(noCursorAction);
285 cursorModeActionGroup->addAction(noCursorAction);
286 cursorModeActionGroup->addAction(verticalCursorAction);
286 cursorModeActionGroup->addAction(verticalCursorAction);
287 cursorModeActionGroup->addAction(temporalCursorAction);
287 cursorModeActionGroup->addAction(temporalCursorAction);
288 cursorModeActionGroup->addAction(horizontalCursorAction);
288 cursorModeActionGroup->addAction(horizontalCursorAction);
289 cursorModeActionGroup->addAction(crossCursorAction);
289 cursorModeActionGroup->addAction(crossCursorAction);
290
290
291 // //////// //
291 // //////// //
292 // Settings //
292 // Settings //
293 // //////// //
293 // //////// //
294
294
295 // Registers "general settings" widget to the settings dialog
295 // Registers "general settings" widget to the settings dialog
296 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
296 impl->m_SettingsDialog->registerWidget(QStringLiteral("General"),
297 impl->m_GeneralSettingsWidget);
297 impl->m_GeneralSettingsWidget);
298
298
299 // /////////// //
299 // /////////// //
300 // Connections //
300 // Connections //
301 // /////////// //
301 // /////////// //
302
302
303 // Controllers / controllers connections
303 // Controllers / controllers connections
304 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
304 connect(&sqpApp->timeController(), SIGNAL(timeUpdated(SqpRange)), &sqpApp->variableController(),
305 SLOT(onDateTimeOnSelection(SqpRange)));
305 SLOT(onDateTimeOnSelection(SqpRange)));
306
306
307 // Widgets / controllers connections
307 // Widgets / controllers connections
308
308
309 // DataSource
309 // DataSource
310 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
310 connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem *)),
311 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
311 m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem *)));
312
312
313 // Time
313 // Time
314 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
314 connect(timeWidget, SIGNAL(timeUpdated(SqpRange)), &sqpApp->timeController(),
315 SLOT(onTimeToUpdate(SqpRange)));
315 SLOT(onTimeToUpdate(SqpRange)));
316
316
317 // Visualization
317 // Visualization
318 connect(&sqpApp->visualizationController(),
318 connect(&sqpApp->visualizationController(),
319 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
319 SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view,
320 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
320 SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>)));
321
321
322 connect(&sqpApp->visualizationController(),
322 connect(&sqpApp->visualizationController(),
323 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
323 SIGNAL(rangeChanged(std::shared_ptr<Variable>, const SqpRange &)), m_Ui->view,
324 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
324 SLOT(onRangeChanged(std::shared_ptr<Variable>, const SqpRange &)));
325
325
326 // Widgets / widgets connections
326 // Widgets / widgets connections
327
327
328 // For the following connections, we use DirectConnection to allow each widget that can
328 // For the following connections, we use DirectConnection to allow each widget that can
329 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
329 // potentially attach a menu to the variable's menu to do so before this menu is displayed.
330 // The order of connections is also important, since it determines the order in which each
330 // The order of connections is also important, since it determines the order in which each
331 // widget will attach its menu
331 // widget will attach its menu
332 connect(
332 connect(
333 m_Ui->variableInspectorWidget,
333 m_Ui->variableInspectorWidget,
334 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
334 SIGNAL(tableMenuAboutToBeDisplayed(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
335 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
335 m_Ui->view, SLOT(attachVariableMenu(QMenu *, const QVector<std::shared_ptr<Variable> > &)),
336 Qt::DirectConnection);
336 Qt::DirectConnection);
337 }
337 }
338
338
339 MainWindow::~MainWindow()
339 MainWindow::~MainWindow()
340 {
340 {
341 }
341 }
342
342
343 void MainWindow::changeEvent(QEvent *e)
343 void MainWindow::changeEvent(QEvent *e)
344 {
344 {
345 QMainWindow::changeEvent(e);
345 QMainWindow::changeEvent(e);
346 switch (e->type()) {
346 switch (e->type()) {
347 case QEvent::LanguageChange:
347 case QEvent::LanguageChange:
348 m_Ui->retranslateUi(this);
348 m_Ui->retranslateUi(this);
349 break;
349 break;
350 default:
350 default:
351 break;
351 break;
352 }
352 }
353 }
353 }
@@ -1,876 +1,876
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationCursorItem.h"
3 #include "Visualization/VisualizationCursorItem.h"
4 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationDefs.h"
5 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphHelper.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "Visualization/VisualizationGraphRenderingDelegate.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
7 #include "Visualization/VisualizationSelectionZoneItem.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
8 #include "Visualization/VisualizationSelectionZoneManager.h"
9 #include "Visualization/VisualizationWidget.h"
9 #include "Visualization/VisualizationWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
10 #include "Visualization/VisualizationZoneWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
11 #include "ui_VisualizationGraphWidget.h"
12
12
13 #include <Common/MimeTypesDef.h>
13 #include <Common/MimeTypesDef.h>
14 #include <Data/ArrayData.h>
14 #include <Data/ArrayData.h>
15 #include <Data/IDataSeries.h>
15 #include <Data/IDataSeries.h>
16 #include <Data/SpectrogramSeries.h>
16 #include <Data/SpectrogramSeries.h>
17 #include <DragAndDrop/DragDropHelper.h>
17 #include <DragAndDrop/DragDropHelper.h>
18 #include <Settings/SqpSettingsDefs.h>
18 #include <Settings/SqpSettingsDefs.h>
19 #include <SqpApplication.h>
19 #include <SqpApplication.h>
20 #include <Time/TimeController.h>
20 #include <Time/TimeController.h>
21 #include <Variable/Variable.h>
21 #include <Variable/Variable.h>
22 #include <Variable/VariableController.h>
22 #include <Variable/VariableController.h>
23
23
24 #include <unordered_map>
24 #include <unordered_map>
25
25
26 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
26 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
27
27
28 namespace {
28 namespace {
29
29
30 /// Key pressed to enable drag&drop in all modes
30 /// Key pressed to enable drag&drop in all modes
31 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
31 const auto DRAG_DROP_MODIFIER = Qt::AltModifier;
32
32
33 /// Key pressed to enable zoom on horizontal axis
33 /// Key pressed to enable zoom on horizontal axis
34 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
34 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier;
35
35
36 /// Key pressed to enable zoom on vertical axis
36 /// Key pressed to enable zoom on vertical axis
37 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
37 const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier;
38
38
39 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
39 /// Speed of a step of a wheel event for a pan, in percentage of the axis range
40 const auto PAN_SPEED = 5;
40 const auto PAN_SPEED = 5;
41
41
42 /// Key pressed to enable a calibration pan
42 /// Key pressed to enable a calibration pan
43 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
43 const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier;
44
44
45 /// Key pressed to enable multi selection of selection zones
45 /// Key pressed to enable multi selection of selection zones
46 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
46 const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier;
47
47
48 /// Minimum size for the zoom box, in percentage of the axis range
48 /// Minimum size for the zoom box, in percentage of the axis range
49 const auto ZOOM_BOX_MIN_SIZE = 0.8;
49 const auto ZOOM_BOX_MIN_SIZE = 0.8;
50
50
51 /// Format of the dates appearing in the label of a cursor
51 /// Format of the dates appearing in the label of a cursor
52 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
52 const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz");
53
53
54 } // namespace
54 } // namespace
55
55
56 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
56 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
57
57
58 explicit VisualizationGraphWidgetPrivate(const QString &name)
58 explicit VisualizationGraphWidgetPrivate(const QString &name)
59 : m_Name{name},
59 : m_Name{name},
60 m_DoAcquisition{true},
60 m_DoAcquisition{true},
61 m_IsCalibration{false},
61 m_IsCalibration{false},
62 m_RenderingDelegate{nullptr}
62 m_RenderingDelegate{nullptr}
63 {
63 {
64 }
64 }
65
65
66 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
66 void updateData(PlottablesMap &plottables, std::shared_ptr<IDataSeries> dataSeries,
67 const SqpRange &range)
67 const SqpRange &range)
68 {
68 {
69 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
69 VisualizationGraphHelper::updateData(plottables, dataSeries, range);
70
70
71 // Prevents that data has changed to update rendering
71 // Prevents that data has changed to update rendering
72 m_RenderingDelegate->onPlotUpdated();
72 m_RenderingDelegate->onPlotUpdated();
73 }
73 }
74
74
75 QString m_Name;
75 QString m_Name;
76 // 1 variable -> n qcpplot
76 // 1 variable -> n qcpplot
77 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
77 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
78 bool m_DoAcquisition;
78 bool m_DoAcquisition;
79 bool m_IsCalibration;
79 bool m_IsCalibration;
80 /// Delegate used to attach rendering features to the plot
80 /// Delegate used to attach rendering features to the plot
81 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
81 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
82
82
83 QCPItemRect *m_DrawingZoomRect = nullptr;
83 QCPItemRect *m_DrawingZoomRect = nullptr;
84 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
84 QStack<QPair<QCPRange, QCPRange> > m_ZoomStack;
85
85
86 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
86 std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr;
87 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
87 std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr;
88
88
89 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
89 VisualizationSelectionZoneItem *m_DrawingZone = nullptr;
90 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
90 VisualizationSelectionZoneItem *m_HoveredZone = nullptr;
91 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
91 QVector<VisualizationSelectionZoneItem *> m_SelectionZones;
92
92
93 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
93 bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even
94
94
95 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
95 void startDrawingRect(const QPoint &pos, QCustomPlot &plot)
96 {
96 {
97 removeDrawingRect(plot);
97 removeDrawingRect(plot);
98
98
99 auto axisPos = posToAxisPos(pos, plot);
99 auto axisPos = posToAxisPos(pos, plot);
100
100
101 m_DrawingZoomRect = new QCPItemRect{&plot};
101 m_DrawingZoomRect = new QCPItemRect{&plot};
102 QPen p;
102 QPen p;
103 p.setWidth(2);
103 p.setWidth(2);
104 m_DrawingZoomRect->setPen(p);
104 m_DrawingZoomRect->setPen(p);
105
105
106 m_DrawingZoomRect->topLeft->setCoords(axisPos);
106 m_DrawingZoomRect->topLeft->setCoords(axisPos);
107 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
107 m_DrawingZoomRect->bottomRight->setCoords(axisPos);
108 }
108 }
109
109
110 void removeDrawingRect(QCustomPlot &plot)
110 void removeDrawingRect(QCustomPlot &plot)
111 {
111 {
112 if (m_DrawingZoomRect) {
112 if (m_DrawingZoomRect) {
113 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
113 plot.removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot
114 m_DrawingZoomRect = nullptr;
114 m_DrawingZoomRect = nullptr;
115 plot.replot(QCustomPlot::rpQueuedReplot);
115 plot.replot(QCustomPlot::rpQueuedReplot);
116 }
116 }
117 }
117 }
118
118
119 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
119 void startDrawingZone(const QPoint &pos, VisualizationGraphWidget *graph)
120 {
120 {
121 endDrawingZone(graph);
121 endDrawingZone(graph);
122
122
123 auto axisPos = posToAxisPos(pos, graph->plot());
123 auto axisPos = posToAxisPos(pos, graph->plot());
124
124
125 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
125 m_DrawingZone = new VisualizationSelectionZoneItem{&graph->plot()};
126 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
126 m_DrawingZone->setRange(axisPos.x(), axisPos.x());
127 m_DrawingZone->setEditionEnabled(false);
127 m_DrawingZone->setEditionEnabled(false);
128 }
128 }
129
129
130 void endDrawingZone(VisualizationGraphWidget *graph)
130 void endDrawingZone(VisualizationGraphWidget *graph)
131 {
131 {
132 if (m_DrawingZone) {
132 if (m_DrawingZone) {
133 auto drawingZoneRange = m_DrawingZone->range();
133 auto drawingZoneRange = m_DrawingZone->range();
134 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
134 if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) {
135 m_DrawingZone->setEditionEnabled(true);
135 m_DrawingZone->setEditionEnabled(true);
136 addSelectionZone(m_DrawingZone);
136 addSelectionZone(m_DrawingZone);
137 }
137 }
138 else {
138 else {
139 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
139 graph->plot().removeItem(m_DrawingZone); // the item is deleted by QCustomPlot
140 }
140 }
141
141
142 graph->plot().replot(QCustomPlot::rpQueuedReplot);
142 graph->plot().replot(QCustomPlot::rpQueuedReplot);
143 m_DrawingZone = nullptr;
143 m_DrawingZone = nullptr;
144 }
144 }
145 }
145 }
146
146
147 void setSelectionZonesEditionEnabled(bool value)
147 void setSelectionZonesEditionEnabled(bool value)
148 {
148 {
149 for (auto s : m_SelectionZones) {
149 for (auto s : m_SelectionZones) {
150 s->setEditionEnabled(value);
150 s->setEditionEnabled(value);
151 }
151 }
152 }
152 }
153
153
154 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
154 void addSelectionZone(VisualizationSelectionZoneItem *zone) { m_SelectionZones << zone; }
155
155
156 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
156 VisualizationSelectionZoneItem *selectionZoneAt(const QPoint &pos,
157 const QCustomPlot &plot) const
157 const QCustomPlot &plot) const
158 {
158 {
159 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
159 VisualizationSelectionZoneItem *selectionZoneItemUnderCursor = nullptr;
160 auto minDistanceToZone = -1;
160 auto minDistanceToZone = -1;
161 for (auto zone : m_SelectionZones) {
161 for (auto zone : m_SelectionZones) {
162 auto distanceToZone = zone->selectTest(pos, false);
162 auto distanceToZone = zone->selectTest(pos, false);
163 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
163 if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone)
164 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
164 && distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) {
165 selectionZoneItemUnderCursor = zone;
165 selectionZoneItemUnderCursor = zone;
166 }
166 }
167 }
167 }
168
168
169 return selectionZoneItemUnderCursor;
169 return selectionZoneItemUnderCursor;
170 }
170 }
171
171
172 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
172 QPointF posToAxisPos(const QPoint &pos, QCustomPlot &plot) const
173 {
173 {
174 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
174 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
175 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
175 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
176 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
176 return QPointF{axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y())};
177 }
177 }
178
178
179 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
179 bool pointIsInAxisRect(const QPointF &axisPoint, QCustomPlot &plot) const
180 {
180 {
181 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
181 auto axisX = plot.axisRect()->axis(QCPAxis::atBottom);
182 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
182 auto axisY = plot.axisRect()->axis(QCPAxis::atLeft);
183 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
183 return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y());
184 }
184 }
185 };
185 };
186
186
187 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
187 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
188 : VisualizationDragWidget{parent},
188 : VisualizationDragWidget{parent},
189 ui{new Ui::VisualizationGraphWidget},
189 ui{new Ui::VisualizationGraphWidget},
190 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
190 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
191 {
191 {
192 ui->setupUi(this);
192 ui->setupUi(this);
193
193
194 // 'Close' options : widget is deleted when closed
194 // 'Close' options : widget is deleted when closed
195 setAttribute(Qt::WA_DeleteOnClose);
195 setAttribute(Qt::WA_DeleteOnClose);
196
196
197 // Set qcpplot properties :
197 // Set qcpplot properties :
198 // - zoom is enabled
198 // - zoom is enabled
199 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
199 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
200 ui->widget->setInteractions(QCP::iRangeZoom);
200 ui->widget->setInteractions(QCP::iRangeZoom | QCP::iSelectItems);
201 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
201 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal | Qt::Vertical);
202
202
203 // The delegate must be initialized after the ui as it uses the plot
203 // The delegate must be initialized after the ui as it uses the plot
204 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
204 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
205
205
206 // Init the cursors
206 // Init the cursors
207 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
207 impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot());
208 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
208 impl->m_HorizontalCursor->setOrientation(Qt::Horizontal);
209 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
209 impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot());
210 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
210 impl->m_VerticalCursor->setOrientation(Qt::Vertical);
211
211
212 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
212 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
213 connect(ui->widget, &QCustomPlot::mouseRelease, this,
213 connect(ui->widget, &QCustomPlot::mouseRelease, this,
214 &VisualizationGraphWidget::onMouseRelease);
214 &VisualizationGraphWidget::onMouseRelease);
215 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
215 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
216 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
216 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
217 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
217 connect(ui->widget, &QCustomPlot::mouseDoubleClick, this,
218 &VisualizationGraphWidget::onMouseDoubleClick);
218 &VisualizationGraphWidget::onMouseDoubleClick);
219 connect(
219 connect(
220 ui->widget->xAxis,
220 ui->widget->xAxis,
221 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
221 static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(&QCPAxis::rangeChanged),
222 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
222 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
223
223
224 // Activates menu when right clicking on the graph
224 // Activates menu when right clicking on the graph
225 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
225 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
226 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
226 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
227 &VisualizationGraphWidget::onGraphMenuRequested);
227 &VisualizationGraphWidget::onGraphMenuRequested);
228
228
229 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
229 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
230 &VariableController::onRequestDataLoading);
230 &VariableController::onRequestDataLoading);
231
231
232 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
232 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
233 &VisualizationGraphWidget::onUpdateVarDisplaying);
233 &VisualizationGraphWidget::onUpdateVarDisplaying);
234
234
235 #ifdef Q_OS_MAC
235 #ifdef Q_OS_MAC
236 plot().setPlottingHint(QCP::phFastPolylines, true);
236 plot().setPlottingHint(QCP::phFastPolylines, true);
237 #endif
237 #endif
238 }
238 }
239
239
240
240
241 VisualizationGraphWidget::~VisualizationGraphWidget()
241 VisualizationGraphWidget::~VisualizationGraphWidget()
242 {
242 {
243 delete ui;
243 delete ui;
244 }
244 }
245
245
246 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
246 VisualizationZoneWidget *VisualizationGraphWidget::parentZoneWidget() const noexcept
247 {
247 {
248 auto parent = parentWidget();
248 auto parent = parentWidget();
249 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
249 while (parent != nullptr && !qobject_cast<VisualizationZoneWidget *>(parent)) {
250 parent = parent->parentWidget();
250 parent = parent->parentWidget();
251 }
251 }
252
252
253 return qobject_cast<VisualizationZoneWidget *>(parent);
253 return qobject_cast<VisualizationZoneWidget *>(parent);
254 }
254 }
255
255
256 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
256 VisualizationWidget *VisualizationGraphWidget::parentVisualizationWidget() const
257 {
257 {
258 auto parent = parentWidget();
258 auto parent = parentWidget();
259 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
259 while (parent != nullptr && !qobject_cast<VisualizationWidget *>(parent)) {
260 parent = parent->parentWidget();
260 parent = parent->parentWidget();
261 }
261 }
262
262
263 return qobject_cast<VisualizationWidget *>(parent);
263 return qobject_cast<VisualizationWidget *>(parent);
264 }
264 }
265
265
266 void VisualizationGraphWidget::enableAcquisition(bool enable)
266 void VisualizationGraphWidget::enableAcquisition(bool enable)
267 {
267 {
268 impl->m_DoAcquisition = enable;
268 impl->m_DoAcquisition = enable;
269 }
269 }
270
270
271 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
271 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
272 {
272 {
273 // Uses delegate to create the qcpplot components according to the variable
273 // Uses delegate to create the qcpplot components according to the variable
274 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
274 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
275
275
276 if (auto dataSeries = variable->dataSeries()) {
276 if (auto dataSeries = variable->dataSeries()) {
277 // Set axes properties according to the units of the data series
277 // Set axes properties according to the units of the data series
278 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
278 impl->m_RenderingDelegate->setAxesProperties(dataSeries);
279
279
280 // Sets rendering properties for the new plottables
280 // Sets rendering properties for the new plottables
281 // Warning: this method must be called after setAxesProperties(), as it can access to some
281 // Warning: this method must be called after setAxesProperties(), as it can access to some
282 // axes properties that have to be initialized
282 // axes properties that have to be initialized
283 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
283 impl->m_RenderingDelegate->setPlottablesProperties(dataSeries, createdPlottables);
284 }
284 }
285
285
286 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
286 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
287
287
288 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
288 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
289
289
290 this->enableAcquisition(false);
290 this->enableAcquisition(false);
291 this->setGraphRange(range);
291 this->setGraphRange(range);
292 this->enableAcquisition(true);
292 this->enableAcquisition(true);
293
293
294 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
294 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, false);
295
295
296 emit variableAdded(variable);
296 emit variableAdded(variable);
297 }
297 }
298
298
299 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
299 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
300 {
300 {
301 // Each component associated to the variable :
301 // Each component associated to the variable :
302 // - is removed from qcpplot (which deletes it)
302 // - is removed from qcpplot (which deletes it)
303 // - is no longer referenced in the map
303 // - is no longer referenced in the map
304 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
304 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
305 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
305 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
306 emit variableAboutToBeRemoved(variable);
306 emit variableAboutToBeRemoved(variable);
307
307
308 auto &plottablesMap = variableIt->second;
308 auto &plottablesMap = variableIt->second;
309
309
310 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
310 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
311 plottableIt != plottableEnd;) {
311 plottableIt != plottableEnd;) {
312 ui->widget->removePlottable(plottableIt->second);
312 ui->widget->removePlottable(plottableIt->second);
313 plottableIt = plottablesMap.erase(plottableIt);
313 plottableIt = plottablesMap.erase(plottableIt);
314 }
314 }
315
315
316 impl->m_VariableToPlotMultiMap.erase(variableIt);
316 impl->m_VariableToPlotMultiMap.erase(variableIt);
317 }
317 }
318
318
319 // Updates graph
319 // Updates graph
320 ui->widget->replot();
320 ui->widget->replot();
321 }
321 }
322
322
323 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
323 QList<std::shared_ptr<Variable> > VisualizationGraphWidget::variables() const
324 {
324 {
325 auto variables = QList<std::shared_ptr<Variable> >{};
325 auto variables = QList<std::shared_ptr<Variable> >{};
326 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
326 for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap);
327 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
327 it != std::cend(impl->m_VariableToPlotMultiMap); ++it) {
328 variables << it->first;
328 variables << it->first;
329 }
329 }
330
330
331 return variables;
331 return variables;
332 }
332 }
333
333
334 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
334 void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable> variable)
335 {
335 {
336 if (!variable) {
336 if (!variable) {
337 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
337 qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null";
338 return;
338 return;
339 }
339 }
340
340
341 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
341 VisualizationGraphHelper::setYAxisRange(variable, *ui->widget);
342 }
342 }
343
343
344 SqpRange VisualizationGraphWidget::graphRange() const noexcept
344 SqpRange VisualizationGraphWidget::graphRange() const noexcept
345 {
345 {
346 auto graphRange = ui->widget->xAxis->range();
346 auto graphRange = ui->widget->xAxis->range();
347 return SqpRange{graphRange.lower, graphRange.upper};
347 return SqpRange{graphRange.lower, graphRange.upper};
348 }
348 }
349
349
350 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
350 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
351 {
351 {
352 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
352 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
353 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
353 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
354 ui->widget->replot();
354 ui->widget->replot();
355 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
355 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
356 }
356 }
357
357
358 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
358 QVector<SqpRange> VisualizationGraphWidget::selectionZoneRanges() const
359 {
359 {
360 QVector<SqpRange> ranges;
360 QVector<SqpRange> ranges;
361 for (auto zone : impl->m_SelectionZones) {
361 for (auto zone : impl->m_SelectionZones) {
362 ranges << zone->range();
362 ranges << zone->range();
363 }
363 }
364
364
365 return ranges;
365 return ranges;
366 }
366 }
367
367
368 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
368 void VisualizationGraphWidget::addSelectionZones(const QVector<SqpRange> &ranges)
369 {
369 {
370 for (const auto &range : ranges) {
370 for (const auto &range : ranges) {
371 // note: ownership is transfered to QCustomPlot
371 // note: ownership is transfered to QCustomPlot
372 auto zone = new VisualizationSelectionZoneItem(&plot());
372 auto zone = new VisualizationSelectionZoneItem(&plot());
373 zone->setRange(range.m_TStart, range.m_TEnd);
373 zone->setRange(range.m_TStart, range.m_TEnd);
374 impl->addSelectionZone(zone);
374 impl->addSelectionZone(zone);
375 }
375 }
376
376
377 plot().replot(QCustomPlot::rpQueuedReplot);
377 plot().replot(QCustomPlot::rpQueuedReplot);
378 }
378 }
379
379
380 void VisualizationGraphWidget::undoZoom()
380 void VisualizationGraphWidget::undoZoom()
381 {
381 {
382 auto zoom = impl->m_ZoomStack.pop();
382 auto zoom = impl->m_ZoomStack.pop();
383 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
383 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
384 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
384 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
385
385
386 axisX->setRange(zoom.first);
386 axisX->setRange(zoom.first);
387 axisY->setRange(zoom.second);
387 axisY->setRange(zoom.second);
388
388
389 plot().replot(QCustomPlot::rpQueuedReplot);
389 plot().replot(QCustomPlot::rpQueuedReplot);
390 }
390 }
391
391
392 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
392 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
393 {
393 {
394 if (visitor) {
394 if (visitor) {
395 visitor->visit(this);
395 visitor->visit(this);
396 }
396 }
397 else {
397 else {
398 qCCritical(LOG_VisualizationGraphWidget())
398 qCCritical(LOG_VisualizationGraphWidget())
399 << tr("Can't visit widget : the visitor is null");
399 << tr("Can't visit widget : the visitor is null");
400 }
400 }
401 }
401 }
402
402
403 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
403 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
404 {
404 {
405 auto isSpectrogram = [](const auto &variable) {
405 auto isSpectrogram = [](const auto &variable) {
406 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
406 return std::dynamic_pointer_cast<SpectrogramSeries>(variable.dataSeries()) != nullptr;
407 };
407 };
408
408
409 // - A spectrogram series can't be dropped on graph with existing plottables
409 // - A spectrogram series can't be dropped on graph with existing plottables
410 // - No data series can be dropped on graph with existing spectrogram series
410 // - No data series can be dropped on graph with existing spectrogram series
411 return isSpectrogram(variable)
411 return isSpectrogram(variable)
412 ? impl->m_VariableToPlotMultiMap.empty()
412 ? impl->m_VariableToPlotMultiMap.empty()
413 : std::none_of(
413 : std::none_of(
414 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
414 impl->m_VariableToPlotMultiMap.cbegin(), impl->m_VariableToPlotMultiMap.cend(),
415 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
415 [isSpectrogram](const auto &entry) { return isSpectrogram(*entry.first); });
416 }
416 }
417
417
418 bool VisualizationGraphWidget::contains(const Variable &variable) const
418 bool VisualizationGraphWidget::contains(const Variable &variable) const
419 {
419 {
420 // Finds the variable among the keys of the map
420 // Finds the variable among the keys of the map
421 auto variablePtr = &variable;
421 auto variablePtr = &variable;
422 auto findVariable
422 auto findVariable
423 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
423 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
424
424
425 auto end = impl->m_VariableToPlotMultiMap.cend();
425 auto end = impl->m_VariableToPlotMultiMap.cend();
426 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
426 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
427 return it != end;
427 return it != end;
428 }
428 }
429
429
430 QString VisualizationGraphWidget::name() const
430 QString VisualizationGraphWidget::name() const
431 {
431 {
432 return impl->m_Name;
432 return impl->m_Name;
433 }
433 }
434
434
435 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
435 QMimeData *VisualizationGraphWidget::mimeData(const QPoint &position) const
436 {
436 {
437 auto mimeData = new QMimeData;
437 auto mimeData = new QMimeData;
438
438
439 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
439 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position, plot());
440 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
440 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
441 && selectionZoneItemUnderCursor) {
441 && selectionZoneItemUnderCursor) {
442 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
442 mimeData->setData(MIME_TYPE_TIME_RANGE, TimeController::mimeDataForTimeRange(
443 selectionZoneItemUnderCursor->range()));
443 selectionZoneItemUnderCursor->range()));
444 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
444 mimeData->setData(MIME_TYPE_SELECTION_ZONE, TimeController::mimeDataForTimeRange(
445 selectionZoneItemUnderCursor->range()));
445 selectionZoneItemUnderCursor->range()));
446 }
446 }
447 else {
447 else {
448 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
448 mimeData->setData(MIME_TYPE_GRAPH, QByteArray{});
449
449
450 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
450 auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange());
451 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
451 mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData);
452 }
452 }
453
453
454 return mimeData;
454 return mimeData;
455 }
455 }
456
456
457 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
457 QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint &dragPosition)
458 {
458 {
459 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
459 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition, plot());
460 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
460 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones
461 && selectionZoneItemUnderCursor) {
461 && selectionZoneItemUnderCursor) {
462
462
463 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
463 auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition();
464 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
464 auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition();
465
465
466 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
466 auto zoneSize = QSizeF{qAbs(zoneBottomRight.x() - zoneTopLeft.x()),
467 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
467 qAbs(zoneBottomRight.y() - zoneTopLeft.y())}
468 .toSize();
468 .toSize();
469
469
470 auto pixmap = QPixmap(zoneSize);
470 auto pixmap = QPixmap(zoneSize);
471 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
471 render(&pixmap, QPoint(), QRegion{QRect{zoneTopLeft.toPoint(), zoneSize}});
472
472
473 return pixmap;
473 return pixmap;
474 }
474 }
475
475
476 return QPixmap();
476 return QPixmap();
477 }
477 }
478
478
479 bool VisualizationGraphWidget::isDragAllowed() const
479 bool VisualizationGraphWidget::isDragAllowed() const
480 {
480 {
481 return true;
481 return true;
482 }
482 }
483
483
484 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
484 void VisualizationGraphWidget::highlightForMerge(bool highlighted)
485 {
485 {
486 if (highlighted) {
486 if (highlighted) {
487 plot().setBackground(QBrush(QColor("#BBD5EE")));
487 plot().setBackground(QBrush(QColor("#BBD5EE")));
488 }
488 }
489 else {
489 else {
490 plot().setBackground(QBrush(Qt::white));
490 plot().setBackground(QBrush(Qt::white));
491 }
491 }
492
492
493 plot().update();
493 plot().update();
494 }
494 }
495
495
496 void VisualizationGraphWidget::addVerticalCursor(double time)
496 void VisualizationGraphWidget::addVerticalCursor(double time)
497 {
497 {
498 impl->m_VerticalCursor->setPosition(time);
498 impl->m_VerticalCursor->setPosition(time);
499 impl->m_VerticalCursor->setVisible(true);
499 impl->m_VerticalCursor->setVisible(true);
500
500
501 auto text
501 auto text
502 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
502 = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n');
503 impl->m_VerticalCursor->setLabelText(text);
503 impl->m_VerticalCursor->setLabelText(text);
504 }
504 }
505
505
506 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
506 void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position)
507 {
507 {
508 impl->m_VerticalCursor->setAbsolutePosition(position);
508 impl->m_VerticalCursor->setAbsolutePosition(position);
509 impl->m_VerticalCursor->setVisible(true);
509 impl->m_VerticalCursor->setVisible(true);
510
510
511 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
511 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
512 auto text
512 auto text
513 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
513 = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT);
514 impl->m_VerticalCursor->setLabelText(text);
514 impl->m_VerticalCursor->setLabelText(text);
515 }
515 }
516
516
517 void VisualizationGraphWidget::removeVerticalCursor()
517 void VisualizationGraphWidget::removeVerticalCursor()
518 {
518 {
519 impl->m_VerticalCursor->setVisible(false);
519 impl->m_VerticalCursor->setVisible(false);
520 plot().replot(QCustomPlot::rpQueuedReplot);
520 plot().replot(QCustomPlot::rpQueuedReplot);
521 }
521 }
522
522
523 void VisualizationGraphWidget::addHorizontalCursor(double value)
523 void VisualizationGraphWidget::addHorizontalCursor(double value)
524 {
524 {
525 impl->m_HorizontalCursor->setPosition(value);
525 impl->m_HorizontalCursor->setPosition(value);
526 impl->m_HorizontalCursor->setVisible(true);
526 impl->m_HorizontalCursor->setVisible(true);
527 impl->m_HorizontalCursor->setLabelText(QString::number(value));
527 impl->m_HorizontalCursor->setLabelText(QString::number(value));
528 }
528 }
529
529
530 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
530 void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position)
531 {
531 {
532 impl->m_HorizontalCursor->setAbsolutePosition(position);
532 impl->m_HorizontalCursor->setAbsolutePosition(position);
533 impl->m_HorizontalCursor->setVisible(true);
533 impl->m_HorizontalCursor->setVisible(true);
534
534
535 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
535 auto axis = plot().axisRect()->axis(QCPAxis::atLeft);
536 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
536 impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position)));
537 }
537 }
538
538
539 void VisualizationGraphWidget::removeHorizontalCursor()
539 void VisualizationGraphWidget::removeHorizontalCursor()
540 {
540 {
541 impl->m_HorizontalCursor->setVisible(false);
541 impl->m_HorizontalCursor->setVisible(false);
542 plot().replot(QCustomPlot::rpQueuedReplot);
542 plot().replot(QCustomPlot::rpQueuedReplot);
543 }
543 }
544
544
545 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
545 void VisualizationGraphWidget::closeEvent(QCloseEvent *event)
546 {
546 {
547 Q_UNUSED(event);
547 Q_UNUSED(event);
548
548
549 // Prevents that all variables will be removed from graph when it will be closed
549 // Prevents that all variables will be removed from graph when it will be closed
550 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
550 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
551 emit variableAboutToBeRemoved(variableEntry.first);
551 emit variableAboutToBeRemoved(variableEntry.first);
552 }
552 }
553 }
553 }
554
554
555 void VisualizationGraphWidget::enterEvent(QEvent *event)
555 void VisualizationGraphWidget::enterEvent(QEvent *event)
556 {
556 {
557 Q_UNUSED(event);
557 Q_UNUSED(event);
558 impl->m_RenderingDelegate->showGraphOverlay(true);
558 impl->m_RenderingDelegate->showGraphOverlay(true);
559 }
559 }
560
560
561 void VisualizationGraphWidget::leaveEvent(QEvent *event)
561 void VisualizationGraphWidget::leaveEvent(QEvent *event)
562 {
562 {
563 Q_UNUSED(event);
563 Q_UNUSED(event);
564 impl->m_RenderingDelegate->showGraphOverlay(false);
564 impl->m_RenderingDelegate->showGraphOverlay(false);
565
565
566 if (auto parentZone = parentZoneWidget()) {
566 if (auto parentZone = parentZoneWidget()) {
567 parentZone->notifyMouseLeaveGraph(this);
567 parentZone->notifyMouseLeaveGraph(this);
568 }
568 }
569 else {
569 else {
570 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
570 qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget";
571 }
571 }
572
572
573 if (impl->m_HoveredZone) {
573 if (impl->m_HoveredZone) {
574 impl->m_HoveredZone->setHovered(false);
574 impl->m_HoveredZone->setHovered(false);
575 impl->m_HoveredZone = nullptr;
575 impl->m_HoveredZone = nullptr;
576 }
576 }
577 }
577 }
578
578
579 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
579 QCustomPlot &VisualizationGraphWidget::plot() const noexcept
580 {
580 {
581 return *ui->widget;
581 return *ui->widget;
582 }
582 }
583
583
584 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
584 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
585 {
585 {
586 QMenu graphMenu{};
586 QMenu graphMenu{};
587
587
588 // Iterates on variables (unique keys)
588 // Iterates on variables (unique keys)
589 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
589 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
590 end = impl->m_VariableToPlotMultiMap.cend();
590 end = impl->m_VariableToPlotMultiMap.cend();
591 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
591 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
592 // 'Remove variable' action
592 // 'Remove variable' action
593 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
593 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
594 [ this, var = it->first ]() { removeVariable(var); });
594 [ this, var = it->first ]() { removeVariable(var); });
595 }
595 }
596
596
597 if (!impl->m_ZoomStack.isEmpty()) {
597 if (!impl->m_ZoomStack.isEmpty()) {
598 if (!graphMenu.isEmpty()) {
598 if (!graphMenu.isEmpty()) {
599 graphMenu.addSeparator();
599 graphMenu.addSeparator();
600 }
600 }
601
601
602 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
602 graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); });
603 }
603 }
604
604
605 if (!graphMenu.isEmpty()) {
605 if (!graphMenu.isEmpty()) {
606 graphMenu.exec(QCursor::pos());
606 graphMenu.exec(QCursor::pos());
607 }
607 }
608 }
608 }
609
609
610 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
610 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
611 {
611 {
612 qCDebug(LOG_VisualizationGraphWidget())
612 qCDebug(LOG_VisualizationGraphWidget())
613 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
613 << tr("TORM: VisualizationGraphWidget::onRangeChanged")
614 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
614 << QThread::currentThread()->objectName() << "DoAcqui" << impl->m_DoAcquisition;
615
615
616 auto graphRange = SqpRange{t1.lower, t1.upper};
616 auto graphRange = SqpRange{t1.lower, t1.upper};
617 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
617 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
618
618
619 if (impl->m_DoAcquisition) {
619 if (impl->m_DoAcquisition) {
620 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
620 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
621
621
622 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
622 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
623 end = impl->m_VariableToPlotMultiMap.end();
623 end = impl->m_VariableToPlotMultiMap.end();
624 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
624 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
625 variableUnderGraphVector.push_back(it->first);
625 variableUnderGraphVector.push_back(it->first);
626 }
626 }
627 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
627 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange,
628 !impl->m_IsCalibration);
628 !impl->m_IsCalibration);
629
629
630 if (!impl->m_IsCalibration) {
630 if (!impl->m_IsCalibration) {
631 qCDebug(LOG_VisualizationGraphWidget())
631 qCDebug(LOG_VisualizationGraphWidget())
632 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
632 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
633 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
633 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
634 emit synchronize(graphRange, oldGraphRange);
634 emit synchronize(graphRange, oldGraphRange);
635 }
635 }
636 }
636 }
637
637
638 auto pos = mapFromGlobal(QCursor::pos());
638 auto pos = mapFromGlobal(QCursor::pos());
639 auto axisPos = impl->posToAxisPos(pos, plot());
639 auto axisPos = impl->posToAxisPos(pos, plot());
640 if (auto parentZone = parentZoneWidget()) {
640 if (auto parentZone = parentZoneWidget()) {
641 if (impl->pointIsInAxisRect(axisPos, plot())) {
641 if (impl->pointIsInAxisRect(axisPos, plot())) {
642 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
642 parentZone->notifyMouseMoveInGraph(pos, axisPos, this);
643 }
643 }
644 else {
644 else {
645 parentZone->notifyMouseLeaveGraph(this);
645 parentZone->notifyMouseLeaveGraph(this);
646 }
646 }
647 }
647 }
648 else {
648 else {
649 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
649 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
650 }
650 }
651 }
651 }
652
652
653 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
653 void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent *event) noexcept
654 {
654 {
655 impl->m_RenderingDelegate->onMouseDoubleClick(event);
655 impl->m_RenderingDelegate->onMouseDoubleClick(event);
656 }
656 }
657
657
658 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
658 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
659 {
659 {
660 // Handles plot rendering when mouse is moving
660 // Handles plot rendering when mouse is moving
661 impl->m_RenderingDelegate->onMouseMove(event);
661 impl->m_RenderingDelegate->onMouseMove(event);
662
662
663 auto axisPos = impl->posToAxisPos(event->pos(), plot());
663 auto axisPos = impl->posToAxisPos(event->pos(), plot());
664
664
665 // Zoom box and zone drawing
665 // Zoom box and zone drawing
666 if (impl->m_DrawingZoomRect) {
666 if (impl->m_DrawingZoomRect) {
667 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
667 impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos);
668 }
668 }
669 else if (impl->m_DrawingZone) {
669 else if (impl->m_DrawingZone) {
670 impl->m_DrawingZone->setEnd(axisPos.x());
670 impl->m_DrawingZone->setEnd(axisPos.x());
671 }
671 }
672
672
673 // Cursor
673 // Cursor
674 if (auto parentZone = parentZoneWidget()) {
674 if (auto parentZone = parentZoneWidget()) {
675 if (impl->pointIsInAxisRect(axisPos, plot())) {
675 if (impl->pointIsInAxisRect(axisPos, plot())) {
676 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
676 parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this);
677 }
677 }
678 else {
678 else {
679 parentZone->notifyMouseLeaveGraph(this);
679 parentZone->notifyMouseLeaveGraph(this);
680 }
680 }
681 }
681 }
682 else {
682 else {
683 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
683 qCWarning(LOG_VisualizationGraphWidget()) << "onMouseMove: No parent zone widget";
684 }
684 }
685
685
686 // Search for the selection zone under the mouse
686 // Search for the selection zone under the mouse
687 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
687 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
688 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
688 if (selectionZoneItemUnderCursor && !impl->m_DrawingZone
689 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
689 && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) {
690
690
691 // Sets the appropriate cursor shape
691 // Sets the appropriate cursor shape
692 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
692 auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos());
693 setCursor(cursorShape);
693 setCursor(cursorShape);
694
694
695 // Manages the hovered zone
695 // Manages the hovered zone
696 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
696 if (selectionZoneItemUnderCursor != impl->m_HoveredZone) {
697 if (impl->m_HoveredZone) {
697 if (impl->m_HoveredZone) {
698 impl->m_HoveredZone->setHovered(false);
698 impl->m_HoveredZone->setHovered(false);
699 }
699 }
700 selectionZoneItemUnderCursor->setHovered(true);
700 selectionZoneItemUnderCursor->setHovered(true);
701 impl->m_HoveredZone = selectionZoneItemUnderCursor;
701 impl->m_HoveredZone = selectionZoneItemUnderCursor;
702 plot().replot(QCustomPlot::rpQueuedReplot);
702 plot().replot(QCustomPlot::rpQueuedReplot);
703 }
703 }
704 }
704 }
705 else {
705 else {
706 // There is no zone under the mouse or the interaction mode is not "selection zones"
706 // There is no zone under the mouse or the interaction mode is not "selection zones"
707 if (impl->m_HoveredZone) {
707 if (impl->m_HoveredZone) {
708 impl->m_HoveredZone->setHovered(false);
708 impl->m_HoveredZone->setHovered(false);
709 impl->m_HoveredZone = nullptr;
709 impl->m_HoveredZone = nullptr;
710 }
710 }
711
711
712 setCursor(Qt::ArrowCursor);
712 setCursor(Qt::ArrowCursor);
713 }
713 }
714
714
715 impl->m_HasMovedMouse = true;
715 impl->m_HasMovedMouse = true;
716 VisualizationDragWidget::mouseMoveEvent(event);
716 VisualizationDragWidget::mouseMoveEvent(event);
717 }
717 }
718
718
719 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
719 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
720 {
720 {
721 auto value = event->angleDelta().x() + event->angleDelta().y();
721 auto value = event->angleDelta().x() + event->angleDelta().y();
722 if (value != 0) {
722 if (value != 0) {
723
723
724 auto direction = value > 0 ? 1.0 : -1.0;
724 auto direction = value > 0 ? 1.0 : -1.0;
725 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
725 auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER);
726 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
726 auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER);
727 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
727 impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER);
728
728
729 auto zoomOrientations = QFlags<Qt::Orientation>{};
729 auto zoomOrientations = QFlags<Qt::Orientation>{};
730 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
730 zoomOrientations.setFlag(Qt::Horizontal, isZoomX);
731 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
731 zoomOrientations.setFlag(Qt::Vertical, isZoomY);
732
732
733 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
733 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
734
734
735 if (!isZoomX && !isZoomY) {
735 if (!isZoomX && !isZoomY) {
736 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
736 auto axis = plot().axisRect()->axis(QCPAxis::atBottom);
737 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
737 auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0));
738
738
739 axis->setRange(axis->range() + diff);
739 axis->setRange(axis->range() + diff);
740
740
741 if (plot().noAntialiasingOnDrag()) {
741 if (plot().noAntialiasingOnDrag()) {
742 plot().setNotAntialiasedElements(QCP::aeAll);
742 plot().setNotAntialiasedElements(QCP::aeAll);
743 }
743 }
744
744
745 plot().replot(QCustomPlot::rpQueuedReplot);
745 plot().replot(QCustomPlot::rpQueuedReplot);
746 }
746 }
747 }
747 }
748 }
748 }
749
749
750 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
750 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
751 {
751 {
752 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
752 auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER);
753 auto isSelectionZoneMode
753 auto isSelectionZoneMode
754 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
754 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
755 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
755 auto isLeftClick = event->buttons().testFlag(Qt::LeftButton);
756
756
757 if (!isDragDropClick && isLeftClick) {
757 if (!isDragDropClick && isLeftClick) {
758 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
758 if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) {
759 // Starts a zoom box
759 // Starts a zoom box
760 impl->startDrawingRect(event->pos(), plot());
760 impl->startDrawingRect(event->pos(), plot());
761 }
761 }
762 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
762 else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) {
763 // Starts a new selection zone
763 // Starts a new selection zone
764 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
764 auto zoneAtPos = impl->selectionZoneAt(event->pos(), plot());
765 if (!zoneAtPos) {
765 if (!zoneAtPos) {
766 impl->startDrawingZone(event->pos(), this);
766 impl->startDrawingZone(event->pos(), this);
767 }
767 }
768 }
768 }
769 }
769 }
770
770
771 // Allows mouse panning only in default mode
771 // Allows mouse panning only in default mode
772 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
772 plot().setInteraction(QCP::iRangeDrag, sqpApp->plotsInteractionMode()
773 == SqpApplication::PlotsInteractionMode::None
773 == SqpApplication::PlotsInteractionMode::None
774 && !isDragDropClick);
774 && !isDragDropClick);
775
775
776 // Allows zone edition only in selection zone mode without drag&drop
776 // Allows zone edition only in selection zone mode without drag&drop
777 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
777 impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick);
778
778
779 // Selection / Deselection
779 // Selection / Deselection
780 if (isSelectionZoneMode) {
780 if (isSelectionZoneMode) {
781 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
781 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
782 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
782 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
783 if (selectionZoneItemUnderCursor && isLeftClick) {
783 if (selectionZoneItemUnderCursor && isLeftClick) {
784 selectionZoneItemUnderCursor->setAssociatedEditedZones(
784 selectionZoneItemUnderCursor->setAssociatedEditedZones(
785 parentVisualizationWidget()->selectionZoneManager().selectedItems());
785 parentVisualizationWidget()->selectionZoneManager().selectedItems());
786 }
786 }
787 else if (!isMultiSelectionClick && isLeftClick) {
787 else if (!isMultiSelectionClick && isLeftClick) {
788 parentVisualizationWidget()->selectionZoneManager().clearSelection();
788 parentVisualizationWidget()->selectionZoneManager().clearSelection();
789 }
789 }
790 else {
790 else {
791 // No selection change
791 // No selection change
792 }
792 }
793 }
793 }
794
794
795
795
796 impl->m_HasMovedMouse = false;
796 impl->m_HasMovedMouse = false;
797 VisualizationDragWidget::mousePressEvent(event);
797 VisualizationDragWidget::mousePressEvent(event);
798 }
798 }
799
799
800 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
800 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
801 {
801 {
802 if (impl->m_DrawingZoomRect) {
802 if (impl->m_DrawingZoomRect) {
803
803
804 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
804 auto axisX = plot().axisRect()->axis(QCPAxis::atBottom);
805 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
805 auto axisY = plot().axisRect()->axis(QCPAxis::atLeft);
806
806
807 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
807 auto newAxisXRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().x(),
808 impl->m_DrawingZoomRect->bottomRight->coords().x()};
808 impl->m_DrawingZoomRect->bottomRight->coords().x()};
809
809
810 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
810 auto newAxisYRange = QCPRange{impl->m_DrawingZoomRect->topLeft->coords().y(),
811 impl->m_DrawingZoomRect->bottomRight->coords().y()};
811 impl->m_DrawingZoomRect->bottomRight->coords().y()};
812
812
813 impl->removeDrawingRect(plot());
813 impl->removeDrawingRect(plot());
814
814
815 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
815 if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)
816 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
816 && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) {
817 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
817 impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range()));
818 axisX->setRange(newAxisXRange);
818 axisX->setRange(newAxisXRange);
819 axisY->setRange(newAxisYRange);
819 axisY->setRange(newAxisYRange);
820
820
821 plot().replot(QCustomPlot::rpQueuedReplot);
821 plot().replot(QCustomPlot::rpQueuedReplot);
822 }
822 }
823 }
823 }
824
824
825 impl->endDrawingZone(this);
825 impl->endDrawingZone(this);
826
826
827 impl->m_IsCalibration = false;
827 impl->m_IsCalibration = false;
828
828
829 // Selection / Deselection
829 // Selection / Deselection
830 auto isSelectionZoneMode
830 auto isSelectionZoneMode
831 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
831 = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones;
832 if (isSelectionZoneMode) {
832 if (isSelectionZoneMode) {
833 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
833 auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER);
834 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
834 auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos(), plot());
835 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
835 if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton) {
836 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
836 if (!isMultiSelectionClick && !impl->m_HasMovedMouse) {
837 parentVisualizationWidget()->selectionZoneManager().select(
837 parentVisualizationWidget()->selectionZoneManager().select(
838 {selectionZoneItemUnderCursor});
838 {selectionZoneItemUnderCursor});
839 }
839 }
840 else if (!impl->m_HasMovedMouse) {
840 else if (!impl->m_HasMovedMouse) {
841 parentVisualizationWidget()->selectionZoneManager().setSelected(
841 parentVisualizationWidget()->selectionZoneManager().setSelected(
842 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
842 selectionZoneItemUnderCursor, !selectionZoneItemUnderCursor->selected()
843 || event->button() == Qt::RightButton);
843 || event->button() == Qt::RightButton);
844 }
844 }
845 }
845 }
846 else {
846 else {
847 // No selection change
847 // No selection change
848 }
848 }
849 }
849 }
850 }
850 }
851
851
852 void VisualizationGraphWidget::onDataCacheVariableUpdated()
852 void VisualizationGraphWidget::onDataCacheVariableUpdated()
853 {
853 {
854 auto graphRange = ui->widget->xAxis->range();
854 auto graphRange = ui->widget->xAxis->range();
855 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
855 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
856
856
857 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
857 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
858 auto variable = variableEntry.first;
858 auto variable = variableEntry.first;
859 qCDebug(LOG_VisualizationGraphWidget())
859 qCDebug(LOG_VisualizationGraphWidget())
860 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
860 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
861 qCDebug(LOG_VisualizationGraphWidget())
861 qCDebug(LOG_VisualizationGraphWidget())
862 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
862 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
863 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
863 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
864 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
864 impl->updateData(variableEntry.second, variable->dataSeries(), variable->range());
865 }
865 }
866 }
866 }
867 }
867 }
868
868
869 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
869 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
870 const SqpRange &range)
870 const SqpRange &range)
871 {
871 {
872 auto it = impl->m_VariableToPlotMultiMap.find(variable);
872 auto it = impl->m_VariableToPlotMultiMap.find(variable);
873 if (it != impl->m_VariableToPlotMultiMap.end()) {
873 if (it != impl->m_VariableToPlotMultiMap.end()) {
874 impl->updateData(it->second, variable->dataSeries(), range);
874 impl->updateData(it->second, variable->dataSeries(), range);
875 }
875 }
876 }
876 }
General Comments 0
You need to be logged in to leave comments. Login now