@@ -1,396 +1,395 | |||||
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 <Catalogue/CatalogueController.h> |
|
25 | #include <Catalogue/CatalogueController.h> | |
26 | //#include <Catalogue/CatalogueExplorer.h> |
|
26 | //#include <Catalogue/CatalogueExplorer.h> | |
27 | #include <DataSource/DataSourceController.h> |
|
27 | #include <DataSource/DataSourceController.h> | |
28 | #include <DataSource/DataSourceWidget.h> |
|
28 | #include <DataSource/DataSourceWidget.h> | |
29 | #include <Settings/SqpSettingsDialog.h> |
|
29 | #include <Settings/SqpSettingsDialog.h> | |
30 | #include <Settings/SqpSettingsGeneralWidget.h> |
|
30 | #include <Settings/SqpSettingsGeneralWidget.h> | |
31 | #include <SidePane/SqpSidePane.h> |
|
31 | #include <SidePane/SqpSidePane.h> | |
32 | #include <SqpApplication.h> |
|
32 | #include <SqpApplication.h> | |
33 | #include <Time/TimeController.h> |
|
33 | #include <Time/TimeController.h> | |
34 | #include <TimeWidget/TimeWidget.h> |
|
34 | #include <TimeWidget/TimeWidget.h> | |
35 | #include <Variable/Variable.h> |
|
|||
36 | #include <Visualization/VisualizationController.h> |
|
35 | #include <Visualization/VisualizationController.h> | |
37 |
|
36 | |||
38 | #include <QAction> |
|
37 | #include <QAction> | |
39 | #include <QCloseEvent> |
|
38 | #include <QCloseEvent> | |
40 | #include <QDate> |
|
39 | #include <QDate> | |
41 | #include <QDir> |
|
40 | #include <QDir> | |
42 | #include <QFileDialog> |
|
41 | #include <QFileDialog> | |
43 | #include <QMessageBox> |
|
42 | #include <QMessageBox> | |
44 | #include <QToolBar> |
|
43 | #include <QToolBar> | |
45 | #include <QToolButton> |
|
44 | #include <QToolButton> | |
46 | #include <memory.h> |
|
45 | #include <memory.h> | |
47 |
|
46 | |||
48 | #include "iostream" |
|
47 | #include "iostream" | |
49 |
|
48 | |||
50 | Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow") |
|
49 | Q_LOGGING_CATEGORY(LOG_MainWindow, "MainWindow") | |
51 |
|
50 | |||
52 | namespace |
|
51 | namespace | |
53 | { |
|
52 | { | |
54 | const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0; |
|
53 | const auto LEFTMAININSPECTORWIDGETSPLITTERINDEX = 0; | |
55 | const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1; |
|
54 | const auto LEFTINSPECTORSIDEPANESPLITTERINDEX = 1; | |
56 | const auto VIEWPLITTERINDEX = 2; |
|
55 | const auto VIEWPLITTERINDEX = 2; | |
57 | const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3; |
|
56 | const auto RIGHTINSPECTORSIDEPANESPLITTERINDEX = 3; | |
58 | const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4; |
|
57 | const auto RIGHTMAININSPECTORWIDGETSPLITTERINDEX = 4; | |
59 | } |
|
58 | } | |
60 |
|
59 | |||
61 | class MainWindow::MainWindowPrivate |
|
60 | class MainWindow::MainWindowPrivate | |
62 | { |
|
61 | { | |
63 | public: |
|
62 | public: | |
64 | explicit MainWindowPrivate(MainWindow* mainWindow) |
|
63 | explicit MainWindowPrivate(MainWindow* mainWindow) | |
65 | : m_LastOpenLeftInspectorSize {} |
|
64 | : m_LastOpenLeftInspectorSize {} | |
66 | , m_LastOpenRightInspectorSize {} |
|
65 | , m_LastOpenRightInspectorSize {} | |
67 | , m_GeneralSettingsWidget { new SqpSettingsGeneralWidget { mainWindow } } |
|
66 | , m_GeneralSettingsWidget { new SqpSettingsGeneralWidget { mainWindow } } | |
68 | , m_SettingsDialog { new SqpSettingsDialog { mainWindow } } |
|
67 | , m_SettingsDialog { new SqpSettingsDialog { mainWindow } } | |
69 | //, m_CatalogExplorer { new CatalogueExplorer { mainWindow } } |
|
68 | //, m_CatalogExplorer { new CatalogueExplorer { mainWindow } } | |
70 | { |
|
69 | { | |
71 | } |
|
70 | } | |
72 |
|
71 | |||
73 | QSize m_LastOpenLeftInspectorSize; |
|
72 | QSize m_LastOpenLeftInspectorSize; | |
74 | QSize m_LastOpenRightInspectorSize; |
|
73 | QSize m_LastOpenRightInspectorSize; | |
75 | /// General settings widget. MainWindow has the ownership |
|
74 | /// General settings widget. MainWindow has the ownership | |
76 | SqpSettingsGeneralWidget* m_GeneralSettingsWidget; |
|
75 | SqpSettingsGeneralWidget* m_GeneralSettingsWidget; | |
77 | /// Settings dialog. MainWindow has the ownership |
|
76 | /// Settings dialog. MainWindow has the ownership | |
78 | SqpSettingsDialog* m_SettingsDialog; |
|
77 | SqpSettingsDialog* m_SettingsDialog; | |
79 | /// Catalogue dialog. MainWindow has the ownership |
|
78 | /// Catalogue dialog. MainWindow has the ownership | |
80 | // CatalogueExplorer* m_CatalogExplorer; |
|
79 | // CatalogueExplorer* m_CatalogExplorer; | |
81 |
|
80 | |||
82 | bool checkDataToSave(QWidget* parentWidget); |
|
81 | bool checkDataToSave(QWidget* parentWidget); | |
83 | }; |
|
82 | }; | |
84 |
|
83 | |||
85 | MainWindow::MainWindow(QWidget* parent) |
|
84 | MainWindow::MainWindow(QWidget* parent) | |
86 | : QMainWindow { parent } |
|
85 | : QMainWindow { parent } | |
87 | , m_Ui { new Ui::MainWindow } |
|
86 | , m_Ui { new Ui::MainWindow } | |
88 | , impl { spimpl::make_unique_impl<MainWindowPrivate>(this) } |
|
87 | , impl { spimpl::make_unique_impl<MainWindowPrivate>(this) } | |
89 | { |
|
88 | { | |
90 | m_Ui->setupUi(this); |
|
89 | m_Ui->setupUi(this); | |
91 |
|
90 | |||
92 | m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false); |
|
91 | m_Ui->splitter->setCollapsible(LEFTINSPECTORSIDEPANESPLITTERINDEX, false); | |
93 | m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false); |
|
92 | m_Ui->splitter->setCollapsible(RIGHTINSPECTORSIDEPANESPLITTERINDEX, false); | |
94 |
|
93 | |||
95 | // impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view); |
|
94 | // impl->m_CatalogExplorer->setVisualizationWidget(m_Ui->view); | |
96 |
|
95 | |||
97 |
|
96 | |||
98 | auto spacerLeftTop = new QWidget {}; |
|
97 | auto spacerLeftTop = new QWidget {}; | |
99 | spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
98 | spacerLeftTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | |
100 |
|
99 | |||
101 | auto spacerLeftBottom = new QWidget {}; |
|
100 | auto spacerLeftBottom = new QWidget {}; | |
102 | spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
101 | spacerLeftBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | |
103 |
|
102 | |||
104 |
|
103 | |||
105 | auto spacerRightTop = new QWidget {}; |
|
104 | auto spacerRightTop = new QWidget {}; | |
106 | spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
105 | spacerRightTop->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | |
107 |
|
106 | |||
108 | auto spacerRightBottom = new QWidget {}; |
|
107 | auto spacerRightBottom = new QWidget {}; | |
109 | spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
108 | spacerRightBottom->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | |
110 |
|
109 | |||
111 |
|
110 | |||
112 | auto openInspector = [this](bool checked, bool right, auto action) { |
|
111 | auto openInspector = [this](bool checked, bool right, auto action) { | |
113 | action->setIcon( |
|
112 | action->setIcon( | |
114 | QIcon { (checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png" }); |
|
113 | QIcon { (checked ^ right) ? ":/icones/next.png" : ":/icones/previous.png" }); | |
115 |
|
114 | |||
116 | auto& lastInspectorSize |
|
115 | auto& lastInspectorSize | |
117 | = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize; |
|
116 | = right ? impl->m_LastOpenRightInspectorSize : impl->m_LastOpenLeftInspectorSize; | |
118 |
|
117 | |||
119 | auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size() |
|
118 | auto nextInspectorSize = right ? m_Ui->rightMainInspectorWidget->size() | |
120 | : m_Ui->leftMainInspectorWidget->size(); |
|
119 | : m_Ui->leftMainInspectorWidget->size(); | |
121 |
|
120 | |||
122 | // Update of the last opened geometry |
|
121 | // Update of the last opened geometry | |
123 | if (checked) |
|
122 | if (checked) | |
124 | { |
|
123 | { | |
125 | lastInspectorSize = nextInspectorSize; |
|
124 | lastInspectorSize = nextInspectorSize; | |
126 | } |
|
125 | } | |
127 |
|
126 | |||
128 | auto startSize = lastInspectorSize; |
|
127 | auto startSize = lastInspectorSize; | |
129 | auto endSize = startSize; |
|
128 | auto endSize = startSize; | |
130 | endSize.setWidth(0); |
|
129 | endSize.setWidth(0); | |
131 |
|
130 | |||
132 | auto splitterInspectorIndex |
|
131 | auto splitterInspectorIndex | |
133 | = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX; |
|
132 | = right ? RIGHTMAININSPECTORWIDGETSPLITTERINDEX : LEFTMAININSPECTORWIDGETSPLITTERINDEX; | |
134 |
|
133 | |||
135 | auto currentSizes = m_Ui->splitter->sizes(); |
|
134 | auto currentSizes = m_Ui->splitter->sizes(); | |
136 | if (checked) |
|
135 | if (checked) | |
137 | { |
|
136 | { | |
138 | // adjust sizes individually here, e.g. |
|
137 | // adjust sizes individually here, e.g. | |
139 | currentSizes[splitterInspectorIndex] -= lastInspectorSize.width(); |
|
138 | currentSizes[splitterInspectorIndex] -= lastInspectorSize.width(); | |
140 | currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width(); |
|
139 | currentSizes[VIEWPLITTERINDEX] += lastInspectorSize.width(); | |
141 | m_Ui->splitter->setSizes(currentSizes); |
|
140 | m_Ui->splitter->setSizes(currentSizes); | |
142 | } |
|
141 | } | |
143 | else |
|
142 | else | |
144 | { |
|
143 | { | |
145 | // adjust sizes individually here, e.g. |
|
144 | // adjust sizes individually here, e.g. | |
146 | currentSizes[splitterInspectorIndex] += lastInspectorSize.width(); |
|
145 | currentSizes[splitterInspectorIndex] += lastInspectorSize.width(); | |
147 | currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width(); |
|
146 | currentSizes[VIEWPLITTERINDEX] -= lastInspectorSize.width(); | |
148 | m_Ui->splitter->setSizes(currentSizes); |
|
147 | m_Ui->splitter->setSizes(currentSizes); | |
149 | } |
|
148 | } | |
150 | }; |
|
149 | }; | |
151 |
|
150 | |||
152 |
|
151 | |||
153 | // //////////////// // |
|
152 | // //////////////// // | |
154 | // Menu and Toolbar // |
|
153 | // Menu and Toolbar // | |
155 | // //////////////// // |
|
154 | // //////////////// // | |
156 | this->menuBar()->addAction(tr("File")); |
|
155 | this->menuBar()->addAction(tr("File")); | |
157 | auto toolsMenu = this->menuBar()->addMenu(tr("Tools")); |
|
156 | auto toolsMenu = this->menuBar()->addMenu(tr("Tools")); | |
158 | toolsMenu->addAction(tr("Settings..."), [this]() { |
|
157 | toolsMenu->addAction(tr("Settings..."), [this]() { | |
159 | // Loads settings |
|
158 | // Loads settings | |
160 | impl->m_SettingsDialog->loadSettings(); |
|
159 | impl->m_SettingsDialog->loadSettings(); | |
161 |
|
160 | |||
162 | // Open settings dialog and save settings if the dialog is accepted |
|
161 | // Open settings dialog and save settings if the dialog is accepted | |
163 | if (impl->m_SettingsDialog->exec() == QDialog::Accepted) |
|
162 | if (impl->m_SettingsDialog->exec() == QDialog::Accepted) | |
164 | { |
|
163 | { | |
165 | impl->m_SettingsDialog->saveSettings(); |
|
164 | impl->m_SettingsDialog->saveSettings(); | |
166 | } |
|
165 | } | |
167 | }); |
|
166 | }); | |
168 |
|
167 | |||
169 | auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar")); |
|
168 | auto mainToolBar = this->addToolBar(QStringLiteral("MainToolBar")); | |
170 |
|
169 | |||
171 | auto timeWidget = new TimeWidget {}; |
|
170 | auto timeWidget = new TimeWidget {}; | |
172 | mainToolBar->addWidget(timeWidget); |
|
171 | mainToolBar->addWidget(timeWidget); | |
173 |
|
172 | |||
174 | // Interaction modes |
|
173 | // Interaction modes | |
175 | auto actionPointerMode = new QAction { QIcon(":/icones/pointer.png"), "Move", this }; |
|
174 | auto actionPointerMode = new QAction { QIcon(":/icones/pointer.png"), "Move", this }; | |
176 | actionPointerMode->setCheckable(true); |
|
175 | actionPointerMode->setCheckable(true); | |
177 | actionPointerMode->setChecked( |
|
176 | actionPointerMode->setChecked( | |
178 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None); |
|
177 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None); | |
179 | connect(actionPointerMode, &QAction::triggered, |
|
178 | connect(actionPointerMode, &QAction::triggered, | |
180 | []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); }); |
|
179 | []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::None); }); | |
181 |
|
180 | |||
182 | auto actionZoomMode = new QAction { QIcon(":/icones/zoom.png"), "Zoom", this }; |
|
181 | auto actionZoomMode = new QAction { QIcon(":/icones/zoom.png"), "Zoom", this }; | |
183 | actionZoomMode->setCheckable(true); |
|
182 | actionZoomMode->setCheckable(true); | |
184 | actionZoomMode->setChecked( |
|
183 | actionZoomMode->setChecked( | |
185 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox); |
|
184 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox); | |
186 | connect(actionZoomMode, &QAction::triggered, |
|
185 | connect(actionZoomMode, &QAction::triggered, | |
187 | []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox); }); |
|
186 | []() { sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::ZoomBox); }); | |
188 |
|
187 | |||
189 | auto actionOrganisationMode = new QAction { QIcon(":/icones/drag.png"), "Organize", this }; |
|
188 | auto actionOrganisationMode = new QAction { QIcon(":/icones/drag.png"), "Organize", this }; | |
190 | actionOrganisationMode->setCheckable(true); |
|
189 | actionOrganisationMode->setCheckable(true); | |
191 | actionOrganisationMode->setChecked( |
|
190 | actionOrganisationMode->setChecked( | |
192 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::DragAndDrop); |
|
191 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::DragAndDrop); | |
193 | connect(actionOrganisationMode, &QAction::triggered, []() { |
|
192 | connect(actionOrganisationMode, &QAction::triggered, []() { | |
194 | sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop); |
|
193 | sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::DragAndDrop); | |
195 | }); |
|
194 | }); | |
196 |
|
195 | |||
197 | auto actionZonesMode = new QAction { QIcon(":/icones/rectangle.png"), "Zones", this }; |
|
196 | auto actionZonesMode = new QAction { QIcon(":/icones/rectangle.png"), "Zones", this }; | |
198 | actionZonesMode->setCheckable(true); |
|
197 | actionZonesMode->setCheckable(true); | |
199 | actionZonesMode->setChecked( |
|
198 | actionZonesMode->setChecked( | |
200 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones); |
|
199 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones); | |
201 | connect(actionZonesMode, &QAction::triggered, []() { |
|
200 | connect(actionZonesMode, &QAction::triggered, []() { | |
202 | sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones); |
|
201 | sqpApp->setPlotsInteractionMode(SqpApplication::PlotsInteractionMode::SelectionZones); | |
203 | }); |
|
202 | }); | |
204 |
|
203 | |||
205 | auto modeActionGroup = new QActionGroup { this }; |
|
204 | auto modeActionGroup = new QActionGroup { this }; | |
206 | modeActionGroup->addAction(actionZoomMode); |
|
205 | modeActionGroup->addAction(actionZoomMode); | |
207 | modeActionGroup->addAction(actionZonesMode); |
|
206 | modeActionGroup->addAction(actionZonesMode); | |
208 | modeActionGroup->addAction(actionOrganisationMode); |
|
207 | modeActionGroup->addAction(actionOrganisationMode); | |
209 | modeActionGroup->addAction(actionPointerMode); |
|
208 | modeActionGroup->addAction(actionPointerMode); | |
210 | modeActionGroup->setExclusive(true); |
|
209 | modeActionGroup->setExclusive(true); | |
211 |
|
210 | |||
212 | mainToolBar->addSeparator(); |
|
211 | mainToolBar->addSeparator(); | |
213 | mainToolBar->addAction(actionPointerMode); |
|
212 | mainToolBar->addAction(actionPointerMode); | |
214 | mainToolBar->addAction(actionZoomMode); |
|
213 | mainToolBar->addAction(actionZoomMode); | |
215 | mainToolBar->addAction(actionOrganisationMode); |
|
214 | mainToolBar->addAction(actionOrganisationMode); | |
216 | mainToolBar->addAction(actionZonesMode); |
|
215 | mainToolBar->addAction(actionZonesMode); | |
217 | mainToolBar->addSeparator(); |
|
216 | mainToolBar->addSeparator(); | |
218 |
|
217 | |||
219 | // Cursors |
|
218 | // Cursors | |
220 | auto btnCursor = new QToolButton { this }; |
|
219 | auto btnCursor = new QToolButton { this }; | |
221 | btnCursor->setIcon(QIcon(":/icones/cursor.png")); |
|
220 | btnCursor->setIcon(QIcon(":/icones/cursor.png")); | |
222 | btnCursor->setText("Cursor"); |
|
221 | btnCursor->setText("Cursor"); | |
223 | btnCursor->setToolTip("Cursor"); |
|
222 | btnCursor->setToolTip("Cursor"); | |
224 | btnCursor->setPopupMode(QToolButton::InstantPopup); |
|
223 | btnCursor->setPopupMode(QToolButton::InstantPopup); | |
225 | auto cursorMenu = new QMenu("CursorMenu", this); |
|
224 | auto cursorMenu = new QMenu("CursorMenu", this); | |
226 | btnCursor->setMenu(cursorMenu); |
|
225 | btnCursor->setMenu(cursorMenu); | |
227 |
|
226 | |||
228 | auto noCursorAction = cursorMenu->addAction("No Cursor"); |
|
227 | auto noCursorAction = cursorMenu->addAction("No Cursor"); | |
229 | noCursorAction->setCheckable(true); |
|
228 | noCursorAction->setCheckable(true); | |
230 | noCursorAction->setChecked( |
|
229 | noCursorAction->setChecked( | |
231 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::NoCursor); |
|
230 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::NoCursor); | |
232 | connect(noCursorAction, &QAction::triggered, |
|
231 | connect(noCursorAction, &QAction::triggered, | |
233 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); }); |
|
232 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::NoCursor); }); | |
234 |
|
233 | |||
235 | cursorMenu->addSeparator(); |
|
234 | cursorMenu->addSeparator(); | |
236 | auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor"); |
|
235 | auto verticalCursorAction = cursorMenu->addAction("Vertical Cursor"); | |
237 | verticalCursorAction->setCheckable(true); |
|
236 | verticalCursorAction->setCheckable(true); | |
238 | verticalCursorAction->setChecked( |
|
237 | verticalCursorAction->setChecked( | |
239 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Vertical); |
|
238 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Vertical); | |
240 | connect(verticalCursorAction, &QAction::triggered, |
|
239 | connect(verticalCursorAction, &QAction::triggered, | |
241 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); }); |
|
240 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Vertical); }); | |
242 |
|
241 | |||
243 | auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor"); |
|
242 | auto temporalCursorAction = cursorMenu->addAction("Temporal Cursor"); | |
244 | temporalCursorAction->setCheckable(true); |
|
243 | temporalCursorAction->setCheckable(true); | |
245 | temporalCursorAction->setChecked( |
|
244 | temporalCursorAction->setChecked( | |
246 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Temporal); |
|
245 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Temporal); | |
247 | connect(temporalCursorAction, &QAction::triggered, |
|
246 | connect(temporalCursorAction, &QAction::triggered, | |
248 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); }); |
|
247 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Temporal); }); | |
249 |
|
248 | |||
250 | auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor"); |
|
249 | auto horizontalCursorAction = cursorMenu->addAction("Horizontal Cursor"); | |
251 | horizontalCursorAction->setCheckable(true); |
|
250 | horizontalCursorAction->setCheckable(true); | |
252 | horizontalCursorAction->setChecked( |
|
251 | horizontalCursorAction->setChecked( | |
253 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Horizontal); |
|
252 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Horizontal); | |
254 | connect(horizontalCursorAction, &QAction::triggered, |
|
253 | connect(horizontalCursorAction, &QAction::triggered, | |
255 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); }); |
|
254 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Horizontal); }); | |
256 |
|
255 | |||
257 | auto crossCursorAction = cursorMenu->addAction("Cross Cursor"); |
|
256 | auto crossCursorAction = cursorMenu->addAction("Cross Cursor"); | |
258 | crossCursorAction->setCheckable(true); |
|
257 | crossCursorAction->setCheckable(true); | |
259 | crossCursorAction->setChecked( |
|
258 | crossCursorAction->setChecked( | |
260 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Cross); |
|
259 | sqpApp->plotsCursorMode() == SqpApplication::PlotsCursorMode::Cross); | |
261 | connect(crossCursorAction, &QAction::triggered, |
|
260 | connect(crossCursorAction, &QAction::triggered, | |
262 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); }); |
|
261 | []() { sqpApp->setPlotsCursorMode(SqpApplication::PlotsCursorMode::Cross); }); | |
263 |
|
262 | |||
264 | mainToolBar->addWidget(btnCursor); |
|
263 | mainToolBar->addWidget(btnCursor); | |
265 |
|
264 | |||
266 | auto cursorModeActionGroup = new QActionGroup { this }; |
|
265 | auto cursorModeActionGroup = new QActionGroup { this }; | |
267 | cursorModeActionGroup->setExclusive(true); |
|
266 | cursorModeActionGroup->setExclusive(true); | |
268 | cursorModeActionGroup->addAction(noCursorAction); |
|
267 | cursorModeActionGroup->addAction(noCursorAction); | |
269 | cursorModeActionGroup->addAction(verticalCursorAction); |
|
268 | cursorModeActionGroup->addAction(verticalCursorAction); | |
270 | cursorModeActionGroup->addAction(temporalCursorAction); |
|
269 | cursorModeActionGroup->addAction(temporalCursorAction); | |
271 | cursorModeActionGroup->addAction(horizontalCursorAction); |
|
270 | cursorModeActionGroup->addAction(horizontalCursorAction); | |
272 | cursorModeActionGroup->addAction(crossCursorAction); |
|
271 | cursorModeActionGroup->addAction(crossCursorAction); | |
273 |
|
272 | |||
274 | // Catalog |
|
273 | // Catalog | |
275 | mainToolBar->addSeparator(); |
|
274 | mainToolBar->addSeparator(); | |
276 | // mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues", |
|
275 | // mainToolBar->addAction(QIcon(":/icones/catalogue.png"), "Catalogues", | |
277 | // [this]() { impl->m_CatalogExplorer->show(); }); |
|
276 | // [this]() { impl->m_CatalogExplorer->show(); }); | |
278 |
|
277 | |||
279 | // //////// // |
|
278 | // //////// // | |
280 | // Settings // |
|
279 | // Settings // | |
281 | // //////// // |
|
280 | // //////// // | |
282 |
|
281 | |||
283 | // Registers "general settings" widget to the settings dialog |
|
282 | // Registers "general settings" widget to the settings dialog | |
284 | impl->m_SettingsDialog->registerWidget( |
|
283 | impl->m_SettingsDialog->registerWidget( | |
285 | QStringLiteral("General"), impl->m_GeneralSettingsWidget); |
|
284 | QStringLiteral("General"), impl->m_GeneralSettingsWidget); | |
286 |
|
285 | |||
287 | // /////////// // |
|
286 | // /////////// // | |
288 | // Connections // |
|
287 | // Connections // | |
289 | // /////////// // |
|
288 | // /////////// // | |
290 |
|
289 | |||
291 | // Controllers / controllers connections |
|
290 | // Controllers / controllers connections | |
292 | // connect(&sqpApp->timeController(), SIGNAL(timeUpdated(DateTimeRange)), |
|
291 | // connect(&sqpApp->timeController(), SIGNAL(timeUpdated(DateTimeRange)), | |
293 | // &sqpApp->variableController(), |
|
292 | // &sqpApp->variableController(), | |
294 | // SLOT(onDateTimeOnSelection(DateTimeRange))); |
|
293 | // SLOT(onDateTimeOnSelection(DateTimeRange))); | |
295 |
|
294 | |||
296 | // Widgets / controllers connections |
|
295 | // Widgets / controllers connections | |
297 |
|
296 | |||
298 | // DataSource |
|
297 | // DataSource | |
299 | connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem*)), |
|
298 | connect(&sqpApp->dataSourceController(), SIGNAL(dataSourceItemSet(DataSourceItem*)), | |
300 | m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem*))); |
|
299 | m_Ui->dataSourceWidget, SLOT(addDataSource(DataSourceItem*))); | |
301 |
|
300 | |||
302 | // Time |
|
301 | // Time | |
303 | connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(), |
|
302 | connect(timeWidget, SIGNAL(timeUpdated(DateTimeRange)), &sqpApp->timeController(), | |
304 | SLOT(onTimeToUpdate(DateTimeRange))); |
|
303 | SLOT(onTimeToUpdate(DateTimeRange))); | |
305 |
|
304 | |||
306 | // Visualization |
|
305 | // Visualization | |
307 | connect(&sqpApp->visualizationController(), |
|
306 | connect(&sqpApp->visualizationController(), | |
308 | SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view, |
|
307 | SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), m_Ui->view, | |
309 | SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>))); |
|
308 | SLOT(onVariableAboutToBeDeleted(std::shared_ptr<Variable>))); | |
310 |
|
309 | |||
311 | connect(&sqpApp->visualizationController(), |
|
310 | connect(&sqpApp->visualizationController(), | |
312 | SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange&)), m_Ui->view, |
|
311 | SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange&)), m_Ui->view, | |
313 | SLOT(onRangeChanged(std::shared_ptr<Variable>, const DateTimeRange&))); |
|
312 | SLOT(onRangeChanged(std::shared_ptr<Variable>, const DateTimeRange&))); | |
314 |
|
313 | |||
315 | // Widgets / widgets connections |
|
314 | // Widgets / widgets connections | |
316 |
|
315 | |||
317 | // For the following connections, we use DirectConnection to allow each widget that can |
|
316 | // For the following connections, we use DirectConnection to allow each widget that can | |
318 | // potentially attach a menu to the variable's menu to do so before this menu is displayed. |
|
317 | // potentially attach a menu to the variable's menu to do so before this menu is displayed. | |
319 | // The order of connections is also important, since it determines the order in which each |
|
318 | // The order of connections is also important, since it determines the order in which each | |
320 | // widget will attach its menu |
|
319 | // widget will attach its menu | |
321 | connect(m_Ui->variableInspectorWidget, |
|
320 | connect(m_Ui->variableInspectorWidget, | |
322 | SIGNAL(tableMenuAboutToBeDisplayed(QMenu*, const QVector<std::shared_ptr<Variable>>&)), |
|
321 | SIGNAL(tableMenuAboutToBeDisplayed(QMenu*, const QVector<std::shared_ptr<Variable>>&)), | |
323 | m_Ui->view, SLOT(attachVariableMenu(QMenu*, const QVector<std::shared_ptr<Variable>>&)), |
|
322 | m_Ui->view, SLOT(attachVariableMenu(QMenu*, const QVector<std::shared_ptr<Variable>>&)), | |
324 | Qt::DirectConnection); |
|
323 | Qt::DirectConnection); | |
325 | } |
|
324 | } | |
326 |
|
325 | |||
327 | MainWindow::~MainWindow() {} |
|
326 | MainWindow::~MainWindow() {} | |
328 |
|
327 | |||
329 | void MainWindow::changeEvent(QEvent* e) |
|
328 | void MainWindow::changeEvent(QEvent* e) | |
330 | { |
|
329 | { | |
331 | QMainWindow::changeEvent(e); |
|
330 | QMainWindow::changeEvent(e); | |
332 | switch (e->type()) |
|
331 | switch (e->type()) | |
333 | { |
|
332 | { | |
334 | case QEvent::LanguageChange: |
|
333 | case QEvent::LanguageChange: | |
335 | m_Ui->retranslateUi(this); |
|
334 | m_Ui->retranslateUi(this); | |
336 | break; |
|
335 | break; | |
337 | default: |
|
336 | default: | |
338 | break; |
|
337 | break; | |
339 | } |
|
338 | } | |
340 | } |
|
339 | } | |
341 |
|
340 | |||
342 | void MainWindow::closeEvent(QCloseEvent* event) |
|
341 | void MainWindow::closeEvent(QCloseEvent* event) | |
343 | { |
|
342 | { | |
344 | if (!impl->checkDataToSave(this)) |
|
343 | if (!impl->checkDataToSave(this)) | |
345 | { |
|
344 | { | |
346 | event->ignore(); |
|
345 | event->ignore(); | |
347 | } |
|
346 | } | |
348 | else |
|
347 | else | |
349 | { |
|
348 | { | |
350 | event->accept(); |
|
349 | event->accept(); | |
351 | } |
|
350 | } | |
352 | } |
|
351 | } | |
353 |
|
352 | |||
354 | void MainWindow::keyPressEvent(QKeyEvent* event) |
|
353 | void MainWindow::keyPressEvent(QKeyEvent* event) | |
355 | { |
|
354 | { | |
356 | switch (event->key()) |
|
355 | switch (event->key()) | |
357 | { |
|
356 | { | |
358 | case Qt::Key_F11: |
|
357 | case Qt::Key_F11: | |
359 | if (this->isFullScreen()) |
|
358 | if (this->isFullScreen()) | |
360 | { |
|
359 | { | |
361 | this->showNormal(); |
|
360 | this->showNormal(); | |
362 | } |
|
361 | } | |
363 | else |
|
362 | else | |
364 | { |
|
363 | { | |
365 | this->showFullScreen(); |
|
364 | this->showFullScreen(); | |
366 | } |
|
365 | } | |
367 | break; |
|
366 | break; | |
368 | default: |
|
367 | default: | |
369 | break; |
|
368 | break; | |
370 | } |
|
369 | } | |
371 | } |
|
370 | } | |
372 |
|
371 | |||
373 | bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget* parentWidget) |
|
372 | bool MainWindow::MainWindowPrivate::checkDataToSave(QWidget* parentWidget) | |
374 | { |
|
373 | { | |
375 | // auto hasChanges = sqpApp->catalogueController().hasChanges(); |
|
374 | // auto hasChanges = sqpApp->catalogueController().hasChanges(); | |
376 | // if (hasChanges) |
|
375 | // if (hasChanges) | |
377 | // { |
|
376 | // { | |
378 | // // There are some unsaved changes |
|
377 | // // There are some unsaved changes | |
379 | // switch (QMessageBox::question(parentWidget, tr("Save changes"), |
|
378 | // switch (QMessageBox::question(parentWidget, tr("Save changes"), | |
380 | // tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"), |
|
379 | // tr("The catalogue controller has unsaved changes.\nDo you want to save them ?"), | |
381 | // QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel, |
|
380 | // QMessageBox::SaveAll | QMessageBox::Discard | QMessageBox::Cancel, | |
382 | // QMessageBox::SaveAll)) |
|
381 | // QMessageBox::SaveAll)) | |
383 | // { |
|
382 | // { | |
384 | // case QMessageBox::SaveAll: |
|
383 | // case QMessageBox::SaveAll: | |
385 | // sqpApp->catalogueController().saveAll(); |
|
384 | // sqpApp->catalogueController().saveAll(); | |
386 | // break; |
|
385 | // break; | |
387 | // case QMessageBox::Discard: |
|
386 | // case QMessageBox::Discard: | |
388 | // break; |
|
387 | // break; | |
389 | // case QMessageBox::Cancel: |
|
388 | // case QMessageBox::Cancel: | |
390 | // default: |
|
389 | // default: | |
391 | // return false; |
|
390 | // return false; | |
392 | // } |
|
391 | // } | |
393 | // } |
|
392 | // } | |
394 |
|
393 | |||
395 | return true; |
|
394 | return true; | |
396 | } |
|
395 | } |
@@ -1,1 +1,1 | |||||
1 | Subproject commit ae48b17833443bc2730a7511f964569dc7cdb1df |
|
1 | Subproject commit cc26524fb5d10feca3820e6921c9cd3cfb1a3591 |
@@ -1,332 +1,331 | |||||
1 | #include "DragAndDrop/DragDropGuiController.h" |
|
1 | #include "DragAndDrop/DragDropGuiController.h" | |
2 | #include "DragAndDrop/DragDropScroller.h" |
|
2 | #include "DragAndDrop/DragDropScroller.h" | |
3 | #include "DragAndDrop/DragDropTabSwitcher.h" |
|
3 | #include "DragAndDrop/DragDropTabSwitcher.h" | |
4 | #include "SqpApplication.h" |
|
4 | #include "SqpApplication.h" | |
5 | #include "Visualization/VisualizationDragDropContainer.h" |
|
5 | #include "Visualization/VisualizationDragDropContainer.h" | |
6 | #include "Visualization/VisualizationDragWidget.h" |
|
6 | #include "Visualization/VisualizationDragWidget.h" | |
7 | #include "Visualization/VisualizationWidget.h" |
|
7 | #include "Visualization/VisualizationWidget.h" | |
8 | #include "Visualization/operations/FindVariableOperation.h" |
|
8 | #include "Visualization/operations/FindVariableOperation.h" | |
9 |
|
9 | |||
10 | #include "DataSource/DataSourceController.h" |
|
10 | #include "DataSource/DataSourceController.h" | |
11 | #include "Variable/Variable.h" |
|
|||
12 | #include "Variable/VariableController2.h" |
|
11 | #include "Variable/VariableController2.h" | |
13 |
|
12 | |||
14 | #include "Common/MimeTypesDef.h" |
|
13 | #include "Common/MimeTypesDef.h" | |
15 | #include "Common/VisualizationDef.h" |
|
14 | #include "Common/VisualizationDef.h" | |
16 |
|
15 | |||
17 | #include <QDir> |
|
16 | #include <QDir> | |
18 | #include <QLabel> |
|
17 | #include <QLabel> | |
19 | #include <QUrl> |
|
18 | #include <QUrl> | |
20 | #include <QVBoxLayout> |
|
19 | #include <QVBoxLayout> | |
21 |
|
20 | |||
22 |
|
21 | |||
23 | Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController") |
|
22 | Q_LOGGING_CATEGORY(LOG_DragDropGuiController, "DragDropGuiController") | |
24 |
|
23 | |||
25 |
|
24 | |||
26 | struct DragDropGuiController::DragDropGuiControllerPrivate |
|
25 | struct DragDropGuiController::DragDropGuiControllerPrivate | |
27 | { |
|
26 | { | |
28 |
|
27 | |||
29 | VisualizationDragWidget* m_CurrentDragWidget = nullptr; |
|
28 | VisualizationDragWidget* m_CurrentDragWidget = nullptr; | |
30 | std::unique_ptr<QWidget> m_PlaceHolder = nullptr; |
|
29 | std::unique_ptr<QWidget> m_PlaceHolder = nullptr; | |
31 | QLabel* m_PlaceHolderLabel; |
|
30 | QLabel* m_PlaceHolderLabel; | |
32 | QWidget* m_PlaceBackground; |
|
31 | QWidget* m_PlaceBackground; | |
33 | std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr; |
|
32 | std::unique_ptr<DragDropScroller> m_DragDropScroller = nullptr; | |
34 | std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr; |
|
33 | std::unique_ptr<DragDropTabSwitcher> m_DragDropTabSwitcher = nullptr; | |
35 | QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using |
|
34 | QString m_ImageTempUrl; // Temporary file for image url generated by the drag & drop. Not using | |
36 | // QTemporaryFile to have a name which is not generated. |
|
35 | // QTemporaryFile to have a name which is not generated. | |
37 |
|
36 | |||
38 | VisualizationDragWidget* m_HighlightedDragWidget = nullptr; |
|
37 | VisualizationDragWidget* m_HighlightedDragWidget = nullptr; | |
39 |
|
38 | |||
40 | QMetaObject::Connection m_DragWidgetDestroyedConnection; |
|
39 | QMetaObject::Connection m_DragWidgetDestroyedConnection; | |
41 | QMetaObject::Connection m_HighlightedWidgetDestroyedConnection; |
|
40 | QMetaObject::Connection m_HighlightedWidgetDestroyedConnection; | |
42 |
|
41 | |||
43 | QList<QWidget*> m_WidgetToClose; |
|
42 | QList<QWidget*> m_WidgetToClose; | |
44 |
|
43 | |||
45 | explicit DragDropGuiControllerPrivate() |
|
44 | explicit DragDropGuiControllerPrivate() | |
46 | : m_PlaceHolder { std::make_unique<QWidget>() } |
|
45 | : m_PlaceHolder { std::make_unique<QWidget>() } | |
47 | , m_DragDropScroller { std::make_unique<DragDropScroller>() } |
|
46 | , m_DragDropScroller { std::make_unique<DragDropScroller>() } | |
48 | , m_DragDropTabSwitcher { std::make_unique<DragDropTabSwitcher>() } |
|
47 | , m_DragDropTabSwitcher { std::make_unique<DragDropTabSwitcher>() } | |
49 | { |
|
48 | { | |
50 |
|
49 | |||
51 | auto layout = new QVBoxLayout { m_PlaceHolder.get() }; |
|
50 | auto layout = new QVBoxLayout { m_PlaceHolder.get() }; | |
52 | layout->setSpacing(0); |
|
51 | layout->setSpacing(0); | |
53 | layout->setContentsMargins(0, 0, 0, 0); |
|
52 | layout->setContentsMargins(0, 0, 0, 0); | |
54 |
|
53 | |||
55 | m_PlaceHolderLabel = new QLabel { "", m_PlaceHolder.get() }; |
|
54 | m_PlaceHolderLabel = new QLabel { "", m_PlaceHolder.get() }; | |
56 | m_PlaceHolderLabel->setMinimumHeight(25); |
|
55 | m_PlaceHolderLabel->setMinimumHeight(25); | |
57 | layout->addWidget(m_PlaceHolderLabel); |
|
56 | layout->addWidget(m_PlaceHolderLabel); | |
58 |
|
57 | |||
59 | m_PlaceBackground = new QWidget { m_PlaceHolder.get() }; |
|
58 | m_PlaceBackground = new QWidget { m_PlaceHolder.get() }; | |
60 | m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
59 | m_PlaceBackground->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | |
61 | layout->addWidget(m_PlaceBackground); |
|
60 | layout->addWidget(m_PlaceBackground); | |
62 |
|
61 | |||
63 | sqpApp->installEventFilter(m_DragDropScroller.get()); |
|
62 | sqpApp->installEventFilter(m_DragDropScroller.get()); | |
64 | sqpApp->installEventFilter(m_DragDropTabSwitcher.get()); |
|
63 | sqpApp->installEventFilter(m_DragDropTabSwitcher.get()); | |
65 |
|
64 | |||
66 | m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png"); |
|
65 | m_ImageTempUrl = QDir::temp().absoluteFilePath("Sciqlop_graph.png"); | |
67 | } |
|
66 | } | |
68 |
|
67 | |||
69 | void preparePlaceHolder( |
|
68 | void preparePlaceHolder( | |
70 | DragDropGuiController::PlaceHolderType type, const QString& topLabelText) const |
|
69 | DragDropGuiController::PlaceHolderType type, const QString& topLabelText) const | |
71 | { |
|
70 | { | |
72 | if (m_CurrentDragWidget) |
|
71 | if (m_CurrentDragWidget) | |
73 | { |
|
72 | { | |
74 | m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size()); |
|
73 | m_PlaceHolder->setMinimumSize(m_CurrentDragWidget->size()); | |
75 | m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy()); |
|
74 | m_PlaceHolder->setSizePolicy(m_CurrentDragWidget->sizePolicy()); | |
76 | } |
|
75 | } | |
77 | else |
|
76 | else | |
78 | { |
|
77 | { | |
79 | // Configuration of the placeHolder when there is no dragWidget |
|
78 | // Configuration of the placeHolder when there is no dragWidget | |
80 | // (for instance with a drag from a variable) |
|
79 | // (for instance with a drag from a variable) | |
81 |
|
80 | |||
82 | m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT); |
|
81 | m_PlaceHolder->setMinimumSize(0, GRAPH_MINIMUM_HEIGHT); | |
83 | m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
82 | m_PlaceHolder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); | |
84 | } |
|
83 | } | |
85 |
|
84 | |||
86 | switch (type) |
|
85 | switch (type) | |
87 | { |
|
86 | { | |
88 | case DragDropGuiController::PlaceHolderType::Graph: |
|
87 | case DragDropGuiController::PlaceHolderType::Graph: | |
89 | m_PlaceBackground->setStyleSheet( |
|
88 | m_PlaceBackground->setStyleSheet( | |
90 | "background-color: #BBD5EE; border: 1px solid #2A7FD4"); |
|
89 | "background-color: #BBD5EE; border: 1px solid #2A7FD4"); | |
91 | break; |
|
90 | break; | |
92 | case DragDropGuiController::PlaceHolderType::Zone: |
|
91 | case DragDropGuiController::PlaceHolderType::Zone: | |
93 | case DragDropGuiController::PlaceHolderType::Default: |
|
92 | case DragDropGuiController::PlaceHolderType::Default: | |
94 | m_PlaceBackground->setStyleSheet( |
|
93 | m_PlaceBackground->setStyleSheet( | |
95 | "background-color: #BBD5EE; border: 2px solid #2A7FD4"); |
|
94 | "background-color: #BBD5EE; border: 2px solid #2A7FD4"); | |
96 | m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4"); |
|
95 | m_PlaceHolderLabel->setStyleSheet("color: #2A7FD4"); | |
97 | break; |
|
96 | break; | |
98 | } |
|
97 | } | |
99 |
|
98 | |||
100 | m_PlaceHolderLabel->setText(topLabelText); |
|
99 | m_PlaceHolderLabel->setText(topLabelText); | |
101 | m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty()); |
|
100 | m_PlaceHolderLabel->setVisible(!topLabelText.isEmpty()); | |
102 | } |
|
101 | } | |
103 | }; |
|
102 | }; | |
104 |
|
103 | |||
105 |
|
104 | |||
106 | DragDropGuiController::DragDropGuiController() |
|
105 | DragDropGuiController::DragDropGuiController() | |
107 | : impl { spimpl::make_unique_impl<DragDropGuiControllerPrivate>() } |
|
106 | : impl { spimpl::make_unique_impl<DragDropGuiControllerPrivate>() } | |
108 | { |
|
107 | { | |
109 | } |
|
108 | } | |
110 |
|
109 | |||
111 | DragDropGuiController::~DragDropGuiController() |
|
110 | DragDropGuiController::~DragDropGuiController() | |
112 | { |
|
111 | { | |
113 | QFile::remove(impl->m_ImageTempUrl); |
|
112 | QFile::remove(impl->m_ImageTempUrl); | |
114 | } |
|
113 | } | |
115 |
|
114 | |||
116 | void DragDropGuiController::resetDragAndDrop() |
|
115 | void DragDropGuiController::resetDragAndDrop() | |
117 | { |
|
116 | { | |
118 | setCurrentDragWidget(nullptr); |
|
117 | setCurrentDragWidget(nullptr); | |
119 | impl->m_HighlightedDragWidget = nullptr; |
|
118 | impl->m_HighlightedDragWidget = nullptr; | |
120 | } |
|
119 | } | |
121 |
|
120 | |||
122 | void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget* dragWidget) |
|
121 | void DragDropGuiController::setCurrentDragWidget(VisualizationDragWidget* dragWidget) | |
123 | { |
|
122 | { | |
124 | if (impl->m_CurrentDragWidget) |
|
123 | if (impl->m_CurrentDragWidget) | |
125 | { |
|
124 | { | |
126 |
|
125 | |||
127 | QObject::disconnect(impl->m_DragWidgetDestroyedConnection); |
|
126 | QObject::disconnect(impl->m_DragWidgetDestroyedConnection); | |
128 | } |
|
127 | } | |
129 |
|
128 | |||
130 | if (dragWidget) |
|
129 | if (dragWidget) | |
131 | { |
|
130 | { | |
132 | // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed |
|
131 | // ensures the impl->m_CurrentDragWidget is reset when the widget is destroyed | |
133 | impl->m_DragWidgetDestroyedConnection = QObject::connect(dragWidget, |
|
132 | impl->m_DragWidgetDestroyedConnection = QObject::connect(dragWidget, | |
134 | &VisualizationDragWidget::destroyed, [this]() { impl->m_CurrentDragWidget = nullptr; }); |
|
133 | &VisualizationDragWidget::destroyed, [this]() { impl->m_CurrentDragWidget = nullptr; }); | |
135 | } |
|
134 | } | |
136 |
|
135 | |||
137 | impl->m_CurrentDragWidget = dragWidget; |
|
136 | impl->m_CurrentDragWidget = dragWidget; | |
138 | } |
|
137 | } | |
139 |
|
138 | |||
140 | VisualizationDragWidget* DragDropGuiController::getCurrentDragWidget() const |
|
139 | VisualizationDragWidget* DragDropGuiController::getCurrentDragWidget() const | |
141 | { |
|
140 | { | |
142 | return impl->m_CurrentDragWidget; |
|
141 | return impl->m_CurrentDragWidget; | |
143 | } |
|
142 | } | |
144 |
|
143 | |||
145 | QWidget& DragDropGuiController::placeHolder() const |
|
144 | QWidget& DragDropGuiController::placeHolder() const | |
146 | { |
|
145 | { | |
147 | return *impl->m_PlaceHolder; |
|
146 | return *impl->m_PlaceHolder; | |
148 | } |
|
147 | } | |
149 |
|
148 | |||
150 | void DragDropGuiController::insertPlaceHolder( |
|
149 | void DragDropGuiController::insertPlaceHolder( | |
151 | QVBoxLayout* layout, int index, PlaceHolderType type, const QString& topLabelText) |
|
150 | QVBoxLayout* layout, int index, PlaceHolderType type, const QString& topLabelText) | |
152 | { |
|
151 | { | |
153 | removePlaceHolder(); |
|
152 | removePlaceHolder(); | |
154 | impl->preparePlaceHolder(type, topLabelText); |
|
153 | impl->preparePlaceHolder(type, topLabelText); | |
155 | layout->insertWidget(index, impl->m_PlaceHolder.get()); |
|
154 | layout->insertWidget(index, impl->m_PlaceHolder.get()); | |
156 | impl->m_PlaceHolder->show(); |
|
155 | impl->m_PlaceHolder->show(); | |
157 | } |
|
156 | } | |
158 |
|
157 | |||
159 | void DragDropGuiController::removePlaceHolder() |
|
158 | void DragDropGuiController::removePlaceHolder() | |
160 | { |
|
159 | { | |
161 | auto parentWidget = impl->m_PlaceHolder->parentWidget(); |
|
160 | auto parentWidget = impl->m_PlaceHolder->parentWidget(); | |
162 | if (parentWidget) |
|
161 | if (parentWidget) | |
163 | { |
|
162 | { | |
164 | parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get()); |
|
163 | parentWidget->layout()->removeWidget(impl->m_PlaceHolder.get()); | |
165 | impl->m_PlaceHolder->setParent(nullptr); |
|
164 | impl->m_PlaceHolder->setParent(nullptr); | |
166 | impl->m_PlaceHolder->hide(); |
|
165 | impl->m_PlaceHolder->hide(); | |
167 | } |
|
166 | } | |
168 | } |
|
167 | } | |
169 |
|
168 | |||
170 | bool DragDropGuiController::isPlaceHolderSet() const |
|
169 | bool DragDropGuiController::isPlaceHolderSet() const | |
171 | { |
|
170 | { | |
172 | return impl->m_PlaceHolder->parentWidget(); |
|
171 | return impl->m_PlaceHolder->parentWidget(); | |
173 | } |
|
172 | } | |
174 |
|
173 | |||
175 | void DragDropGuiController::addDragDropScrollArea(QScrollArea* scrollArea) |
|
174 | void DragDropGuiController::addDragDropScrollArea(QScrollArea* scrollArea) | |
176 | { |
|
175 | { | |
177 | impl->m_DragDropScroller->addScrollArea(scrollArea); |
|
176 | impl->m_DragDropScroller->addScrollArea(scrollArea); | |
178 | } |
|
177 | } | |
179 |
|
178 | |||
180 | void DragDropGuiController::removeDragDropScrollArea(QScrollArea* scrollArea) |
|
179 | void DragDropGuiController::removeDragDropScrollArea(QScrollArea* scrollArea) | |
181 | { |
|
180 | { | |
182 | impl->m_DragDropScroller->removeScrollArea(scrollArea); |
|
181 | impl->m_DragDropScroller->removeScrollArea(scrollArea); | |
183 | } |
|
182 | } | |
184 |
|
183 | |||
185 | void DragDropGuiController::addDragDropTabBar(QTabBar* tabBar) |
|
184 | void DragDropGuiController::addDragDropTabBar(QTabBar* tabBar) | |
186 | { |
|
185 | { | |
187 | impl->m_DragDropTabSwitcher->addTabBar(tabBar); |
|
186 | impl->m_DragDropTabSwitcher->addTabBar(tabBar); | |
188 | } |
|
187 | } | |
189 |
|
188 | |||
190 | void DragDropGuiController::removeDragDropTabBar(QTabBar* tabBar) |
|
189 | void DragDropGuiController::removeDragDropTabBar(QTabBar* tabBar) | |
191 | { |
|
190 | { | |
192 | impl->m_DragDropTabSwitcher->removeTabBar(tabBar); |
|
191 | impl->m_DragDropTabSwitcher->removeTabBar(tabBar); | |
193 | } |
|
192 | } | |
194 |
|
193 | |||
195 | QUrl DragDropGuiController::imageTemporaryUrl(const QImage& image) const |
|
194 | QUrl DragDropGuiController::imageTemporaryUrl(const QImage& image) const | |
196 | { |
|
195 | { | |
197 | image.save(impl->m_ImageTempUrl); |
|
196 | image.save(impl->m_ImageTempUrl); | |
198 | return QUrl::fromLocalFile(impl->m_ImageTempUrl); |
|
197 | return QUrl::fromLocalFile(impl->m_ImageTempUrl); | |
199 | } |
|
198 | } | |
200 |
|
199 | |||
201 | void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget* dragWidget) |
|
200 | void DragDropGuiController::setHightlightedDragWidget(VisualizationDragWidget* dragWidget) | |
202 | { |
|
201 | { | |
203 | if (impl->m_HighlightedDragWidget) |
|
202 | if (impl->m_HighlightedDragWidget) | |
204 | { |
|
203 | { | |
205 | impl->m_HighlightedDragWidget->highlightForMerge(false); |
|
204 | impl->m_HighlightedDragWidget->highlightForMerge(false); | |
206 | QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection); |
|
205 | QObject::disconnect(impl->m_HighlightedWidgetDestroyedConnection); | |
207 | } |
|
206 | } | |
208 |
|
207 | |||
209 | if (dragWidget) |
|
208 | if (dragWidget) | |
210 | { |
|
209 | { | |
211 | dragWidget->highlightForMerge(true); |
|
210 | dragWidget->highlightForMerge(true); | |
212 |
|
211 | |||
213 | // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed |
|
212 | // ensures the impl->m_HighlightedDragWidget is reset when the widget is destroyed | |
214 | impl->m_DragWidgetDestroyedConnection |
|
213 | impl->m_DragWidgetDestroyedConnection | |
215 | = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed, |
|
214 | = QObject::connect(dragWidget, &VisualizationDragWidget::destroyed, | |
216 | [this]() { impl->m_HighlightedDragWidget = nullptr; }); |
|
215 | [this]() { impl->m_HighlightedDragWidget = nullptr; }); | |
217 | } |
|
216 | } | |
218 |
|
217 | |||
219 | impl->m_HighlightedDragWidget = dragWidget; |
|
218 | impl->m_HighlightedDragWidget = dragWidget; | |
220 | } |
|
219 | } | |
221 |
|
220 | |||
222 | VisualizationDragWidget* DragDropGuiController::getHightlightedDragWidget() const |
|
221 | VisualizationDragWidget* DragDropGuiController::getHightlightedDragWidget() const | |
223 | { |
|
222 | { | |
224 | return impl->m_HighlightedDragWidget; |
|
223 | return impl->m_HighlightedDragWidget; | |
225 | } |
|
224 | } | |
226 |
|
225 | |||
227 | void DragDropGuiController::delayedCloseWidget(QWidget* widget) |
|
226 | void DragDropGuiController::delayedCloseWidget(QWidget* widget) | |
228 | { |
|
227 | { | |
229 | widget->hide(); |
|
228 | widget->hide(); | |
230 | impl->m_WidgetToClose << widget; |
|
229 | impl->m_WidgetToClose << widget; | |
231 | } |
|
230 | } | |
232 |
|
231 | |||
233 | void DragDropGuiController::doCloseWidgets() |
|
232 | void DragDropGuiController::doCloseWidgets() | |
234 | { |
|
233 | { | |
235 | for (auto widget : impl->m_WidgetToClose) |
|
234 | for (auto widget : impl->m_WidgetToClose) | |
236 | { |
|
235 | { | |
237 | widget->close(); |
|
236 | widget->close(); | |
238 | } |
|
237 | } | |
239 |
|
238 | |||
240 | impl->m_WidgetToClose.clear(); |
|
239 | impl->m_WidgetToClose.clear(); | |
241 | } |
|
240 | } | |
242 |
|
241 | |||
243 | bool DragDropGuiController::checkMimeDataForVisualization( |
|
242 | bool DragDropGuiController::checkMimeDataForVisualization( | |
244 | const QMimeData* mimeData, VisualizationDragDropContainer* dropContainer) |
|
243 | const QMimeData* mimeData, VisualizationDragDropContainer* dropContainer) | |
245 | { |
|
244 | { | |
246 | if (!mimeData || !dropContainer) |
|
245 | if (!mimeData || !dropContainer) | |
247 | { |
|
246 | { | |
248 | qCWarning(LOG_DragDropGuiController()) << QObject::tr( |
|
247 | qCWarning(LOG_DragDropGuiController()) << QObject::tr( | |
249 | "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters."); |
|
248 | "DragDropGuiController::checkMimeDataForVisualization, invalid input parameters."); | |
250 | Q_ASSERT(false); |
|
249 | Q_ASSERT(false); | |
251 | return false; |
|
250 | return false; | |
252 | } |
|
251 | } | |
253 |
|
252 | |||
254 | auto result = false; |
|
253 | auto result = false; | |
255 |
|
254 | |||
256 | if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) |
|
255 | if (mimeData->hasFormat(MIME_TYPE_VARIABLE_LIST)) | |
257 | { |
|
256 | { | |
258 | auto variables = sqpApp->variableController().variables( |
|
257 | auto variables = sqpApp->variableController().variables( | |
259 |
Variable:: |
|
258 | Variable2::IDs(mimeData->data(MIME_TYPE_VARIABLE_LIST))); | |
260 |
|
259 | |||
261 | if (variables.size() == 1) |
|
260 | if (variables.size() == 1) | |
262 | { |
|
261 | { | |
263 |
|
262 | |||
264 | auto variable = variables[0]; |
|
263 | auto variable = variables[0]; | |
265 | if (variable->data() != nullptr) |
|
264 | if (variable->data() != nullptr) | |
266 | { |
|
265 | { | |
267 |
|
266 | |||
268 | // Check that the variable is not already in a graph |
|
267 | // Check that the variable is not already in a graph | |
269 |
|
268 | |||
270 | auto parent = dropContainer->parentWidget(); |
|
269 | auto parent = dropContainer->parentWidget(); | |
271 | while (parent && qobject_cast<VisualizationWidget*>(parent) == nullptr) |
|
270 | while (parent && qobject_cast<VisualizationWidget*>(parent) == nullptr) | |
272 | { |
|
271 | { | |
273 | parent = parent->parentWidget(); // Search for the top level VisualizationWidget |
|
272 | parent = parent->parentWidget(); // Search for the top level VisualizationWidget | |
274 | } |
|
273 | } | |
275 |
|
274 | |||
276 | if (parent) |
|
275 | if (parent) | |
277 | { |
|
276 | { | |
278 | auto visualizationWidget = static_cast<VisualizationWidget*>(parent); |
|
277 | auto visualizationWidget = static_cast<VisualizationWidget*>(parent); | |
279 |
|
278 | |||
280 | FindVariableOperation findVariableOperation { variable }; |
|
279 | FindVariableOperation findVariableOperation { variable }; | |
281 | visualizationWidget->accept(&findVariableOperation); |
|
280 | visualizationWidget->accept(&findVariableOperation); | |
282 | auto variableContainers = findVariableOperation.result(); |
|
281 | auto variableContainers = findVariableOperation.result(); | |
283 | if (variableContainers.empty()) |
|
282 | if (variableContainers.empty()) | |
284 | { |
|
283 | { | |
285 | result = true; |
|
284 | result = true; | |
286 | } |
|
285 | } | |
287 | else |
|
286 | else | |
288 | { |
|
287 | { | |
289 | // result = false: the variable already exist in the visualisation |
|
288 | // result = false: the variable already exist in the visualisation | |
290 | } |
|
289 | } | |
291 | } |
|
290 | } | |
292 | else |
|
291 | else | |
293 | { |
|
292 | { | |
294 | qCWarning(LOG_DragDropGuiController()) << QObject::tr( |
|
293 | qCWarning(LOG_DragDropGuiController()) << QObject::tr( | |
295 | "DragDropGuiController::checkMimeDataForVisualization, the parent " |
|
294 | "DragDropGuiController::checkMimeDataForVisualization, the parent " | |
296 | "VisualizationWidget cannot be found. Cannot check if the variable is " |
|
295 | "VisualizationWidget cannot be found. Cannot check if the variable is " | |
297 | "already used or not."); |
|
296 | "already used or not."); | |
298 | } |
|
297 | } | |
299 | } |
|
298 | } | |
300 | else |
|
299 | else | |
301 | { |
|
300 | { | |
302 | // result = false: the variable is not fully loaded |
|
301 | // result = false: the variable is not fully loaded | |
303 | } |
|
302 | } | |
304 | } |
|
303 | } | |
305 | else |
|
304 | else | |
306 | { |
|
305 | { | |
307 | // result = false: cannot drop multiple variables in the visualisation |
|
306 | // result = false: cannot drop multiple variables in the visualisation | |
308 | } |
|
307 | } | |
309 | } |
|
308 | } | |
310 | else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) |
|
309 | else if (mimeData->hasFormat(MIME_TYPE_PRODUCT_LIST)) | |
311 | { |
|
310 | { | |
312 | auto productDataList = sqpApp->dataSourceController().productsDataForMimeData( |
|
311 | auto productDataList = sqpApp->dataSourceController().productsDataForMimeData( | |
313 | mimeData->data(MIME_TYPE_PRODUCT_LIST)); |
|
312 | mimeData->data(MIME_TYPE_PRODUCT_LIST)); | |
314 | if (productDataList.count() == 1) |
|
313 | if (productDataList.count() == 1) | |
315 | { |
|
314 | { | |
316 | result = true; |
|
315 | result = true; | |
317 | } |
|
316 | } | |
318 | else |
|
317 | else | |
319 | { |
|
318 | { | |
320 | // result = false: cannot drop multiple products in the visualisation |
|
319 | // result = false: cannot drop multiple products in the visualisation | |
321 | } |
|
320 | } | |
322 | } |
|
321 | } | |
323 | else |
|
322 | else | |
324 | { |
|
323 | { | |
325 | // Other MIME data |
|
324 | // Other MIME data | |
326 | // no special rules, accepted by default |
|
325 | // no special rules, accepted by default | |
327 | result = true; |
|
326 | result = true; | |
328 | } |
|
327 | } | |
329 |
|
328 | |||
330 |
|
329 | |||
331 | return result; |
|
330 | return result; | |
332 | } |
|
331 | } |
@@ -1,193 +1,192 | |||||
1 | #include "SqpApplication.h" |
|
1 | #include "SqpApplication.h" | |
2 |
|
2 | |||
3 | #include <Actions/ActionsGuiController.h> |
|
3 | #include <Actions/ActionsGuiController.h> | |
4 | #include <Catalogue/CatalogueController.h> |
|
4 | #include <Catalogue/CatalogueController.h> | |
5 | #include <Data/IDataProvider.h> |
|
5 | #include <Data/IDataProvider.h> | |
6 | #include <DataSource/DataSourceController.h> |
|
6 | #include <DataSource/DataSourceController.h> | |
7 | #include <DragAndDrop/DragDropGuiController.h> |
|
7 | #include <DragAndDrop/DragDropGuiController.h> | |
8 | #include <Network/NetworkController.h> |
|
8 | #include <Network/NetworkController.h> | |
9 | #include <QThread> |
|
9 | #include <QThread> | |
10 | #include <Time/TimeController.h> |
|
10 | #include <Time/TimeController.h> | |
11 | #include <Variable/Variable.h> |
|
|||
12 | #include <Variable/VariableController2.h> |
|
11 | #include <Variable/VariableController2.h> | |
13 | #include <Variable/VariableModel2.h> |
|
12 | #include <Variable/VariableModel2.h> | |
14 | #include <Visualization/VisualizationController.h> |
|
13 | #include <Visualization/VisualizationController.h> | |
15 |
|
14 | |||
16 | Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication") |
|
15 | Q_LOGGING_CATEGORY(LOG_SqpApplication, "SqpApplication") | |
17 |
|
16 | |||
18 | class SqpApplication::SqpApplicationPrivate |
|
17 | class SqpApplication::SqpApplicationPrivate | |
19 | { |
|
18 | { | |
20 | public: |
|
19 | public: | |
21 | SqpApplicationPrivate() |
|
20 | SqpApplicationPrivate() | |
22 | : m_VariableController { std::make_shared<VariableController2>() } |
|
21 | : m_VariableController { std::make_shared<VariableController2>() } | |
23 | , m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None) |
|
22 | , m_PlotInterractionMode(SqpApplication::PlotsInteractionMode::None) | |
24 | , m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor) |
|
23 | , m_PlotCursorMode(SqpApplication::PlotsCursorMode::NoCursor) | |
25 | { |
|
24 | { | |
26 | // /////////////////////////////// // |
|
25 | // /////////////////////////////// // | |
27 | // Connections between controllers // |
|
26 | // Connections between controllers // | |
28 | // /////////////////////////////// // |
|
27 | // /////////////////////////////// // | |
29 |
|
28 | |||
30 | // VariableController <-> DataSourceController |
|
29 | // VariableController <-> DataSourceController | |
31 | connect(&m_DataSourceController, &DataSourceController::createVariable, |
|
30 | connect(&m_DataSourceController, &DataSourceController::createVariable, | |
32 | [](const QString& variableName, const QVariantHash& variableMetadata, |
|
31 | [](const QString& variableName, const QVariantHash& variableMetadata, | |
33 | std::shared_ptr<IDataProvider> variableProvider) { |
|
32 | std::shared_ptr<IDataProvider> variableProvider) { | |
34 | sqpApp->variableController().createVariable(variableName, variableMetadata, |
|
33 | sqpApp->variableController().createVariable(variableName, variableMetadata, | |
35 | variableProvider, sqpApp->timeController().dateTime()); |
|
34 | variableProvider, sqpApp->timeController().dateTime()); | |
36 | }); |
|
35 | }); | |
37 |
|
36 | |||
38 | // VariableController <-> VisualizationController |
|
37 | // VariableController <-> VisualizationController | |
39 | // connect(m_VariableController.get(), |
|
38 | // connect(m_VariableController.get(), | |
40 | // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), |
|
39 | // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), | |
41 | // m_VisualizationController.get(), |
|
40 | // m_VisualizationController.get(), | |
42 | // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), |
|
41 | // SIGNAL(variableAboutToBeDeleted(std::shared_ptr<Variable>)), | |
43 | // Qt::DirectConnection); |
|
42 | // Qt::DirectConnection); | |
44 |
|
43 | |||
45 | // connect(m_VariableController.get(), |
|
44 | // connect(m_VariableController.get(), | |
46 | // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)), |
|
45 | // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &)), | |
47 | // m_VisualizationController.get(), |
|
46 | // m_VisualizationController.get(), | |
48 | // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &))); |
|
47 | // SIGNAL(rangeChanged(std::shared_ptr<Variable>, const DateTimeRange &))); | |
49 |
|
48 | |||
50 |
|
49 | |||
51 | m_DataSourceController.moveToThread(&m_DataSourceControllerThread); |
|
50 | m_DataSourceController.moveToThread(&m_DataSourceControllerThread); | |
52 | m_DataSourceControllerThread.setObjectName("DataSourceControllerThread"); |
|
51 | m_DataSourceControllerThread.setObjectName("DataSourceControllerThread"); | |
53 | m_NetworkController.moveToThread(&m_NetworkControllerThread); |
|
52 | m_NetworkController.moveToThread(&m_NetworkControllerThread); | |
54 | m_NetworkControllerThread.setObjectName("NetworkControllerThread"); |
|
53 | m_NetworkControllerThread.setObjectName("NetworkControllerThread"); | |
55 | m_VisualizationController.moveToThread(&m_VisualizationControllerThread); |
|
54 | m_VisualizationController.moveToThread(&m_VisualizationControllerThread); | |
56 | m_VisualizationControllerThread.setObjectName("VsualizationControllerThread"); |
|
55 | m_VisualizationControllerThread.setObjectName("VsualizationControllerThread"); | |
57 |
|
56 | |||
58 | // Additionnal init |
|
57 | // Additionnal init | |
59 | // m_VariableController->setTimeController(m_TimeController.get()); |
|
58 | // m_VariableController->setTimeController(m_TimeController.get()); | |
60 | } |
|
59 | } | |
61 |
|
60 | |||
62 | virtual ~SqpApplicationPrivate() |
|
61 | virtual ~SqpApplicationPrivate() | |
63 | { |
|
62 | { | |
64 | m_DataSourceControllerThread.quit(); |
|
63 | m_DataSourceControllerThread.quit(); | |
65 | m_DataSourceControllerThread.wait(); |
|
64 | m_DataSourceControllerThread.wait(); | |
66 |
|
65 | |||
67 | m_NetworkControllerThread.quit(); |
|
66 | m_NetworkControllerThread.quit(); | |
68 | m_NetworkControllerThread.wait(); |
|
67 | m_NetworkControllerThread.wait(); | |
69 |
|
68 | |||
70 | m_VisualizationControllerThread.quit(); |
|
69 | m_VisualizationControllerThread.quit(); | |
71 | m_VisualizationControllerThread.wait(); |
|
70 | m_VisualizationControllerThread.wait(); | |
72 | } |
|
71 | } | |
73 |
|
72 | |||
74 | DataSourceController m_DataSourceController; |
|
73 | DataSourceController m_DataSourceController; | |
75 | std::shared_ptr<VariableController2> m_VariableController; |
|
74 | std::shared_ptr<VariableController2> m_VariableController; | |
76 | TimeController m_TimeController; |
|
75 | TimeController m_TimeController; | |
77 | NetworkController m_NetworkController; |
|
76 | NetworkController m_NetworkController; | |
78 | VisualizationController m_VisualizationController; |
|
77 | VisualizationController m_VisualizationController; | |
79 | CatalogueController m_CatalogueController; |
|
78 | CatalogueController m_CatalogueController; | |
80 |
|
79 | |||
81 | QThread m_DataSourceControllerThread; |
|
80 | QThread m_DataSourceControllerThread; | |
82 | QThread m_NetworkControllerThread; |
|
81 | QThread m_NetworkControllerThread; | |
83 | QThread m_VisualizationControllerThread; |
|
82 | QThread m_VisualizationControllerThread; | |
84 |
|
83 | |||
85 | DragDropGuiController m_DragDropGuiController; |
|
84 | DragDropGuiController m_DragDropGuiController; | |
86 | ActionsGuiController m_ActionsGuiController; |
|
85 | ActionsGuiController m_ActionsGuiController; | |
87 |
|
86 | |||
88 | SqpApplication::PlotsInteractionMode m_PlotInterractionMode; |
|
87 | SqpApplication::PlotsInteractionMode m_PlotInterractionMode; | |
89 | SqpApplication::PlotsCursorMode m_PlotCursorMode; |
|
88 | SqpApplication::PlotsCursorMode m_PlotCursorMode; | |
90 | }; |
|
89 | }; | |
91 |
|
90 | |||
92 |
|
91 | |||
93 | SqpApplication::SqpApplication(int& argc, char** argv) |
|
92 | SqpApplication::SqpApplication(int& argc, char** argv) | |
94 | : QApplication { argc, argv }, impl { spimpl::make_unique_impl<SqpApplicationPrivate>() } |
|
93 | : QApplication { argc, argv }, impl { spimpl::make_unique_impl<SqpApplicationPrivate>() } | |
95 | { |
|
94 | { | |
96 | qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread(); |
|
95 | qCDebug(LOG_SqpApplication()) << tr("SqpApplication construction") << QThread::currentThread(); | |
97 |
|
96 | |||
98 | QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); |
|
97 | QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); | |
99 |
|
98 | |||
100 | connect(&impl->m_DataSourceControllerThread, &QThread::started, &impl->m_DataSourceController, |
|
99 | connect(&impl->m_DataSourceControllerThread, &QThread::started, &impl->m_DataSourceController, | |
101 | &DataSourceController::initialize); |
|
100 | &DataSourceController::initialize); | |
102 | connect(&impl->m_DataSourceControllerThread, &QThread::finished, &impl->m_DataSourceController, |
|
101 | connect(&impl->m_DataSourceControllerThread, &QThread::finished, &impl->m_DataSourceController, | |
103 | &DataSourceController::finalize); |
|
102 | &DataSourceController::finalize); | |
104 |
|
103 | |||
105 | connect(&impl->m_NetworkControllerThread, &QThread::started, &impl->m_NetworkController, |
|
104 | connect(&impl->m_NetworkControllerThread, &QThread::started, &impl->m_NetworkController, | |
106 | &NetworkController::initialize); |
|
105 | &NetworkController::initialize); | |
107 | connect(&impl->m_NetworkControllerThread, &QThread::finished, &impl->m_NetworkController, |
|
106 | connect(&impl->m_NetworkControllerThread, &QThread::finished, &impl->m_NetworkController, | |
108 | &NetworkController::finalize); |
|
107 | &NetworkController::finalize); | |
109 |
|
108 | |||
110 | connect(&impl->m_VisualizationControllerThread, &QThread::started, |
|
109 | connect(&impl->m_VisualizationControllerThread, &QThread::started, | |
111 | &impl->m_VisualizationController, &VisualizationController::initialize); |
|
110 | &impl->m_VisualizationController, &VisualizationController::initialize); | |
112 | connect(&impl->m_VisualizationControllerThread, &QThread::finished, |
|
111 | connect(&impl->m_VisualizationControllerThread, &QThread::finished, | |
113 | &impl->m_VisualizationController, &VisualizationController::finalize); |
|
112 | &impl->m_VisualizationController, &VisualizationController::finalize); | |
114 |
|
113 | |||
115 | impl->m_DataSourceControllerThread.start(); |
|
114 | impl->m_DataSourceControllerThread.start(); | |
116 | impl->m_NetworkControllerThread.start(); |
|
115 | impl->m_NetworkControllerThread.start(); | |
117 | impl->m_VisualizationControllerThread.start(); |
|
116 | impl->m_VisualizationControllerThread.start(); | |
118 | // impl->m_CatalogueController.initialize(); |
|
117 | // impl->m_CatalogueController.initialize(); | |
119 | } |
|
118 | } | |
120 |
|
119 | |||
121 | SqpApplication::~SqpApplication() {} |
|
120 | SqpApplication::~SqpApplication() {} | |
122 |
|
121 | |||
123 | void SqpApplication::initialize() {} |
|
122 | void SqpApplication::initialize() {} | |
124 |
|
123 | |||
125 | DataSourceController& SqpApplication::dataSourceController() noexcept |
|
124 | DataSourceController& SqpApplication::dataSourceController() noexcept | |
126 | { |
|
125 | { | |
127 | return impl->m_DataSourceController; |
|
126 | return impl->m_DataSourceController; | |
128 | } |
|
127 | } | |
129 |
|
128 | |||
130 | NetworkController& SqpApplication::networkController() noexcept |
|
129 | NetworkController& SqpApplication::networkController() noexcept | |
131 | { |
|
130 | { | |
132 | return impl->m_NetworkController; |
|
131 | return impl->m_NetworkController; | |
133 | } |
|
132 | } | |
134 |
|
133 | |||
135 | TimeController& SqpApplication::timeController() noexcept |
|
134 | TimeController& SqpApplication::timeController() noexcept | |
136 | { |
|
135 | { | |
137 | return impl->m_TimeController; |
|
136 | return impl->m_TimeController; | |
138 | } |
|
137 | } | |
139 |
|
138 | |||
140 | VariableController2& SqpApplication::variableController() noexcept |
|
139 | VariableController2& SqpApplication::variableController() noexcept | |
141 | { |
|
140 | { | |
142 | return *impl->m_VariableController; |
|
141 | return *impl->m_VariableController; | |
143 | } |
|
142 | } | |
144 |
|
143 | |||
145 | std::shared_ptr<VariableController2> SqpApplication::variableControllerOwner() noexcept |
|
144 | std::shared_ptr<VariableController2> SqpApplication::variableControllerOwner() noexcept | |
146 | { |
|
145 | { | |
147 | return impl->m_VariableController; |
|
146 | return impl->m_VariableController; | |
148 | } |
|
147 | } | |
149 |
|
148 | |||
150 | // VariableModel2 &SqpApplication::variableModel() noexcept |
|
149 | // VariableModel2 &SqpApplication::variableModel() noexcept | |
151 | //{ |
|
150 | //{ | |
152 | // return impl->m_VariableModel; |
|
151 | // return impl->m_VariableModel; | |
153 | //} |
|
152 | //} | |
154 |
|
153 | |||
155 | VisualizationController& SqpApplication::visualizationController() noexcept |
|
154 | VisualizationController& SqpApplication::visualizationController() noexcept | |
156 | { |
|
155 | { | |
157 | return impl->m_VisualizationController; |
|
156 | return impl->m_VisualizationController; | |
158 | } |
|
157 | } | |
159 |
|
158 | |||
160 | CatalogueController& SqpApplication::catalogueController() noexcept |
|
159 | CatalogueController& SqpApplication::catalogueController() noexcept | |
161 | { |
|
160 | { | |
162 | return impl->m_CatalogueController; |
|
161 | return impl->m_CatalogueController; | |
163 | } |
|
162 | } | |
164 |
|
163 | |||
165 | DragDropGuiController& SqpApplication::dragDropGuiController() noexcept |
|
164 | DragDropGuiController& SqpApplication::dragDropGuiController() noexcept | |
166 | { |
|
165 | { | |
167 | return impl->m_DragDropGuiController; |
|
166 | return impl->m_DragDropGuiController; | |
168 | } |
|
167 | } | |
169 |
|
168 | |||
170 | ActionsGuiController& SqpApplication::actionsGuiController() noexcept |
|
169 | ActionsGuiController& SqpApplication::actionsGuiController() noexcept | |
171 | { |
|
170 | { | |
172 | return impl->m_ActionsGuiController; |
|
171 | return impl->m_ActionsGuiController; | |
173 | } |
|
172 | } | |
174 |
|
173 | |||
175 | SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const |
|
174 | SqpApplication::PlotsInteractionMode SqpApplication::plotsInteractionMode() const | |
176 | { |
|
175 | { | |
177 | return impl->m_PlotInterractionMode; |
|
176 | return impl->m_PlotInterractionMode; | |
178 | } |
|
177 | } | |
179 |
|
178 | |||
180 | void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode) |
|
179 | void SqpApplication::setPlotsInteractionMode(SqpApplication::PlotsInteractionMode mode) | |
181 | { |
|
180 | { | |
182 | impl->m_PlotInterractionMode = mode; |
|
181 | impl->m_PlotInterractionMode = mode; | |
183 | } |
|
182 | } | |
184 |
|
183 | |||
185 | SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const |
|
184 | SqpApplication::PlotsCursorMode SqpApplication::plotsCursorMode() const | |
186 | { |
|
185 | { | |
187 | return impl->m_PlotCursorMode; |
|
186 | return impl->m_PlotCursorMode; | |
188 | } |
|
187 | } | |
189 |
|
188 | |||
190 | void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode) |
|
189 | void SqpApplication::setPlotsCursorMode(SqpApplication::PlotsCursorMode mode) | |
191 | { |
|
190 | { | |
192 | impl->m_PlotCursorMode = mode; |
|
191 | impl->m_PlotCursorMode = mode; | |
193 | } |
|
192 | } |
@@ -1,266 +1,265 | |||||
1 | #include <DataSource/DataSourceController.h> |
|
1 | #include <DataSource/DataSourceController.h> | |
2 | #include <Variable/RenameVariableDialog.h> |
|
2 | #include <Variable/RenameVariableDialog.h> | |
3 | #include <Variable/Variable.h> |
|
|||
4 | #include <Variable/VariableController2.h> |
|
3 | #include <Variable/VariableController2.h> | |
5 | #include <Variable/VariableInspectorWidget.h> |
|
4 | #include <Variable/VariableInspectorWidget.h> | |
6 | #include <Variable/VariableMenuHeaderWidget.h> |
|
5 | #include <Variable/VariableMenuHeaderWidget.h> | |
7 | #include <Variable/VariableModel2.h> |
|
6 | #include <Variable/VariableModel2.h> | |
8 |
|
7 | |||
9 | #include <ui_VariableInspectorWidget.h> |
|
8 | #include <ui_VariableInspectorWidget.h> | |
10 |
|
9 | |||
11 | #include <QMouseEvent> |
|
10 | #include <QMouseEvent> | |
12 | #include <QSortFilterProxyModel> |
|
11 | #include <QSortFilterProxyModel> | |
13 | #include <QStyledItemDelegate> |
|
12 | #include <QStyledItemDelegate> | |
14 | #include <QWidgetAction> |
|
13 | #include <QWidgetAction> | |
15 |
|
14 | |||
16 | #include <DragAndDrop/DragDropGuiController.h> |
|
15 | #include <DragAndDrop/DragDropGuiController.h> | |
17 | #include <SqpApplication.h> |
|
16 | #include <SqpApplication.h> | |
18 |
|
17 | |||
19 | Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget") |
|
18 | Q_LOGGING_CATEGORY(LOG_VariableInspectorWidget, "VariableInspectorWidget") | |
20 |
|
19 | |||
21 |
|
20 | |||
22 | class QProgressBarItemDelegate : public QStyledItemDelegate |
|
21 | class QProgressBarItemDelegate : public QStyledItemDelegate | |
23 | { |
|
22 | { | |
24 |
|
23 | |||
25 | public: |
|
24 | public: | |
26 | QProgressBarItemDelegate(QObject* parent) : QStyledItemDelegate { parent } {} |
|
25 | QProgressBarItemDelegate(QObject* parent) : QStyledItemDelegate { parent } {} | |
27 |
|
26 | |||
28 | void paint( |
|
27 | void paint( | |
29 | QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const |
|
28 | QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const | |
30 | { |
|
29 | { | |
31 | auto data = index.data(Qt::DisplayRole); |
|
30 | auto data = index.data(Qt::DisplayRole); | |
32 | auto progressData = index.data(VariableRoles::ProgressRole); |
|
31 | auto progressData = index.data(VariableRoles::ProgressRole); | |
33 | if (data.isValid() && progressData.isValid()) |
|
32 | if (data.isValid() && progressData.isValid()) | |
34 | { |
|
33 | { | |
35 | auto name = data.value<QString>(); |
|
34 | auto name = data.value<QString>(); | |
36 | auto progress = progressData.value<double>(); |
|
35 | auto progress = progressData.value<double>(); | |
37 | if (progress > 0) |
|
36 | if (progress > 0) | |
38 | { |
|
37 | { | |
39 | auto cancelButtonWidth = 20; |
|
38 | auto cancelButtonWidth = 20; | |
40 | auto progressBarOption = QStyleOptionProgressBar {}; |
|
39 | auto progressBarOption = QStyleOptionProgressBar {}; | |
41 | auto progressRect = option.rect; |
|
40 | auto progressRect = option.rect; | |
42 | progressRect.setWidth(progressRect.width() - cancelButtonWidth); |
|
41 | progressRect.setWidth(progressRect.width() - cancelButtonWidth); | |
43 | progressBarOption.rect = progressRect; |
|
42 | progressBarOption.rect = progressRect; | |
44 | progressBarOption.minimum = 0; |
|
43 | progressBarOption.minimum = 0; | |
45 | progressBarOption.maximum = 100; |
|
44 | progressBarOption.maximum = 100; | |
46 | progressBarOption.progress = progress; |
|
45 | progressBarOption.progress = progress; | |
47 | progressBarOption.text |
|
46 | progressBarOption.text | |
48 | = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%"); |
|
47 | = QString("%1 %2").arg(name).arg(QString::number(progress, 'f', 2) + "%"); | |
49 | progressBarOption.textVisible = true; |
|
48 | progressBarOption.textVisible = true; | |
50 | progressBarOption.textAlignment = Qt::AlignCenter; |
|
49 | progressBarOption.textAlignment = Qt::AlignCenter; | |
51 |
|
50 | |||
52 |
|
51 | |||
53 | QApplication::style()->drawControl( |
|
52 | QApplication::style()->drawControl( | |
54 | QStyle::CE_ProgressBar, &progressBarOption, painter); |
|
53 | QStyle::CE_ProgressBar, &progressBarOption, painter); | |
55 |
|
54 | |||
56 | // Cancel button |
|
55 | // Cancel button | |
57 | auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, |
|
56 | auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, | |
58 | option.rect.height()); |
|
57 | option.rect.height()); | |
59 | auto buttonOption = QStyleOptionButton {}; |
|
58 | auto buttonOption = QStyleOptionButton {}; | |
60 | buttonOption.rect = buttonRect; |
|
59 | buttonOption.rect = buttonRect; | |
61 | buttonOption.text = "X"; |
|
60 | buttonOption.text = "X"; | |
62 |
|
61 | |||
63 | QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter); |
|
62 | QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter); | |
64 | } |
|
63 | } | |
65 | else |
|
64 | else | |
66 | { |
|
65 | { | |
67 | QStyledItemDelegate::paint(painter, option, index); |
|
66 | QStyledItemDelegate::paint(painter, option, index); | |
68 | } |
|
67 | } | |
69 | } |
|
68 | } | |
70 | else |
|
69 | else | |
71 | { |
|
70 | { | |
72 | QStyledItemDelegate::paint(painter, option, index); |
|
71 | QStyledItemDelegate::paint(painter, option, index); | |
73 | } |
|
72 | } | |
74 | } |
|
73 | } | |
75 |
|
74 | |||
76 | bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, |
|
75 | bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, | |
77 | const QModelIndex& index) |
|
76 | const QModelIndex& index) | |
78 | { |
|
77 | { | |
79 | if (event->type() == QEvent::MouseButtonRelease) |
|
78 | if (event->type() == QEvent::MouseButtonRelease) | |
80 | { |
|
79 | { | |
81 | auto data = index.data(Qt::DisplayRole); |
|
80 | auto data = index.data(Qt::DisplayRole); | |
82 | auto progressData = index.data(VariableRoles::ProgressRole); |
|
81 | auto progressData = index.data(VariableRoles::ProgressRole); | |
83 | if (data.isValid() && progressData.isValid()) |
|
82 | if (data.isValid() && progressData.isValid()) | |
84 | { |
|
83 | { | |
85 | auto cancelButtonWidth = 20; |
|
84 | auto cancelButtonWidth = 20; | |
86 | auto progressRect = option.rect; |
|
85 | auto progressRect = option.rect; | |
87 | progressRect.setWidth(progressRect.width() - cancelButtonWidth); |
|
86 | progressRect.setWidth(progressRect.width() - cancelButtonWidth); | |
88 | // Cancel button |
|
87 | // Cancel button | |
89 | auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, |
|
88 | auto buttonRect = QRect(progressRect.right(), option.rect.top(), cancelButtonWidth, | |
90 | option.rect.height()); |
|
89 | option.rect.height()); | |
91 |
|
90 | |||
92 | auto e = (QMouseEvent*)event; |
|
91 | auto e = (QMouseEvent*)event; | |
93 | auto clickX = e->x(); |
|
92 | auto clickX = e->x(); | |
94 | auto clickY = e->y(); |
|
93 | auto clickY = e->y(); | |
95 |
|
94 | |||
96 | auto x = buttonRect.left(); // the X coordinate |
|
95 | auto x = buttonRect.left(); // the X coordinate | |
97 | auto y = buttonRect.top(); // the Y coordinate |
|
96 | auto y = buttonRect.top(); // the Y coordinate | |
98 | auto w = buttonRect.width(); // button width |
|
97 | auto w = buttonRect.width(); // button width | |
99 | auto h = buttonRect.height(); // button height |
|
98 | auto h = buttonRect.height(); // button height | |
100 |
|
99 | |||
101 | if (clickX > x && clickX < x + w) |
|
100 | if (clickX > x && clickX < x + w) | |
102 | { |
|
101 | { | |
103 | if (clickY > y && clickY < y + h) |
|
102 | if (clickY > y && clickY < y + h) | |
104 | { |
|
103 | { | |
105 | // auto& variableModel = sqpApp->variableModel(); |
|
104 | // auto& variableModel = sqpApp->variableModel(); | |
106 | // variableModel->abortProgress(index); |
|
105 | // variableModel->abortProgress(index); | |
107 | } |
|
106 | } | |
108 | return true; |
|
107 | return true; | |
109 | } |
|
108 | } | |
110 | else |
|
109 | else | |
111 | { |
|
110 | { | |
112 | return QStyledItemDelegate::editorEvent(event, model, option, index); |
|
111 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |
113 | } |
|
112 | } | |
114 | } |
|
113 | } | |
115 | else |
|
114 | else | |
116 | { |
|
115 | { | |
117 | return QStyledItemDelegate::editorEvent(event, model, option, index); |
|
116 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |
118 | } |
|
117 | } | |
119 | } |
|
118 | } | |
120 | else |
|
119 | else | |
121 | { |
|
120 | { | |
122 | return QStyledItemDelegate::editorEvent(event, model, option, index); |
|
121 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |
123 | } |
|
122 | } | |
124 |
|
123 | |||
125 |
|
124 | |||
126 | return QStyledItemDelegate::editorEvent(event, model, option, index); |
|
125 | return QStyledItemDelegate::editorEvent(event, model, option, index); | |
127 | } |
|
126 | } | |
128 | }; |
|
127 | }; | |
129 |
|
128 | |||
130 | VariableInspectorWidget::VariableInspectorWidget(QWidget* parent) |
|
129 | VariableInspectorWidget::VariableInspectorWidget(QWidget* parent) | |
131 | : QWidget { parent } |
|
130 | : QWidget { parent } | |
132 | , ui { new Ui::VariableInspectorWidget } |
|
131 | , ui { new Ui::VariableInspectorWidget } | |
133 | , m_ProgressBarItemDelegate { new QProgressBarItemDelegate { this } } |
|
132 | , m_ProgressBarItemDelegate { new QProgressBarItemDelegate { this } } | |
134 | { |
|
133 | { | |
135 | ui->setupUi(this); |
|
134 | ui->setupUi(this); | |
136 |
|
135 | |||
137 | // Sets model for table |
|
136 | // Sets model for table | |
138 | // auto sortFilterModel = new QSortFilterProxyModel{this}; |
|
137 | // auto sortFilterModel = new QSortFilterProxyModel{this}; | |
139 | // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel()); |
|
138 | // sortFilterModel->setSourceModel(sqpApp->variableController().variableModel()); | |
140 |
|
139 | |||
141 | m_model = new VariableModel2(); |
|
140 | m_model = new VariableModel2(); | |
142 | ui->tableView->setModel(m_model); |
|
141 | ui->tableView->setModel(m_model); | |
143 | connect(m_model, &VariableModel2::createVariable, [](const QVariantHash& productData) { |
|
142 | connect(m_model, &VariableModel2::createVariable, [](const QVariantHash& productData) { | |
144 | sqpApp->dataSourceController().requestVariable(productData); |
|
143 | sqpApp->dataSourceController().requestVariable(productData); | |
145 | }); |
|
144 | }); | |
146 | auto vc = &(sqpApp->variableController()); |
|
145 | auto vc = &(sqpApp->variableController()); | |
147 | connect(vc, &VariableController2::variableAdded, m_model, &VariableModel2::variableAdded); |
|
146 | connect(vc, &VariableController2::variableAdded, m_model, &VariableModel2::variableAdded); | |
148 | connect(vc, &VariableController2::variableDeleted, m_model, &VariableModel2::variableDeleted); |
|
147 | connect(vc, &VariableController2::variableDeleted, m_model, &VariableModel2::variableDeleted); | |
149 | connect(m_model, &VariableModel2::asyncChangeRange, vc, &VariableController2::asyncChangeRange); |
|
148 | connect(m_model, &VariableModel2::asyncChangeRange, vc, &VariableController2::asyncChangeRange); | |
150 |
|
149 | |||
151 | // Adds extra signal/slot between view and model, so the view can be updated instantly when |
|
150 | // Adds extra signal/slot between view and model, so the view can be updated instantly when | |
152 | // there is a change of data in the model |
|
151 | // there is a change of data in the model | |
153 | // connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, |
|
152 | // connect(m_model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), this, | |
154 | // SLOT(refresh())); |
|
153 | // SLOT(refresh())); | |
155 |
|
154 | |||
156 | // ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel()); |
|
155 | // ui->tableView->setSelectionModel(sqpApp->variableController().variableSelectionModel()); | |
157 | ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate); |
|
156 | ui->tableView->setItemDelegateForColumn(0, m_ProgressBarItemDelegate); | |
158 |
|
157 | |||
159 | // Fixes column sizes |
|
158 | // Fixes column sizes | |
160 | auto model = ui->tableView->model(); |
|
159 | auto model = ui->tableView->model(); | |
161 | const auto count = model->columnCount(); |
|
160 | const auto count = model->columnCount(); | |
162 | for (auto i = 0; i < count; ++i) |
|
161 | for (auto i = 0; i < count; ++i) | |
163 | { |
|
162 | { | |
164 | ui->tableView->setColumnWidth( |
|
163 | ui->tableView->setColumnWidth( | |
165 | i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width()); |
|
164 | i, model->headerData(i, Qt::Horizontal, Qt::SizeHintRole).toSize().width()); | |
166 | } |
|
165 | } | |
167 |
|
166 | |||
168 | // Sets selection options |
|
167 | // Sets selection options | |
169 | ui->tableView->setSelectionBehavior(QTableView::SelectRows); |
|
168 | ui->tableView->setSelectionBehavior(QTableView::SelectRows); | |
170 | ui->tableView->setSelectionMode(QTableView::ExtendedSelection); |
|
169 | ui->tableView->setSelectionMode(QTableView::ExtendedSelection); | |
171 |
|
170 | |||
172 | // Connection to show a menu when right clicking on the tree |
|
171 | // Connection to show a menu when right clicking on the tree | |
173 | ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); |
|
172 | ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); | |
174 | connect(ui->tableView, &QTableView::customContextMenuRequested, this, |
|
173 | connect(ui->tableView, &QTableView::customContextMenuRequested, this, | |
175 | &VariableInspectorWidget::onTableMenuRequested); |
|
174 | &VariableInspectorWidget::onTableMenuRequested); | |
176 | } |
|
175 | } | |
177 |
|
176 | |||
178 | VariableInspectorWidget::~VariableInspectorWidget() |
|
177 | VariableInspectorWidget::~VariableInspectorWidget() | |
179 | { |
|
178 | { | |
180 | delete ui; |
|
179 | delete ui; | |
181 | } |
|
180 | } | |
182 |
|
181 | |||
183 | void VariableInspectorWidget::onTableMenuRequested(const QPoint& pos) noexcept |
|
182 | void VariableInspectorWidget::onTableMenuRequested(const QPoint& pos) noexcept | |
184 | { |
|
183 | { | |
185 | auto selectedRows = ui->tableView->selectionModel()->selectedRows(); |
|
184 | auto selectedRows = ui->tableView->selectionModel()->selectedRows(); | |
186 | auto selectedVariables = QVector<std::shared_ptr<Variable2>> {}; |
|
185 | auto selectedVariables = QVector<std::shared_ptr<Variable2>> {}; | |
187 | for (const auto& selectedRow : qAsConst(selectedRows)) |
|
186 | for (const auto& selectedRow : qAsConst(selectedRows)) | |
188 | { |
|
187 | { | |
189 | if (auto selectedVariable = this->m_model->variables()[selectedRow.row()]) |
|
188 | if (auto selectedVariable = this->m_model->variables()[selectedRow.row()]) | |
190 | { |
|
189 | { | |
191 | selectedVariables.push_back(selectedVariable); |
|
190 | selectedVariables.push_back(selectedVariable); | |
192 | } |
|
191 | } | |
193 | } |
|
192 | } | |
194 |
|
193 | |||
195 | QMenu tableMenu {}; |
|
194 | QMenu tableMenu {}; | |
196 |
|
195 | |||
197 | // Emits a signal so that potential receivers can populate the menu before displaying it |
|
196 | // Emits a signal so that potential receivers can populate the menu before displaying it | |
198 | emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables); |
|
197 | emit tableMenuAboutToBeDisplayed(&tableMenu, selectedVariables); | |
199 |
|
198 | |||
200 | // Adds menu-specific actions |
|
199 | // Adds menu-specific actions | |
201 | if (!selectedVariables.isEmpty()) |
|
200 | if (!selectedVariables.isEmpty()) | |
202 | { |
|
201 | { | |
203 | tableMenu.addSeparator(); |
|
202 | tableMenu.addSeparator(); | |
204 |
|
203 | |||
205 | // 'Rename' and 'Duplicate' actions (only if one variable selected) |
|
204 | // 'Rename' and 'Duplicate' actions (only if one variable selected) | |
206 | if (selectedVariables.size() == 1) |
|
205 | if (selectedVariables.size() == 1) | |
207 | { |
|
206 | { | |
208 | auto selectedVariable = selectedVariables.front(); |
|
207 | auto selectedVariable = selectedVariables.front(); | |
209 |
|
208 | |||
210 | auto duplicateFun = [varW = std::weak_ptr<Variable2>(selectedVariable)]() { |
|
209 | auto duplicateFun = [varW = std::weak_ptr<Variable2>(selectedVariable)]() { | |
211 | if (auto var = varW.lock()) |
|
210 | if (auto var = varW.lock()) | |
212 | { |
|
211 | { | |
213 | sqpApp->variableController().cloneVariable(var); |
|
212 | sqpApp->variableController().cloneVariable(var); | |
214 | } |
|
213 | } | |
215 | }; |
|
214 | }; | |
216 |
|
215 | |||
217 | tableMenu.addAction(tr("Duplicate"), duplicateFun); |
|
216 | tableMenu.addAction(tr("Duplicate"), duplicateFun); | |
218 |
|
217 | |||
219 | auto renameFun = [varW = std::weak_ptr<Variable2>(selectedVariable), this]() { |
|
218 | auto renameFun = [varW = std::weak_ptr<Variable2>(selectedVariable), this]() { | |
220 | if (auto var = varW.lock()) |
|
219 | if (auto var = varW.lock()) | |
221 | { |
|
220 | { | |
222 | // Generates forbidden names (names associated to existing variables) |
|
221 | // Generates forbidden names (names associated to existing variables) | |
223 | auto allVariables = sqpApp->variableController().variables(); |
|
222 | auto allVariables = sqpApp->variableController().variables(); | |
224 | auto forbiddenNames = QVector<QString>(allVariables.size()); |
|
223 | auto forbiddenNames = QVector<QString>(allVariables.size()); | |
225 | std::transform(allVariables.cbegin(), allVariables.cend(), |
|
224 | std::transform(allVariables.cbegin(), allVariables.cend(), | |
226 | forbiddenNames.begin(), |
|
225 | forbiddenNames.begin(), | |
227 | [](const auto& variable) { return variable->name(); }); |
|
226 | [](const auto& variable) { return variable->name(); }); | |
228 |
|
227 | |||
229 | RenameVariableDialog dialog { var->name(), forbiddenNames, this }; |
|
228 | RenameVariableDialog dialog { var->name(), forbiddenNames, this }; | |
230 | if (dialog.exec() == QDialog::Accepted) |
|
229 | if (dialog.exec() == QDialog::Accepted) | |
231 | { |
|
230 | { | |
232 | var->setName(dialog.name()); |
|
231 | var->setName(dialog.name()); | |
233 | } |
|
232 | } | |
234 | } |
|
233 | } | |
235 | }; |
|
234 | }; | |
236 |
|
235 | |||
237 | tableMenu.addAction(tr("Rename..."), renameFun); |
|
236 | tableMenu.addAction(tr("Rename..."), renameFun); | |
238 | } |
|
237 | } | |
239 |
|
238 | |||
240 | // 'Delete' action |
|
239 | // 'Delete' action | |
241 | auto deleteFun = [&selectedVariables]() { |
|
240 | auto deleteFun = [&selectedVariables]() { | |
242 | for (const auto& var : selectedVariables) |
|
241 | for (const auto& var : selectedVariables) | |
243 | sqpApp->variableController().deleteVariable(var); |
|
242 | sqpApp->variableController().deleteVariable(var); | |
244 | }; |
|
243 | }; | |
245 |
|
244 | |||
246 | tableMenu.addAction(QIcon { ":/icones/delete.png" }, tr("Delete"), deleteFun); |
|
245 | tableMenu.addAction(QIcon { ":/icones/delete.png" }, tr("Delete"), deleteFun); | |
247 | } |
|
246 | } | |
248 |
|
247 | |||
249 | if (!tableMenu.isEmpty()) |
|
248 | if (!tableMenu.isEmpty()) | |
250 | { |
|
249 | { | |
251 | // Generates menu header (inserted before first action) |
|
250 | // Generates menu header (inserted before first action) | |
252 | auto firstAction = tableMenu.actions().first(); |
|
251 | auto firstAction = tableMenu.actions().first(); | |
253 | auto headerAction = new QWidgetAction { &tableMenu }; |
|
252 | auto headerAction = new QWidgetAction { &tableMenu }; | |
254 | headerAction->setDefaultWidget( |
|
253 | headerAction->setDefaultWidget( | |
255 | new VariableMenuHeaderWidget { selectedVariables, &tableMenu }); |
|
254 | new VariableMenuHeaderWidget { selectedVariables, &tableMenu }); | |
256 | tableMenu.insertAction(firstAction, headerAction); |
|
255 | tableMenu.insertAction(firstAction, headerAction); | |
257 |
|
256 | |||
258 | // Displays menu |
|
257 | // Displays menu | |
259 | tableMenu.exec(QCursor::pos()); |
|
258 | tableMenu.exec(QCursor::pos()); | |
260 | } |
|
259 | } | |
261 | } |
|
260 | } | |
262 |
|
261 | |||
263 | void VariableInspectorWidget::refresh() noexcept |
|
262 | void VariableInspectorWidget::refresh() noexcept | |
264 | { |
|
263 | { | |
265 | ui->tableView->viewport()->update(); |
|
264 | ui->tableView->viewport()->update(); | |
266 | } |
|
265 | } |
@@ -1,137 +1,133 | |||||
1 | #include "Visualization/PlottablesRenderingUtils.h" |
|
1 | #include "Visualization/PlottablesRenderingUtils.h" | |
2 |
|
2 | |||
3 | #include <Common/ColorUtils.h> |
|
3 | #include <Common/ColorUtils.h> | |
4 |
|
4 | |||
5 | #include <Data/ScalarSeries.h> |
|
|||
6 | #include <Data/SpectrogramSeries.h> |
|
|||
7 | #include <Data/VectorSeries.h> |
|
|||
8 |
|
||||
9 | #include <Variable/Variable2.h> |
|
5 | #include <Variable/Variable2.h> | |
10 |
|
6 | |||
11 | #include <Visualization/qcustomplot.h> |
|
7 | #include <Visualization/qcustomplot.h> | |
12 |
|
8 | |||
13 | Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils") |
|
9 | Q_LOGGING_CATEGORY(LOG_PlottablesRenderingUtils, "PlottablesRenderingUtils") | |
14 |
|
10 | |||
15 | namespace |
|
11 | namespace | |
16 | { |
|
12 | { | |
17 |
|
13 | |||
18 | /** |
|
14 | /** | |
19 | * Delegate used to set plottables properties |
|
15 | * Delegate used to set plottables properties | |
20 | */ |
|
16 | */ | |
21 | template <typename T, typename Enabled = void> |
|
17 | template <typename T, typename Enabled = void> | |
22 | struct PlottablesSetter |
|
18 | struct PlottablesSetter | |
23 | { |
|
19 | { | |
24 | static void setProperties(PlottablesMap&) |
|
20 | static void setProperties(PlottablesMap&) | |
25 | { |
|
21 | { | |
26 | // Default implementation does nothing |
|
22 | // Default implementation does nothing | |
27 | qCCritical(LOG_PlottablesRenderingUtils()) |
|
23 | qCCritical(LOG_PlottablesRenderingUtils()) | |
28 | << "Can't set plottables properties: unmanaged type of data"; |
|
24 | << "Can't set plottables properties: unmanaged type of data"; | |
29 | } |
|
25 | } | |
30 | }; |
|
26 | }; | |
31 |
|
27 | |||
32 | /** |
|
28 | /** | |
33 | * Specialization of PlottablesSetter for scalars and vectors |
|
29 | * Specialization of PlottablesSetter for scalars and vectors | |
34 | * @sa ScalarSeries |
|
30 | * @sa ScalarSeries | |
35 | * @sa VectorSeries |
|
31 | * @sa VectorSeries | |
36 | */ |
|
32 | */ | |
37 | template <typename T> |
|
33 | template <typename T> | |
38 | struct PlottablesSetter<T, |
|
34 | struct PlottablesSetter<T, | |
39 | typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value |
|
35 | typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value | |
40 | or std::is_base_of<VectorTimeSerie, T>::value>> |
|
36 | or std::is_base_of<VectorTimeSerie, T>::value>> | |
41 | { |
|
37 | { | |
42 | static void setProperties(PlottablesMap& plottables) |
|
38 | static void setProperties(PlottablesMap& plottables) | |
43 | { |
|
39 | { | |
44 | // Finds the plottable with the highest index to determine the number of colors to generate |
|
40 | // Finds the plottable with the highest index to determine the number of colors to generate | |
45 | auto end = plottables.cend(); |
|
41 | auto end = plottables.cend(); | |
46 | auto maxPlottableIndexIt = std::max_element(plottables.cbegin(), end, |
|
42 | auto maxPlottableIndexIt = std::max_element(plottables.cbegin(), end, | |
47 | [](const auto& it1, const auto& it2) { return it1.first < it2.first; }); |
|
43 | [](const auto& it1, const auto& it2) { return it1.first < it2.first; }); | |
48 | auto componentCount = maxPlottableIndexIt != end ? maxPlottableIndexIt->first + 1 : 0; |
|
44 | auto componentCount = maxPlottableIndexIt != end ? maxPlottableIndexIt->first + 1 : 0; | |
49 |
|
45 | |||
50 | // Generates colors for each component |
|
46 | // Generates colors for each component | |
51 | auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount); |
|
47 | auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount); | |
52 |
|
48 | |||
53 | // For each component of the data series, creates a QCPGraph to add to the plot |
|
49 | // For each component of the data series, creates a QCPGraph to add to the plot | |
54 | for (auto i = 0; i < componentCount; ++i) |
|
50 | for (auto i = 0; i < componentCount; ++i) | |
55 | { |
|
51 | { | |
56 | auto graphIt = plottables.find(i); |
|
52 | auto graphIt = plottables.find(i); | |
57 | if (graphIt != end) |
|
53 | if (graphIt != end) | |
58 | { |
|
54 | { | |
59 | graphIt->second->setPen(QPen { colors.at(i) }); |
|
55 | graphIt->second->setPen(QPen { colors.at(i) }); | |
60 | } |
|
56 | } | |
61 | } |
|
57 | } | |
62 | } |
|
58 | } | |
63 | }; |
|
59 | }; | |
64 |
|
60 | |||
65 | /** |
|
61 | /** | |
66 | * Specialization of PlottablesSetter for spectrograms |
|
62 | * Specialization of PlottablesSetter for spectrograms | |
67 | * @sa SpectrogramSeries |
|
63 | * @sa SpectrogramSeries | |
68 | */ |
|
64 | */ | |
69 | template <typename T> |
|
65 | template <typename T> | |
70 | struct PlottablesSetter<T, |
|
66 | struct PlottablesSetter<T, | |
71 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> |
|
67 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> | |
72 | { |
|
68 | { | |
73 | static void setProperties(PlottablesMap& plottables) |
|
69 | static void setProperties(PlottablesMap& plottables) | |
74 | { |
|
70 | { | |
75 | // Checks that for a spectrogram there is only one plottable, that is a colormap |
|
71 | // Checks that for a spectrogram there is only one plottable, that is a colormap | |
76 | if (plottables.size() != 1) |
|
72 | if (plottables.size() != 1) | |
77 | { |
|
73 | { | |
78 | return; |
|
74 | return; | |
79 | } |
|
75 | } | |
80 |
|
76 | |||
81 | if (auto colormap = dynamic_cast<QCPColorMap*>(plottables.begin()->second)) |
|
77 | if (auto colormap = dynamic_cast<QCPColorMap*>(plottables.begin()->second)) | |
82 | { |
|
78 | { | |
83 | colormap->setInterpolate(false); // No value interpolation |
|
79 | colormap->setInterpolate(false); // No value interpolation | |
84 | colormap->setTightBoundary(true); |
|
80 | colormap->setTightBoundary(true); | |
85 |
|
81 | |||
86 | // Finds color scale in the colormap's plot to associate with it |
|
82 | // Finds color scale in the colormap's plot to associate with it | |
87 | auto plot = colormap->parentPlot(); |
|
83 | auto plot = colormap->parentPlot(); | |
88 | auto plotElements = plot->plotLayout()->elements(false); |
|
84 | auto plotElements = plot->plotLayout()->elements(false); | |
89 | for (auto plotElement : plotElements) |
|
85 | for (auto plotElement : plotElements) | |
90 | { |
|
86 | { | |
91 | if (auto colorScale = dynamic_cast<QCPColorScale*>(plotElement)) |
|
87 | if (auto colorScale = dynamic_cast<QCPColorScale*>(plotElement)) | |
92 | { |
|
88 | { | |
93 | colormap->setColorScale(colorScale); |
|
89 | colormap->setColorScale(colorScale); | |
94 | } |
|
90 | } | |
95 | } |
|
91 | } | |
96 |
|
92 | |||
97 | colormap->rescaleDataRange(); |
|
93 | colormap->rescaleDataRange(); | |
98 | } |
|
94 | } | |
99 | else |
|
95 | else | |
100 | { |
|
96 | { | |
101 | qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram"; |
|
97 | qCCritical(LOG_PlottablesRenderingUtils()) << "Can't get colormap of the spectrogram"; | |
102 | } |
|
98 | } | |
103 | } |
|
99 | } | |
104 | }; |
|
100 | }; | |
105 |
|
101 | |||
106 | /** |
|
102 | /** | |
107 | * Default implementation of IPlottablesHelper, which takes data series to set plottables properties |
|
103 | * Default implementation of IPlottablesHelper, which takes data series to set plottables properties | |
108 | * @tparam T the data series' type |
|
104 | * @tparam T the data series' type | |
109 | */ |
|
105 | */ | |
110 | template <typename T> |
|
106 | template <typename T> | |
111 | struct PlottablesHelper : public IPlottablesHelper |
|
107 | struct PlottablesHelper : public IPlottablesHelper | |
112 | { |
|
108 | { | |
113 | void setProperties(PlottablesMap& plottables) override |
|
109 | void setProperties(PlottablesMap& plottables) override | |
114 | { |
|
110 | { | |
115 | PlottablesSetter<T>::setProperties(plottables); |
|
111 | PlottablesSetter<T>::setProperties(plottables); | |
116 | } |
|
112 | } | |
117 | }; |
|
113 | }; | |
118 |
|
114 | |||
119 | } // namespace |
|
115 | } // namespace | |
120 |
|
116 | |||
121 | std::unique_ptr<IPlottablesHelper> IPlottablesHelperFactory::create(Variable2& variable) noexcept |
|
117 | std::unique_ptr<IPlottablesHelper> IPlottablesHelperFactory::create(Variable2& variable) noexcept | |
122 | { |
|
118 | { | |
123 | switch (variable.type()) |
|
119 | switch (variable.type()) | |
124 | { |
|
120 | { | |
125 | case DataSeriesType::SCALAR: |
|
121 | case DataSeriesType::SCALAR: | |
126 | return std::make_unique<PlottablesHelper<ScalarTimeSerie>>(); |
|
122 | return std::make_unique<PlottablesHelper<ScalarTimeSerie>>(); | |
127 | case DataSeriesType::SPECTROGRAM: |
|
123 | case DataSeriesType::SPECTROGRAM: | |
128 | return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>(); |
|
124 | return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>(); | |
129 | case DataSeriesType::VECTOR: |
|
125 | case DataSeriesType::VECTOR: | |
130 | return std::make_unique<PlottablesHelper<VectorTimeSerie>>(); |
|
126 | return std::make_unique<PlottablesHelper<VectorTimeSerie>>(); | |
131 | default: |
|
127 | default: | |
132 | // Returns default helper |
|
128 | // Returns default helper | |
133 | break; |
|
129 | break; | |
134 | } |
|
130 | } | |
135 |
|
131 | |||
136 |
return std::make_unique<PlottablesHelper< |
|
132 | return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(); | |
137 | } |
|
133 | } |
@@ -1,60 +1,63 | |||||
1 | #include "Visualization/SqpColorScale.h" |
|
1 | #include "Visualization/SqpColorScale.h" | |
2 |
|
2 | |||
3 | #include <Data/DataSeriesUtils.h> |
|
|||
4 |
|
||||
5 | #include <Visualization/QCPColorMapIterator.h> |
|
3 | #include <Visualization/QCPColorMapIterator.h> | |
6 |
|
4 | |||
7 | Q_LOGGING_CATEGORY(LOG_SqpColorScale, "SqpColorScale") |
|
5 | Q_LOGGING_CATEGORY(LOG_SqpColorScale, "SqpColorScale") | |
8 |
|
6 | |||
9 |
namespace |
|
7 | namespace | |
|
8 | { | |||
10 |
|
9 | |||
11 | const auto DEFAULT_GRADIENT_PRESET = QCPColorGradient::gpJet; |
|
10 | const auto DEFAULT_GRADIENT_PRESET = QCPColorGradient::gpJet; | |
12 | const auto DEFAULT_RANGE = QCPRange{1.0e3, 1.7e7}; |
|
11 | const auto DEFAULT_RANGE = QCPRange { 1.0e3, 1.7e7 }; | |
13 |
|
12 | |||
14 | } // namespace |
|
13 | } // namespace | |
15 |
|
14 | |||
16 |
std::pair<double, double> SqpColorScale::computeThresholds(const SqpColorScale |
|
15 | std::pair<double, double> SqpColorScale::computeThresholds(const SqpColorScale& scale) | |
17 | { |
|
16 | { | |
18 | auto qcpScale = scale.m_Scale; |
|
17 | auto qcpScale = scale.m_Scale; | |
19 |
|
18 | |||
20 | auto colorMaps = qcpScale->colorMaps(); |
|
19 | auto colorMaps = qcpScale->colorMaps(); | |
21 |
if (colorMaps.size() != 1) |
|
20 | if (colorMaps.size() != 1) | |
22 | return {std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN()}; |
|
21 | { | |
|
22 | return { std::numeric_limits<double>::quiet_NaN(), | |||
|
23 | std::numeric_limits<double>::quiet_NaN() }; | |||
23 | } |
|
24 | } | |
24 |
|
25 | |||
25 | // Computes thresholds |
|
26 | // Computes thresholds | |
26 | auto isLogarithmicScale = qcpScale->dataScaleType() == QCPAxis::stLogarithmic; |
|
27 | auto isLogarithmicScale = qcpScale->dataScaleType() == QCPAxis::stLogarithmic; | |
27 | auto colorMapData = colorMaps.first()->data(); |
|
28 | auto colorMapData = colorMaps.first()->data(); | |
28 | QCPColorMapIterator begin{colorMapData, true}; |
|
29 | QCPColorMapIterator begin { colorMapData, true }; | |
29 | QCPColorMapIterator end{colorMapData, false}; |
|
30 | QCPColorMapIterator end { colorMapData, false }; | |
30 |
|
31 | |||
31 |
return |
|
32 | return {}; // DataSeriesUtils::thresholds(begin, end, isLogarithmicScale); | |
32 | } |
|
33 | } | |
33 |
|
34 | |||
34 |
SqpColorScale::SqpColorScale(QCustomPlot |
|
35 | SqpColorScale::SqpColorScale(QCustomPlot& plot) | |
35 |
: m_Scale{new QCPColorScale{&plot}} |
|
36 | : m_Scale { new QCPColorScale { &plot } } | |
36 |
|
|
37 | , m_AutomaticThreshold { false } | |
37 |
|
|
38 | , m_GradientPreset { DEFAULT_GRADIENT_PRESET } | |
38 | { |
|
39 | { | |
39 | m_Scale->setGradient(m_GradientPreset); |
|
40 | m_Scale->setGradient(m_GradientPreset); | |
40 | m_Scale->setDataRange(DEFAULT_RANGE); |
|
41 | m_Scale->setDataRange(DEFAULT_RANGE); | |
41 | } |
|
42 | } | |
42 |
|
43 | |||
43 | void SqpColorScale::updateDataRange() noexcept |
|
44 | void SqpColorScale::updateDataRange() noexcept | |
44 | { |
|
45 | { | |
45 | // Updates data range only if mode is automatic |
|
46 | // Updates data range only if mode is automatic | |
46 |
if (!m_AutomaticThreshold) |
|
47 | if (!m_AutomaticThreshold) | |
|
48 | { | |||
47 | return; |
|
49 | return; | |
48 | } |
|
50 | } | |
49 |
|
51 | |||
50 | double minThreshold, maxThreshold; |
|
52 | double minThreshold, maxThreshold; | |
51 | std::tie(minThreshold, maxThreshold) = computeThresholds(*this); |
|
53 | std::tie(minThreshold, maxThreshold) = computeThresholds(*this); | |
52 |
if (std::isnan(minThreshold) || std::isnan(maxThreshold)) |
|
54 | if (std::isnan(minThreshold) || std::isnan(maxThreshold)) | |
|
55 | { | |||
53 | qCCritical(LOG_SqpColorScale()) |
|
56 | qCCritical(LOG_SqpColorScale()) | |
54 | << "Can't update data range of color scale: thresholds computed are invalid"; |
|
57 | << "Can't update data range of color scale: thresholds computed are invalid"; | |
55 | return; |
|
58 | return; | |
56 | } |
|
59 | } | |
57 |
|
60 | |||
58 | // Updates thresholds |
|
61 | // Updates thresholds | |
59 | m_Scale->setDataRange({minThreshold, maxThreshold}); |
|
62 | m_Scale->setDataRange({ minThreshold, maxThreshold }); | |
60 | } |
|
63 | } |
@@ -1,443 +1,442 | |||||
1 | #include "Visualization/VisualizationGraphHelper.h" |
|
1 | #include "Visualization/VisualizationGraphHelper.h" | |
2 | #include "Visualization/qcustomplot.h" |
|
2 | #include "Visualization/qcustomplot.h" | |
3 |
|
3 | |||
4 | #include <Data/DataSeriesUtils.h> |
|
|||
5 | #include <Data/ScalarTimeSerie.h> |
|
4 | #include <Data/ScalarTimeSerie.h> | |
6 | #include <Data/SpectrogramTimeSerie.h> |
|
5 | #include <Data/SpectrogramTimeSerie.h> | |
7 | #include <Data/VectorTimeSerie.h> |
|
6 | #include <Data/VectorTimeSerie.h> | |
8 |
|
7 | |||
9 | #include <Variable/Variable2.h> |
|
8 | #include <Variable/Variable2.h> | |
10 |
|
9 | |||
11 | Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper") |
|
10 | Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper") | |
12 |
|
11 | |||
13 | namespace |
|
12 | namespace | |
14 | { |
|
13 | { | |
15 |
|
14 | |||
16 | class SqpDataContainer : public QCPGraphDataContainer |
|
15 | class SqpDataContainer : public QCPGraphDataContainer | |
17 | { |
|
16 | { | |
18 | public: |
|
17 | public: | |
19 | void appendGraphData(const QCPGraphData& data) { mData.append(data); } |
|
18 | void appendGraphData(const QCPGraphData& data) { mData.append(data); } | |
20 | }; |
|
19 | }; | |
21 |
|
20 | |||
22 | /** |
|
21 | /** | |
23 | * Struct used to create plottables, depending on the type of the data series from which to create |
|
22 | * Struct used to create plottables, depending on the type of the data series from which to create | |
24 | * them |
|
23 | * them | |
25 | * @tparam T the data series' type |
|
24 | * @tparam T the data series' type | |
26 | * @remarks Default implementation can't create plottables |
|
25 | * @remarks Default implementation can't create plottables | |
27 | */ |
|
26 | */ | |
28 | template <typename T, typename Enabled = void> |
|
27 | template <typename T, typename Enabled = void> | |
29 | struct PlottablesCreator |
|
28 | struct PlottablesCreator | |
30 | { |
|
29 | { | |
31 | static PlottablesMap createPlottables(QCustomPlot&) { return {}; } |
|
30 | static PlottablesMap createPlottables(QCustomPlot&) { return {}; } | |
32 | }; |
|
31 | }; | |
33 |
|
32 | |||
34 | PlottablesMap createGraphs(QCustomPlot& plot, int nbGraphs) |
|
33 | PlottablesMap createGraphs(QCustomPlot& plot, int nbGraphs) | |
35 | { |
|
34 | { | |
36 | PlottablesMap result {}; |
|
35 | PlottablesMap result {}; | |
37 |
|
36 | |||
38 | // Creates {nbGraphs} QCPGraph to add to the plot |
|
37 | // Creates {nbGraphs} QCPGraph to add to the plot | |
39 | for (auto i = 0; i < nbGraphs; ++i) |
|
38 | for (auto i = 0; i < nbGraphs; ++i) | |
40 | { |
|
39 | { | |
41 | auto graph = plot.addGraph(); |
|
40 | auto graph = plot.addGraph(); | |
42 | result.insert({ i, graph }); |
|
41 | result.insert({ i, graph }); | |
43 | } |
|
42 | } | |
44 |
|
43 | |||
45 | plot.replot(); |
|
44 | plot.replot(); | |
46 |
|
45 | |||
47 | return result; |
|
46 | return result; | |
48 | } |
|
47 | } | |
49 |
|
48 | |||
50 | /** |
|
49 | /** | |
51 | * Specialization of PlottablesCreator for scalars |
|
50 | * Specialization of PlottablesCreator for scalars | |
52 | * @sa ScalarSeries |
|
51 | * @sa ScalarSeries | |
53 | */ |
|
52 | */ | |
54 | template <typename T> |
|
53 | template <typename T> | |
55 | struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>> |
|
54 | struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>> | |
56 | { |
|
55 | { | |
57 | static PlottablesMap createPlottables(QCustomPlot& plot) { return createGraphs(plot, 1); } |
|
56 | static PlottablesMap createPlottables(QCustomPlot& plot) { return createGraphs(plot, 1); } | |
58 | }; |
|
57 | }; | |
59 |
|
58 | |||
60 | /** |
|
59 | /** | |
61 | * Specialization of PlottablesCreator for vectors |
|
60 | * Specialization of PlottablesCreator for vectors | |
62 | * @sa VectorSeries |
|
61 | * @sa VectorSeries | |
63 | */ |
|
62 | */ | |
64 | template <typename T> |
|
63 | template <typename T> | |
65 | struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>> |
|
64 | struct PlottablesCreator<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>> | |
66 | { |
|
65 | { | |
67 | static PlottablesMap createPlottables(QCustomPlot& plot) { return createGraphs(plot, 3); } |
|
66 | static PlottablesMap createPlottables(QCustomPlot& plot) { return createGraphs(plot, 3); } | |
68 | }; |
|
67 | }; | |
69 |
|
68 | |||
70 | /** |
|
69 | /** | |
71 | * Specialization of PlottablesCreator for spectrograms |
|
70 | * Specialization of PlottablesCreator for spectrograms | |
72 | * @sa SpectrogramSeries |
|
71 | * @sa SpectrogramSeries | |
73 | */ |
|
72 | */ | |
74 | template <typename T> |
|
73 | template <typename T> | |
75 | struct PlottablesCreator<T, |
|
74 | struct PlottablesCreator<T, | |
76 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> |
|
75 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> | |
77 | { |
|
76 | { | |
78 | static PlottablesMap createPlottables(QCustomPlot& plot) |
|
77 | static PlottablesMap createPlottables(QCustomPlot& plot) | |
79 | { |
|
78 | { | |
80 | PlottablesMap result {}; |
|
79 | PlottablesMap result {}; | |
81 | result.insert({ 0, new QCPColorMap { plot.xAxis, plot.yAxis } }); |
|
80 | result.insert({ 0, new QCPColorMap { plot.xAxis, plot.yAxis } }); | |
82 |
|
81 | |||
83 | plot.replot(); |
|
82 | plot.replot(); | |
84 |
|
83 | |||
85 | return result; |
|
84 | return result; | |
86 | } |
|
85 | } | |
87 | }; |
|
86 | }; | |
88 |
|
87 | |||
89 | /** |
|
88 | /** | |
90 | * Struct used to update plottables, depending on the type of the data series from which to update |
|
89 | * Struct used to update plottables, depending on the type of the data series from which to update | |
91 | * them |
|
90 | * them | |
92 | * @tparam T the data series' type |
|
91 | * @tparam T the data series' type | |
93 | * @remarks Default implementation can't update plottables |
|
92 | * @remarks Default implementation can't update plottables | |
94 | */ |
|
93 | */ | |
95 | template <typename T, typename Enabled = void> |
|
94 | template <typename T, typename Enabled = void> | |
96 | struct PlottablesUpdater |
|
95 | struct PlottablesUpdater | |
97 | { |
|
96 | { | |
98 | static void setPlotYAxisRange(T&, const DateTimeRange&, QCustomPlot&) |
|
97 | static void setPlotYAxisRange(T&, const DateTimeRange&, QCustomPlot&) | |
99 | { |
|
98 | { | |
100 | qCCritical(LOG_VisualizationGraphHelper()) |
|
99 | qCCritical(LOG_VisualizationGraphHelper()) | |
101 | << QObject::tr("Can't set plot y-axis range: unmanaged data series type"); |
|
100 | << QObject::tr("Can't set plot y-axis range: unmanaged data series type"); | |
102 | } |
|
101 | } | |
103 |
|
102 | |||
104 | static void updatePlottables(T&, PlottablesMap&, const DateTimeRange&, bool) |
|
103 | static void updatePlottables(T&, PlottablesMap&, const DateTimeRange&, bool) | |
105 | { |
|
104 | { | |
106 | qCCritical(LOG_VisualizationGraphHelper()) |
|
105 | qCCritical(LOG_VisualizationGraphHelper()) | |
107 | << QObject::tr("Can't update plottables: unmanaged data series type"); |
|
106 | << QObject::tr("Can't update plottables: unmanaged data series type"); | |
108 | } |
|
107 | } | |
109 | }; |
|
108 | }; | |
110 |
|
109 | |||
111 | /** |
|
110 | /** | |
112 | * Specialization of PlottablesUpdater for scalars and vectors |
|
111 | * Specialization of PlottablesUpdater for scalars and vectors | |
113 | * @sa ScalarSeries |
|
112 | * @sa ScalarSeries | |
114 | * @sa VectorSeries |
|
113 | * @sa VectorSeries | |
115 | */ |
|
114 | */ | |
116 | template <typename T> |
|
115 | template <typename T> | |
117 | struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>> |
|
116 | struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<ScalarTimeSerie, T>::value>> | |
118 | { |
|
117 | { | |
119 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) |
|
118 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) | |
120 | { |
|
119 | { | |
121 | auto minValue = 0., maxValue = 0.; |
|
120 | auto minValue = 0., maxValue = 0.; | |
122 | if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries)) |
|
121 | if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries)) | |
123 | { |
|
122 | { | |
124 | maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v(); |
|
123 | maxValue = (*std::max_element(std::begin(*serie), std::end(*serie))).v(); | |
125 | minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v(); |
|
124 | minValue = (*std::min_element(std::begin(*serie), std::end(*serie))).v(); | |
126 | } |
|
125 | } | |
127 | plot.yAxis->setRange(QCPRange { minValue, maxValue }); |
|
126 | plot.yAxis->setRange(QCPRange { minValue, maxValue }); | |
128 | } |
|
127 | } | |
129 |
|
128 | |||
130 | static void updatePlottables( |
|
129 | static void updatePlottables( | |
131 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) |
|
130 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) | |
132 | { |
|
131 | { | |
133 |
|
132 | |||
134 | // For each plottable to update, resets its data |
|
133 | // For each plottable to update, resets its data | |
135 | for (const auto& plottable : plottables) |
|
134 | for (const auto& plottable : plottables) | |
136 | { |
|
135 | { | |
137 | if (auto graph = dynamic_cast<QCPGraph*>(plottable.second)) |
|
136 | if (auto graph = dynamic_cast<QCPGraph*>(plottable.second)) | |
138 | { |
|
137 | { | |
139 | auto dataContainer = QSharedPointer<SqpDataContainer>::create(); |
|
138 | auto dataContainer = QSharedPointer<SqpDataContainer>::create(); | |
140 | if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries)) |
|
139 | if (auto serie = dynamic_cast<ScalarTimeSerie*>(&dataSeries)) | |
141 | { |
|
140 | { | |
142 | std::for_each( |
|
141 | std::for_each( | |
143 | std::begin(*serie), std::end(*serie), [&dataContainer](const auto& value) { |
|
142 | std::begin(*serie), std::end(*serie), [&dataContainer](const auto& value) { | |
144 | dataContainer->appendGraphData(QCPGraphData(value.t(), value.v())); |
|
143 | dataContainer->appendGraphData(QCPGraphData(value.t(), value.v())); | |
145 | }); |
|
144 | }); | |
146 | } |
|
145 | } | |
147 | graph->setData(dataContainer); |
|
146 | graph->setData(dataContainer); | |
148 | } |
|
147 | } | |
149 | } |
|
148 | } | |
150 |
|
149 | |||
151 | if (!plottables.empty()) |
|
150 | if (!plottables.empty()) | |
152 | { |
|
151 | { | |
153 | auto plot = plottables.begin()->second->parentPlot(); |
|
152 | auto plot = plottables.begin()->second->parentPlot(); | |
154 |
|
153 | |||
155 | if (rescaleAxes) |
|
154 | if (rescaleAxes) | |
156 | { |
|
155 | { | |
157 | plot->rescaleAxes(); |
|
156 | plot->rescaleAxes(); | |
158 | } |
|
157 | } | |
159 | } |
|
158 | } | |
160 | } |
|
159 | } | |
161 | }; |
|
160 | }; | |
162 |
|
161 | |||
163 |
|
162 | |||
164 | template <typename T> |
|
163 | template <typename T> | |
165 | struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>> |
|
164 | struct PlottablesUpdater<T, typename std::enable_if_t<std::is_base_of<VectorTimeSerie, T>::value>> | |
166 | { |
|
165 | { | |
167 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) |
|
166 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) | |
168 | { |
|
167 | { | |
169 | double minValue = 0., maxValue = 0.; |
|
168 | double minValue = 0., maxValue = 0.; | |
170 | if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries)) |
|
169 | if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries)) | |
171 | { |
|
170 | { | |
172 | std::for_each( |
|
171 | std::for_each( | |
173 | std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) { |
|
172 | std::begin(*serie), std::end(*serie), [&minValue, &maxValue](const auto& v) { | |
174 | minValue = std::min({ minValue, v.v().x, v.v().y, v.v().z }); |
|
173 | minValue = std::min({ minValue, v.v().x, v.v().y, v.v().z }); | |
175 | maxValue = std::max({ maxValue, v.v().x, v.v().y, v.v().z }); |
|
174 | maxValue = std::max({ maxValue, v.v().x, v.v().y, v.v().z }); | |
176 | }); |
|
175 | }); | |
177 | } |
|
176 | } | |
178 |
|
177 | |||
179 | plot.yAxis->setRange(QCPRange { minValue, maxValue }); |
|
178 | plot.yAxis->setRange(QCPRange { minValue, maxValue }); | |
180 | } |
|
179 | } | |
181 |
|
180 | |||
182 | static void updatePlottables( |
|
181 | static void updatePlottables( | |
183 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) |
|
182 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) | |
184 | { |
|
183 | { | |
185 |
|
184 | |||
186 | // For each plottable to update, resets its data |
|
185 | // For each plottable to update, resets its data | |
187 | for (const auto& plottable : plottables) |
|
186 | for (const auto& plottable : plottables) | |
188 | { |
|
187 | { | |
189 | if (auto graph = dynamic_cast<QCPGraph*>(plottable.second)) |
|
188 | if (auto graph = dynamic_cast<QCPGraph*>(plottable.second)) | |
190 | { |
|
189 | { | |
191 | auto dataContainer = QSharedPointer<SqpDataContainer>::create(); |
|
190 | auto dataContainer = QSharedPointer<SqpDataContainer>::create(); | |
192 | if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries)) |
|
191 | if (auto serie = dynamic_cast<VectorTimeSerie*>(&dataSeries)) | |
193 | { |
|
192 | { | |
194 | switch (plottable.first) |
|
193 | switch (plottable.first) | |
195 | { |
|
194 | { | |
196 | case 0: |
|
195 | case 0: | |
197 | std::for_each(std::begin(*serie), std::end(*serie), |
|
196 | std::for_each(std::begin(*serie), std::end(*serie), | |
198 | [&dataContainer](const auto& value) { |
|
197 | [&dataContainer](const auto& value) { | |
199 | dataContainer->appendGraphData( |
|
198 | dataContainer->appendGraphData( | |
200 | QCPGraphData(value.t(), value.v().x)); |
|
199 | QCPGraphData(value.t(), value.v().x)); | |
201 | }); |
|
200 | }); | |
202 | break; |
|
201 | break; | |
203 | case 1: |
|
202 | case 1: | |
204 | std::for_each(std::begin(*serie), std::end(*serie), |
|
203 | std::for_each(std::begin(*serie), std::end(*serie), | |
205 | [&dataContainer](const auto& value) { |
|
204 | [&dataContainer](const auto& value) { | |
206 | dataContainer->appendGraphData( |
|
205 | dataContainer->appendGraphData( | |
207 | QCPGraphData(value.t(), value.v().y)); |
|
206 | QCPGraphData(value.t(), value.v().y)); | |
208 | }); |
|
207 | }); | |
209 | break; |
|
208 | break; | |
210 | case 2: |
|
209 | case 2: | |
211 | std::for_each(std::begin(*serie), std::end(*serie), |
|
210 | std::for_each(std::begin(*serie), std::end(*serie), | |
212 | [&dataContainer](const auto& value) { |
|
211 | [&dataContainer](const auto& value) { | |
213 | dataContainer->appendGraphData( |
|
212 | dataContainer->appendGraphData( | |
214 | QCPGraphData(value.t(), value.v().z)); |
|
213 | QCPGraphData(value.t(), value.v().z)); | |
215 | }); |
|
214 | }); | |
216 | break; |
|
215 | break; | |
217 | default: |
|
216 | default: | |
218 | break; |
|
217 | break; | |
219 | } |
|
218 | } | |
220 | } |
|
219 | } | |
221 | graph->setData(dataContainer); |
|
220 | graph->setData(dataContainer); | |
222 | } |
|
221 | } | |
223 | } |
|
222 | } | |
224 |
|
223 | |||
225 | if (!plottables.empty()) |
|
224 | if (!plottables.empty()) | |
226 | { |
|
225 | { | |
227 | auto plot = plottables.begin()->second->parentPlot(); |
|
226 | auto plot = plottables.begin()->second->parentPlot(); | |
228 |
|
227 | |||
229 | if (rescaleAxes) |
|
228 | if (rescaleAxes) | |
230 | { |
|
229 | { | |
231 | plot->rescaleAxes(); |
|
230 | plot->rescaleAxes(); | |
232 | } |
|
231 | } | |
233 | } |
|
232 | } | |
234 | } |
|
233 | } | |
235 | }; |
|
234 | }; | |
236 |
|
235 | |||
237 | /** |
|
236 | /** | |
238 | * Specialization of PlottablesUpdater for spectrograms |
|
237 | * Specialization of PlottablesUpdater for spectrograms | |
239 | * @sa SpectrogramSeries |
|
238 | * @sa SpectrogramSeries | |
240 | */ |
|
239 | */ | |
241 | template <typename T> |
|
240 | template <typename T> | |
242 | struct PlottablesUpdater<T, |
|
241 | struct PlottablesUpdater<T, | |
243 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> |
|
242 | typename std::enable_if_t<std::is_base_of<SpectrogramTimeSerie, T>::value>> | |
244 | { |
|
243 | { | |
245 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) |
|
244 | static void setPlotYAxisRange(T& dataSeries, const DateTimeRange& xAxisRange, QCustomPlot& plot) | |
246 | { |
|
245 | { | |
247 | // TODO |
|
246 | // TODO | |
248 | // double min, max; |
|
247 | // double min, max; | |
249 | // std::tie(min, max) = dataSeries.yBounds(); |
|
248 | // std::tie(min, max) = dataSeries.yBounds(); | |
250 |
|
249 | |||
251 | // if (!std::isnan(min) && !std::isnan(max)) |
|
250 | // if (!std::isnan(min) && !std::isnan(max)) | |
252 | // { |
|
251 | // { | |
253 | // plot.yAxis->setRange(QCPRange { min, max }); |
|
252 | // plot.yAxis->setRange(QCPRange { min, max }); | |
254 | // } |
|
253 | // } | |
255 | } |
|
254 | } | |
256 |
|
255 | |||
257 | static void updatePlottables( |
|
256 | static void updatePlottables( | |
258 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) |
|
257 | T& dataSeries, PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) | |
259 | { |
|
258 | { | |
260 | // TODO |
|
259 | // TODO | |
261 | // if (plottables.empty()) |
|
260 | // if (plottables.empty()) | |
262 | // { |
|
261 | // { | |
263 | // qCDebug(LOG_VisualizationGraphHelper()) |
|
262 | // qCDebug(LOG_VisualizationGraphHelper()) | |
264 | // << QObject::tr("Can't update spectrogram: no colormap has been |
|
263 | // << QObject::tr("Can't update spectrogram: no colormap has been | |
265 | // associated"); |
|
264 | // associated"); | |
266 | // return; |
|
265 | // return; | |
267 | // } |
|
266 | // } | |
268 |
|
267 | |||
269 | // // Gets the colormap to update (normally there is only one colormap) |
|
268 | // // Gets the colormap to update (normally there is only one colormap) | |
270 | // Q_ASSERT(plottables.size() == 1); |
|
269 | // Q_ASSERT(plottables.size() == 1); | |
271 | // auto colormap = dynamic_cast<QCPColorMap*>(plottables.at(0)); |
|
270 | // auto colormap = dynamic_cast<QCPColorMap*>(plottables.at(0)); | |
272 | // Q_ASSERT(colormap != nullptr); |
|
271 | // Q_ASSERT(colormap != nullptr); | |
273 |
|
272 | |||
274 | // dataSeries.lockRead(); |
|
273 | // dataSeries.lockRead(); | |
275 |
|
274 | |||
276 | // // Processing spectrogram data for display in QCustomPlot |
|
275 | // // Processing spectrogram data for display in QCustomPlot | |
277 | // auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd); |
|
276 | // auto its = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd); | |
278 |
|
277 | |||
279 | // // Computes logarithmic y-axis resolution for the spectrogram |
|
278 | // // Computes logarithmic y-axis resolution for the spectrogram | |
280 | // auto yData = its.first->y(); |
|
279 | // auto yData = its.first->y(); | |
281 | // auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true); |
|
280 | // auto yResolution = DataSeriesUtils::resolution(yData.begin(), yData.end(), true); | |
282 |
|
281 | |||
283 | // // Generates mesh for colormap |
|
282 | // // Generates mesh for colormap | |
284 | // auto mesh = DataSeriesUtils::regularMesh(its.first, its.second, |
|
283 | // auto mesh = DataSeriesUtils::regularMesh(its.first, its.second, | |
285 | // DataSeriesUtils::Resolution { dataSeries.xResolution() }, yResolution); |
|
284 | // DataSeriesUtils::Resolution { dataSeries.xResolution() }, yResolution); | |
286 |
|
285 | |||
287 | // dataSeries.unlock(); |
|
286 | // dataSeries.unlock(); | |
288 |
|
287 | |||
289 | // colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY); |
|
288 | // colormap->data()->setSize(mesh.m_NbX, mesh.m_NbY); | |
290 | // if (!mesh.isEmpty()) |
|
289 | // if (!mesh.isEmpty()) | |
291 | // { |
|
290 | // { | |
292 | // colormap->data()->setRange(QCPRange { mesh.m_XMin, mesh.xMax() }, |
|
291 | // colormap->data()->setRange(QCPRange { mesh.m_XMin, mesh.xMax() }, | |
293 | // // y-axis range is converted to linear values |
|
292 | // // y-axis range is converted to linear values | |
294 | // QCPRange { std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax()) }); |
|
293 | // QCPRange { std::pow(10, mesh.m_YMin), std::pow(10, mesh.yMax()) }); | |
295 |
|
294 | |||
296 | // // Sets values |
|
295 | // // Sets values | |
297 | // auto index = 0; |
|
296 | // auto index = 0; | |
298 | // for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, |
|
297 | // for (auto it = mesh.m_Data.begin(), end = mesh.m_Data.end(); it != end; ++it, | |
299 | // ++index) |
|
298 | // ++index) | |
300 | // { |
|
299 | // { | |
301 | // auto xIndex = index % mesh.m_NbX; |
|
300 | // auto xIndex = index % mesh.m_NbX; | |
302 | // auto yIndex = index / mesh.m_NbX; |
|
301 | // auto yIndex = index / mesh.m_NbX; | |
303 |
|
302 | |||
304 | // colormap->data()->setCell(xIndex, yIndex, *it); |
|
303 | // colormap->data()->setCell(xIndex, yIndex, *it); | |
305 |
|
304 | |||
306 | // // Makes the NaN values to be transparent in the colormap |
|
305 | // // Makes the NaN values to be transparent in the colormap | |
307 | // if (std::isnan(*it)) |
|
306 | // if (std::isnan(*it)) | |
308 | // { |
|
307 | // { | |
309 | // colormap->data()->setAlpha(xIndex, yIndex, 0); |
|
308 | // colormap->data()->setAlpha(xIndex, yIndex, 0); | |
310 | // } |
|
309 | // } | |
311 | // } |
|
310 | // } | |
312 | // } |
|
311 | // } | |
313 |
|
312 | |||
314 | // // Rescales axes |
|
313 | // // Rescales axes | |
315 | // auto plot = colormap->parentPlot(); |
|
314 | // auto plot = colormap->parentPlot(); | |
316 |
|
315 | |||
317 | // if (rescaleAxes) |
|
316 | // if (rescaleAxes) | |
318 | // { |
|
317 | // { | |
319 | // plot->rescaleAxes(); |
|
318 | // plot->rescaleAxes(); | |
320 | // } |
|
319 | // } | |
321 | } |
|
320 | } | |
322 | }; |
|
321 | }; | |
323 |
|
322 | |||
324 | /** |
|
323 | /** | |
325 | * Helper used to create/update plottables |
|
324 | * Helper used to create/update plottables | |
326 | */ |
|
325 | */ | |
327 | struct IPlottablesHelper |
|
326 | struct IPlottablesHelper | |
328 | { |
|
327 | { | |
329 | virtual ~IPlottablesHelper() noexcept = default; |
|
328 | virtual ~IPlottablesHelper() noexcept = default; | |
330 | virtual PlottablesMap create(QCustomPlot& plot) const = 0; |
|
329 | virtual PlottablesMap create(QCustomPlot& plot) const = 0; | |
331 | virtual void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const = 0; |
|
330 | virtual void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const = 0; | |
332 | virtual void update( |
|
331 | virtual void update( | |
333 | PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes = false) const = 0; |
|
332 | PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes = false) const = 0; | |
334 | }; |
|
333 | }; | |
335 |
|
334 | |||
336 | /** |
|
335 | /** | |
337 | * Default implementation of IPlottablesHelper, which takes data series to create/update plottables |
|
336 | * Default implementation of IPlottablesHelper, which takes data series to create/update plottables | |
338 | * @tparam T the data series' type |
|
337 | * @tparam T the data series' type | |
339 | */ |
|
338 | */ | |
340 | template <typename T> |
|
339 | template <typename T> | |
341 | struct PlottablesHelper : public IPlottablesHelper |
|
340 | struct PlottablesHelper : public IPlottablesHelper | |
342 | { |
|
341 | { | |
343 | explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {} |
|
342 | explicit PlottablesHelper(std::shared_ptr<T> dataSeries) : m_DataSeries { dataSeries } {} | |
344 |
|
343 | |||
345 | PlottablesMap create(QCustomPlot& plot) const override |
|
344 | PlottablesMap create(QCustomPlot& plot) const override | |
346 | { |
|
345 | { | |
347 | return PlottablesCreator<T>::createPlottables(plot); |
|
346 | return PlottablesCreator<T>::createPlottables(plot); | |
348 | } |
|
347 | } | |
349 |
|
348 | |||
350 | void update( |
|
349 | void update( | |
351 | PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) const override |
|
350 | PlottablesMap& plottables, const DateTimeRange& range, bool rescaleAxes) const override | |
352 | { |
|
351 | { | |
353 | if (m_DataSeries) |
|
352 | if (m_DataSeries) | |
354 | { |
|
353 | { | |
355 | PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes); |
|
354 | PlottablesUpdater<T>::updatePlottables(*m_DataSeries, plottables, range, rescaleAxes); | |
356 | } |
|
355 | } | |
357 | else |
|
356 | else | |
358 | { |
|
357 | { | |
359 | qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency " |
|
358 | qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency " | |
360 | "between the type of data series and the " |
|
359 | "between the type of data series and the " | |
361 | "type supposed"; |
|
360 | "type supposed"; | |
362 | } |
|
361 | } | |
363 | } |
|
362 | } | |
364 |
|
363 | |||
365 | void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const override |
|
364 | void setYAxisRange(const DateTimeRange& xAxisRange, QCustomPlot& plot) const override | |
366 | { |
|
365 | { | |
367 | if (m_DataSeries) |
|
366 | if (m_DataSeries) | |
368 | { |
|
367 | { | |
369 | PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot); |
|
368 | PlottablesUpdater<T>::setPlotYAxisRange(*m_DataSeries, xAxisRange, plot); | |
370 | } |
|
369 | } | |
371 | else |
|
370 | else | |
372 | { |
|
371 | { | |
373 | qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency " |
|
372 | qCCritical(LOG_VisualizationGraphHelper()) << "Can't update plottables: inconsistency " | |
374 | "between the type of data series and the " |
|
373 | "between the type of data series and the " | |
375 | "type supposed"; |
|
374 | "type supposed"; | |
376 | } |
|
375 | } | |
377 | } |
|
376 | } | |
378 |
|
377 | |||
379 | std::shared_ptr<T> m_DataSeries; |
|
378 | std::shared_ptr<T> m_DataSeries; | |
380 | }; |
|
379 | }; | |
381 |
|
380 | |||
382 | /// Creates IPlottablesHelper according to the type of data series a variable holds |
|
381 | /// Creates IPlottablesHelper according to the type of data series a variable holds | |
383 | std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable2> variable) noexcept |
|
382 | std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<Variable2> variable) noexcept | |
384 | { |
|
383 | { | |
385 | switch (variable->type()) |
|
384 | switch (variable->type()) | |
386 | { |
|
385 | { | |
387 | case DataSeriesType::SCALAR: |
|
386 | case DataSeriesType::SCALAR: | |
388 | return std::make_unique<PlottablesHelper<ScalarTimeSerie>>( |
|
387 | return std::make_unique<PlottablesHelper<ScalarTimeSerie>>( | |
389 | std::dynamic_pointer_cast<ScalarTimeSerie>(variable->data())); |
|
388 | std::dynamic_pointer_cast<ScalarTimeSerie>(variable->data())); | |
390 | case DataSeriesType::SPECTROGRAM: |
|
389 | case DataSeriesType::SPECTROGRAM: | |
391 | return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>( |
|
390 | return std::make_unique<PlottablesHelper<SpectrogramTimeSerie>>( | |
392 | std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable->data())); |
|
391 | std::dynamic_pointer_cast<SpectrogramTimeSerie>(variable->data())); | |
393 | case DataSeriesType::VECTOR: |
|
392 | case DataSeriesType::VECTOR: | |
394 | return std::make_unique<PlottablesHelper<VectorTimeSerie>>( |
|
393 | return std::make_unique<PlottablesHelper<VectorTimeSerie>>( | |
395 | std::dynamic_pointer_cast<VectorTimeSerie>(variable->data())); |
|
394 | std::dynamic_pointer_cast<VectorTimeSerie>(variable->data())); | |
396 | default: |
|
395 | default: | |
397 | // Creates default helper |
|
396 | // Creates default helper | |
398 | break; |
|
397 | break; | |
399 | } |
|
398 | } | |
400 |
|
399 | |||
401 | return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(nullptr); |
|
400 | return std::make_unique<PlottablesHelper<TimeSeries::ITimeSerie>>(nullptr); | |
402 | } |
|
401 | } | |
403 |
|
402 | |||
404 | } // namespace |
|
403 | } // namespace | |
405 |
|
404 | |||
406 | PlottablesMap VisualizationGraphHelper::create( |
|
405 | PlottablesMap VisualizationGraphHelper::create( | |
407 | std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept |
|
406 | std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept | |
408 | { |
|
407 | { | |
409 | if (variable) |
|
408 | if (variable) | |
410 | { |
|
409 | { | |
411 | auto helper = createHelper(variable); |
|
410 | auto helper = createHelper(variable); | |
412 | auto plottables = helper->create(plot); |
|
411 | auto plottables = helper->create(plot); | |
413 | return plottables; |
|
412 | return plottables; | |
414 | } |
|
413 | } | |
415 | else |
|
414 | else | |
416 | { |
|
415 | { | |
417 | qCDebug(LOG_VisualizationGraphHelper()) |
|
416 | qCDebug(LOG_VisualizationGraphHelper()) | |
418 | << QObject::tr("Can't create graph plottables : the variable is null"); |
|
417 | << QObject::tr("Can't create graph plottables : the variable is null"); | |
419 | return PlottablesMap {}; |
|
418 | return PlottablesMap {}; | |
420 | } |
|
419 | } | |
421 | } |
|
420 | } | |
422 |
|
421 | |||
423 | void VisualizationGraphHelper::setYAxisRange( |
|
422 | void VisualizationGraphHelper::setYAxisRange( | |
424 | std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept |
|
423 | std::shared_ptr<Variable2> variable, QCustomPlot& plot) noexcept | |
425 | { |
|
424 | { | |
426 | if (variable) |
|
425 | if (variable) | |
427 | { |
|
426 | { | |
428 | auto helper = createHelper(variable); |
|
427 | auto helper = createHelper(variable); | |
429 | helper->setYAxisRange(variable->range(), plot); |
|
428 | helper->setYAxisRange(variable->range(), plot); | |
430 | } |
|
429 | } | |
431 | else |
|
430 | else | |
432 | { |
|
431 | { | |
433 | qCDebug(LOG_VisualizationGraphHelper()) |
|
432 | qCDebug(LOG_VisualizationGraphHelper()) | |
434 | << QObject::tr("Can't set y-axis range of plot: the variable is null"); |
|
433 | << QObject::tr("Can't set y-axis range of plot: the variable is null"); | |
435 | } |
|
434 | } | |
436 | } |
|
435 | } | |
437 |
|
436 | |||
438 | void VisualizationGraphHelper::updateData( |
|
437 | void VisualizationGraphHelper::updateData( | |
439 | PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& dateTime) |
|
438 | PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& dateTime) | |
440 | { |
|
439 | { | |
441 | auto helper = createHelper(variable); |
|
440 | auto helper = createHelper(variable); | |
442 | helper->update(plottables, dateTime); |
|
441 | helper->update(plottables, dateTime); | |
443 | } |
|
442 | } |
@@ -1,352 +1,349 | |||||
1 | #include "Visualization/VisualizationGraphRenderingDelegate.h" |
|
1 | #include "Visualization/VisualizationGraphRenderingDelegate.h" | |
2 | #include "Visualization/AxisRenderingUtils.h" |
|
2 | #include "Visualization/AxisRenderingUtils.h" | |
3 | #include "Visualization/ColorScaleEditor.h" |
|
3 | #include "Visualization/ColorScaleEditor.h" | |
4 | #include "Visualization/PlottablesRenderingUtils.h" |
|
4 | #include "Visualization/PlottablesRenderingUtils.h" | |
5 | #include "Visualization/SqpColorScale.h" |
|
5 | #include "Visualization/SqpColorScale.h" | |
6 | #include "Visualization/VisualizationGraphWidget.h" |
|
6 | #include "Visualization/VisualizationGraphWidget.h" | |
7 | #include "Visualization/qcustomplot.h" |
|
7 | #include "Visualization/qcustomplot.h" | |
8 |
|
8 | |||
9 | #include <Common/DateUtils.h> |
|
9 | #include <Common/DateUtils.h> | |
10 |
|
10 | |||
11 | #include <Data/IDataSeries.h> |
|
|||
12 | #include <Variable/Variable.h> |
|
|||
13 |
|
||||
14 | #include <SqpApplication.h> |
|
11 | #include <SqpApplication.h> | |
15 |
|
12 | |||
16 | namespace |
|
13 | namespace | |
17 | { |
|
14 | { | |
18 |
|
15 | |||
19 | /// Name of the axes layer in QCustomPlot |
|
16 | /// Name of the axes layer in QCustomPlot | |
20 | const auto AXES_LAYER = QStringLiteral("axes"); |
|
17 | const auto AXES_LAYER = QStringLiteral("axes"); | |
21 |
|
18 | |||
22 | /// Icon used to show x-axis properties |
|
19 | /// Icon used to show x-axis properties | |
23 | const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png"); |
|
20 | const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png"); | |
24 |
|
21 | |||
25 | /// Name of the overlay layer in QCustomPlot |
|
22 | /// Name of the overlay layer in QCustomPlot | |
26 | const auto OVERLAY_LAYER = QStringLiteral("overlay"); |
|
23 | const auto OVERLAY_LAYER = QStringLiteral("overlay"); | |
27 |
|
24 | |||
28 | /// Pixmap used to show x-axis properties |
|
25 | /// Pixmap used to show x-axis properties | |
29 | const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png"); |
|
26 | const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png"); | |
30 |
|
27 | |||
31 | /// Tooltip format for graphs |
|
28 | /// Tooltip format for graphs | |
32 | const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2"); |
|
29 | const auto GRAPH_TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2"); | |
33 |
|
30 | |||
34 | /// Tooltip format for colormaps |
|
31 | /// Tooltip format for colormaps | |
35 | const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3"); |
|
32 | const auto COLORMAP_TOOLTIP_FORMAT = QStringLiteral("x: %1\ny: %2\nvalue: %3"); | |
36 |
|
33 | |||
37 | /// Offset used to shift the tooltip of the mouse |
|
34 | /// Offset used to shift the tooltip of the mouse | |
38 | const auto TOOLTIP_OFFSET = QPoint { 20, 20 }; |
|
35 | const auto TOOLTIP_OFFSET = QPoint { 20, 20 }; | |
39 |
|
36 | |||
40 | /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle) |
|
37 | /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle) | |
41 | const auto TOOLTIP_RECT = QRect { 10, 10, 10, 10 }; |
|
38 | const auto TOOLTIP_RECT = QRect { 10, 10, 10, 10 }; | |
42 |
|
39 | |||
43 | /// Timeout after which the tooltip is displayed |
|
40 | /// Timeout after which the tooltip is displayed | |
44 | const auto TOOLTIP_TIMEOUT = 500; |
|
41 | const auto TOOLTIP_TIMEOUT = 500; | |
45 |
|
42 | |||
46 | void initPointTracerStyle(QCPItemTracer& tracer) noexcept |
|
43 | void initPointTracerStyle(QCPItemTracer& tracer) noexcept | |
47 | { |
|
44 | { | |
48 | tracer.setInterpolating(false); |
|
45 | tracer.setInterpolating(false); | |
49 | tracer.setStyle(QCPItemTracer::tsCircle); |
|
46 | tracer.setStyle(QCPItemTracer::tsCircle); | |
50 | tracer.setSize(3); |
|
47 | tracer.setSize(3); | |
51 | tracer.setPen(QPen(Qt::black)); |
|
48 | tracer.setPen(QPen(Qt::black)); | |
52 | tracer.setBrush(Qt::black); |
|
49 | tracer.setBrush(Qt::black); | |
53 | tracer.setSelectable(false); |
|
50 | tracer.setSelectable(false); | |
54 | } |
|
51 | } | |
55 |
|
52 | |||
56 | QPixmap pixmap(const QString& iconPath) noexcept |
|
53 | QPixmap pixmap(const QString& iconPath) noexcept | |
57 | { |
|
54 | { | |
58 | return QIcon { iconPath }.pixmap(QSize { 16, 16 }); |
|
55 | return QIcon { iconPath }.pixmap(QSize { 16, 16 }); | |
59 | } |
|
56 | } | |
60 |
|
57 | |||
61 | void initClosePixmapStyle(QCPItemPixmap& pixmap) noexcept |
|
58 | void initClosePixmapStyle(QCPItemPixmap& pixmap) noexcept | |
62 | { |
|
59 | { | |
63 | // Icon |
|
60 | // Icon | |
64 | pixmap.setPixmap( |
|
61 | pixmap.setPixmap( | |
65 | sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize { 16, 16 })); |
|
62 | sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize { 16, 16 })); | |
66 |
|
63 | |||
67 | // Position |
|
64 | // Position | |
68 | pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio); |
|
65 | pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio); | |
69 | pixmap.topLeft->setCoords(1, 0); |
|
66 | pixmap.topLeft->setCoords(1, 0); | |
70 | pixmap.setClipToAxisRect(false); |
|
67 | pixmap.setClipToAxisRect(false); | |
71 |
|
68 | |||
72 | // Can be selected |
|
69 | // Can be selected | |
73 | pixmap.setSelectable(true); |
|
70 | pixmap.setSelectable(true); | |
74 | } |
|
71 | } | |
75 |
|
72 | |||
76 | void initXAxisPixmapStyle(QCPItemPixmap& itemPixmap) noexcept |
|
73 | void initXAxisPixmapStyle(QCPItemPixmap& itemPixmap) noexcept | |
77 | { |
|
74 | { | |
78 | // Icon |
|
75 | // Icon | |
79 | itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH)); |
|
76 | itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH)); | |
80 |
|
77 | |||
81 | // Position |
|
78 | // Position | |
82 | itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio); |
|
79 | itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio); | |
83 | itemPixmap.topLeft->setCoords(0, 1); |
|
80 | itemPixmap.topLeft->setCoords(0, 1); | |
84 | itemPixmap.setClipToAxisRect(false); |
|
81 | itemPixmap.setClipToAxisRect(false); | |
85 |
|
82 | |||
86 | // Can be selected |
|
83 | // Can be selected | |
87 | itemPixmap.setSelectable(true); |
|
84 | itemPixmap.setSelectable(true); | |
88 | } |
|
85 | } | |
89 |
|
86 | |||
90 | void initTitleTextStyle(QCPItemText& text) noexcept |
|
87 | void initTitleTextStyle(QCPItemText& text) noexcept | |
91 | { |
|
88 | { | |
92 | // Font and background styles |
|
89 | // Font and background styles | |
93 | text.setColor(Qt::gray); |
|
90 | text.setColor(Qt::gray); | |
94 | text.setBrush(Qt::white); |
|
91 | text.setBrush(Qt::white); | |
95 |
|
92 | |||
96 | // Position |
|
93 | // Position | |
97 | text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft); |
|
94 | text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft); | |
98 | text.position->setType(QCPItemPosition::ptAxisRectRatio); |
|
95 | text.position->setType(QCPItemPosition::ptAxisRectRatio); | |
99 | text.position->setCoords(0.5, 0); |
|
96 | text.position->setCoords(0.5, 0); | |
100 | text.setSelectable(false); |
|
97 | text.setSelectable(false); | |
101 | } |
|
98 | } | |
102 |
|
99 | |||
103 | /** |
|
100 | /** | |
104 | * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter. |
|
101 | * Returns the cell index (x or y) of a colormap according to the coordinate passed in parameter. | |
105 | * This method handles the fact that a colormap axis can be logarithmic or linear. |
|
102 | * This method handles the fact that a colormap axis can be logarithmic or linear. | |
106 | * @param colormap the colormap for which to calculate the index |
|
103 | * @param colormap the colormap for which to calculate the index | |
107 | * @param coord the coord to convert to cell index |
|
104 | * @param coord the coord to convert to cell index | |
108 | * @param xCoord calculates the x index if true, calculates y index if false |
|
105 | * @param xCoord calculates the x index if true, calculates y index if false | |
109 | * @return the cell index |
|
106 | * @return the cell index | |
110 | */ |
|
107 | */ | |
111 | int colorMapCellIndex(const QCPColorMap& colormap, double coord, bool xCoord) |
|
108 | int colorMapCellIndex(const QCPColorMap& colormap, double coord, bool xCoord) | |
112 | { |
|
109 | { | |
113 | // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not |
|
110 | // Determines the axis of the colormap according to xCoord, and whether it is logarithmic or not | |
114 | auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType() |
|
111 | auto isLogarithmic = (xCoord ? colormap.keyAxis() : colormap.valueAxis())->scaleType() | |
115 | == QCPAxis::stLogarithmic; |
|
112 | == QCPAxis::stLogarithmic; | |
116 |
|
113 | |||
117 | if (isLogarithmic) |
|
114 | if (isLogarithmic) | |
118 | { |
|
115 | { | |
119 | // For a logarithmic axis we can't use the conversion method of colormap, so we calculate |
|
116 | // For a logarithmic axis we can't use the conversion method of colormap, so we calculate | |
120 | // the index manually based on the position of the coordinate on the axis |
|
117 | // the index manually based on the position of the coordinate on the axis | |
121 |
|
118 | |||
122 | // Gets the axis range and the number of values between range bounds to calculate the step |
|
119 | // Gets the axis range and the number of values between range bounds to calculate the step | |
123 | // between each value of the range |
|
120 | // between each value of the range | |
124 | auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange(); |
|
121 | auto range = xCoord ? colormap.data()->keyRange() : colormap.data()->valueRange(); | |
125 | auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1; |
|
122 | auto nbValues = (xCoord ? colormap.data()->keySize() : colormap.data()->valueSize()) - 1; | |
126 | auto valueStep |
|
123 | auto valueStep | |
127 | = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues); |
|
124 | = (std::log10(range.upper) - std::log10(range.lower)) / static_cast<double>(nbValues); | |
128 |
|
125 | |||
129 | // According to the coord position, calculates the closest index in the range |
|
126 | // According to the coord position, calculates the closest index in the range | |
130 | return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep); |
|
127 | return std::round((std::log10(coord) - std::log10(range.lower)) / valueStep); | |
131 | } |
|
128 | } | |
132 | else |
|
129 | else | |
133 | { |
|
130 | { | |
134 | // For a linear axis, we use the conversion method of colormap |
|
131 | // For a linear axis, we use the conversion method of colormap | |
135 | int index; |
|
132 | int index; | |
136 | if (xCoord) |
|
133 | if (xCoord) | |
137 | { |
|
134 | { | |
138 | colormap.data()->coordToCell(coord, 0., &index, nullptr); |
|
135 | colormap.data()->coordToCell(coord, 0., &index, nullptr); | |
139 | } |
|
136 | } | |
140 | else |
|
137 | else | |
141 | { |
|
138 | { | |
142 | colormap.data()->coordToCell(0., coord, nullptr, &index); |
|
139 | colormap.data()->coordToCell(0., coord, nullptr, &index); | |
143 | } |
|
140 | } | |
144 |
|
141 | |||
145 | return index; |
|
142 | return index; | |
146 | } |
|
143 | } | |
147 | } |
|
144 | } | |
148 |
|
145 | |||
149 | } // namespace |
|
146 | } // namespace | |
150 |
|
147 | |||
151 | struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate |
|
148 | struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate | |
152 | { |
|
149 | { | |
153 | explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget& graphWidget) |
|
150 | explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget& graphWidget) | |
154 | : m_Plot { graphWidget.plot() } |
|
151 | : m_Plot { graphWidget.plot() } | |
155 | , m_PointTracer { new QCPItemTracer { &m_Plot } } |
|
152 | , m_PointTracer { new QCPItemTracer { &m_Plot } } | |
156 | , m_TracerTimer {} |
|
153 | , m_TracerTimer {} | |
157 | , m_ClosePixmap { new QCPItemPixmap { &m_Plot } } |
|
154 | , m_ClosePixmap { new QCPItemPixmap { &m_Plot } } | |
158 | , m_TitleText { new QCPItemText { &m_Plot } } |
|
155 | , m_TitleText { new QCPItemText { &m_Plot } } | |
159 | , m_XAxisPixmap { new QCPItemPixmap { &m_Plot } } |
|
156 | , m_XAxisPixmap { new QCPItemPixmap { &m_Plot } } | |
160 | , m_ShowXAxis { true } |
|
157 | , m_ShowXAxis { true } | |
161 | , m_XAxisLabel {} |
|
158 | , m_XAxisLabel {} | |
162 | , m_ColorScale { SqpColorScale { m_Plot } } |
|
159 | , m_ColorScale { SqpColorScale { m_Plot } } | |
163 | { |
|
160 | { | |
164 | initPointTracerStyle(*m_PointTracer); |
|
161 | initPointTracerStyle(*m_PointTracer); | |
165 |
|
162 | |||
166 | m_TracerTimer.setInterval(TOOLTIP_TIMEOUT); |
|
163 | m_TracerTimer.setInterval(TOOLTIP_TIMEOUT); | |
167 | m_TracerTimer.setSingleShot(true); |
|
164 | m_TracerTimer.setSingleShot(true); | |
168 |
|
165 | |||
169 | // Inits "close button" in plot overlay |
|
166 | // Inits "close button" in plot overlay | |
170 | m_ClosePixmap->setLayer(OVERLAY_LAYER); |
|
167 | m_ClosePixmap->setLayer(OVERLAY_LAYER); | |
171 | initClosePixmapStyle(*m_ClosePixmap); |
|
168 | initClosePixmapStyle(*m_ClosePixmap); | |
172 |
|
169 | |||
173 | // Connects pixmap selection to graph widget closing |
|
170 | // Connects pixmap selection to graph widget closing | |
174 | QObject::connect( |
|
171 | QObject::connect( | |
175 | &m_Plot, &QCustomPlot::itemClick, [&graphWidget, this](auto item, auto mouseEvent) { |
|
172 | &m_Plot, &QCustomPlot::itemClick, [&graphWidget, this](auto item, auto mouseEvent) { | |
176 | if (item == m_ClosePixmap) |
|
173 | if (item == m_ClosePixmap) | |
177 | { |
|
174 | { | |
178 | graphWidget.close(); |
|
175 | graphWidget.close(); | |
179 | } |
|
176 | } | |
180 | }); |
|
177 | }); | |
181 |
|
178 | |||
182 | // Inits graph name in plot overlay |
|
179 | // Inits graph name in plot overlay | |
183 | m_TitleText->setLayer(OVERLAY_LAYER); |
|
180 | m_TitleText->setLayer(OVERLAY_LAYER); | |
184 | m_TitleText->setText(graphWidget.name()); |
|
181 | m_TitleText->setText(graphWidget.name()); | |
185 | initTitleTextStyle(*m_TitleText); |
|
182 | initTitleTextStyle(*m_TitleText); | |
186 |
|
183 | |||
187 | // Inits "show x-axis button" in plot overlay |
|
184 | // Inits "show x-axis button" in plot overlay | |
188 | m_XAxisPixmap->setLayer(OVERLAY_LAYER); |
|
185 | m_XAxisPixmap->setLayer(OVERLAY_LAYER); | |
189 | initXAxisPixmapStyle(*m_XAxisPixmap); |
|
186 | initXAxisPixmapStyle(*m_XAxisPixmap); | |
190 |
|
187 | |||
191 | // Connects pixmap selection to graph x-axis showing/hiding |
|
188 | // Connects pixmap selection to graph x-axis showing/hiding | |
192 | QObject::connect(&m_Plot, &QCustomPlot::itemClick, [this](auto item, auto mouseEvent) { |
|
189 | QObject::connect(&m_Plot, &QCustomPlot::itemClick, [this](auto item, auto mouseEvent) { | |
193 | if (m_XAxisPixmap == item) |
|
190 | if (m_XAxisPixmap == item) | |
194 | { |
|
191 | { | |
195 | // Changes the selection state and refreshes the x-axis |
|
192 | // Changes the selection state and refreshes the x-axis | |
196 | m_ShowXAxis = !m_ShowXAxis; |
|
193 | m_ShowXAxis = !m_ShowXAxis; | |
197 | this->updateXAxisState(); |
|
194 | this->updateXAxisState(); | |
198 | m_Plot.layer(AXES_LAYER)->replot(); |
|
195 | m_Plot.layer(AXES_LAYER)->replot(); | |
199 |
|
196 | |||
200 | // Deselects the x-axis pixmap and updates icon |
|
197 | // Deselects the x-axis pixmap and updates icon | |
201 | m_XAxisPixmap->setPixmap( |
|
198 | m_XAxisPixmap->setPixmap( | |
202 | pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH)); |
|
199 | pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH)); | |
203 | m_Plot.layer(OVERLAY_LAYER)->replot(); |
|
200 | m_Plot.layer(OVERLAY_LAYER)->replot(); | |
204 | } |
|
201 | } | |
205 | }); |
|
202 | }); | |
206 | } |
|
203 | } | |
207 |
|
204 | |||
208 | /// Updates state of x-axis according to the current selection of x-axis pixmap |
|
205 | /// Updates state of x-axis according to the current selection of x-axis pixmap | |
209 | /// @remarks the method doesn't call plot refresh |
|
206 | /// @remarks the method doesn't call plot refresh | |
210 | void updateXAxisState() noexcept |
|
207 | void updateXAxisState() noexcept | |
211 | { |
|
208 | { | |
212 | m_Plot.xAxis->setTickLabels(m_ShowXAxis); |
|
209 | m_Plot.xAxis->setTickLabels(m_ShowXAxis); | |
213 | m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString {}); |
|
210 | m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString {}); | |
214 | } |
|
211 | } | |
215 |
|
212 | |||
216 | QCustomPlot& m_Plot; |
|
213 | QCustomPlot& m_Plot; | |
217 | QCPItemTracer* m_PointTracer; |
|
214 | QCPItemTracer* m_PointTracer; | |
218 | QTimer m_TracerTimer; |
|
215 | QTimer m_TracerTimer; | |
219 | QCPItemPixmap* m_ClosePixmap; /// Graph's close button |
|
216 | QCPItemPixmap* m_ClosePixmap; /// Graph's close button | |
220 | QCPItemText* m_TitleText; /// Graph's title |
|
217 | QCPItemText* m_TitleText; /// Graph's title | |
221 | QCPItemPixmap* m_XAxisPixmap; |
|
218 | QCPItemPixmap* m_XAxisPixmap; | |
222 | bool m_ShowXAxis; /// X-axis properties are shown or hidden |
|
219 | bool m_ShowXAxis; /// X-axis properties are shown or hidden | |
223 | QString m_XAxisLabel; |
|
220 | QString m_XAxisLabel; | |
224 | SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms) |
|
221 | SqpColorScale m_ColorScale; /// Color scale used for some types of graphs (as spectrograms) | |
225 | }; |
|
222 | }; | |
226 |
|
223 | |||
227 | VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate( |
|
224 | VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate( | |
228 | VisualizationGraphWidget& graphWidget) |
|
225 | VisualizationGraphWidget& graphWidget) | |
229 | : impl { spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget) } |
|
226 | : impl { spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget) } | |
230 | { |
|
227 | { | |
231 | } |
|
228 | } | |
232 |
|
229 | |||
233 | void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent* event) noexcept |
|
230 | void VisualizationGraphRenderingDelegate::onMouseDoubleClick(QMouseEvent* event) noexcept | |
234 | { |
|
231 | { | |
235 | // Opens color scale editor if color scale is double clicked |
|
232 | // Opens color scale editor if color scale is double clicked | |
236 | auto colorScale = static_cast<QCPColorScale*>(impl->m_Plot.layoutElementAt(event->pos())); |
|
233 | auto colorScale = static_cast<QCPColorScale*>(impl->m_Plot.layoutElementAt(event->pos())); | |
237 | if (impl->m_ColorScale.m_Scale == colorScale) |
|
234 | if (impl->m_ColorScale.m_Scale == colorScale) | |
238 | { |
|
235 | { | |
239 | if (ColorScaleEditor { impl->m_ColorScale }.exec() == QDialog::Accepted) |
|
236 | if (ColorScaleEditor { impl->m_ColorScale }.exec() == QDialog::Accepted) | |
240 | { |
|
237 | { | |
241 | impl->m_Plot.replot(); |
|
238 | impl->m_Plot.replot(); | |
242 | } |
|
239 | } | |
243 | } |
|
240 | } | |
244 | } |
|
241 | } | |
245 |
|
242 | |||
246 | void VisualizationGraphRenderingDelegate::updateTooltip(QMouseEvent* event) noexcept |
|
243 | void VisualizationGraphRenderingDelegate::updateTooltip(QMouseEvent* event) noexcept | |
247 | { |
|
244 | { | |
248 | // Cancels pending refresh |
|
245 | // Cancels pending refresh | |
249 | impl->m_TracerTimer.disconnect(); |
|
246 | impl->m_TracerTimer.disconnect(); | |
250 |
|
247 | |||
251 | // Reinits tracers |
|
248 | // Reinits tracers | |
252 | impl->m_PointTracer->setGraph(nullptr); |
|
249 | impl->m_PointTracer->setGraph(nullptr); | |
253 | impl->m_PointTracer->setVisible(false); |
|
250 | impl->m_PointTracer->setVisible(false); | |
254 | impl->m_Plot.replot(); |
|
251 | impl->m_Plot.replot(); | |
255 |
|
252 | |||
256 | QString tooltip {}; |
|
253 | QString tooltip {}; | |
257 |
|
254 | |||
258 | // Gets the graph under the mouse position |
|
255 | // Gets the graph under the mouse position | |
259 | auto eventPos = event->pos(); |
|
256 | auto eventPos = event->pos(); | |
260 | if (auto graph = qobject_cast<QCPGraph*>(impl->m_Plot.plottableAt(eventPos))) |
|
257 | if (auto graph = qobject_cast<QCPGraph*>(impl->m_Plot.plottableAt(eventPos))) | |
261 | { |
|
258 | { | |
262 | auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x()); |
|
259 | auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x()); | |
263 | auto graphData = graph->data(); |
|
260 | auto graphData = graph->data(); | |
264 |
|
261 | |||
265 | // Gets the closest data point to the mouse |
|
262 | // Gets the closest data point to the mouse | |
266 | auto graphDataIt = graphData->findBegin(mouseKey); |
|
263 | auto graphDataIt = graphData->findBegin(mouseKey); | |
267 | if (graphDataIt != graphData->constEnd()) |
|
264 | if (graphDataIt != graphData->constEnd()) | |
268 | { |
|
265 | { | |
269 | // Sets tooltip |
|
266 | // Sets tooltip | |
270 | auto key = formatValue(graphDataIt->key, *graph->keyAxis()); |
|
267 | auto key = formatValue(graphDataIt->key, *graph->keyAxis()); | |
271 | auto value = formatValue(graphDataIt->value, *graph->valueAxis()); |
|
268 | auto value = formatValue(graphDataIt->value, *graph->valueAxis()); | |
272 | tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value); |
|
269 | tooltip = GRAPH_TOOLTIP_FORMAT.arg(key, value); | |
273 |
|
270 | |||
274 | // Displays point tracer |
|
271 | // Displays point tracer | |
275 | impl->m_PointTracer->setGraph(graph); |
|
272 | impl->m_PointTracer->setGraph(graph); | |
276 | impl->m_PointTracer->setGraphKey(graphDataIt->key); |
|
273 | impl->m_PointTracer->setGraphKey(graphDataIt->key); | |
277 | impl->m_PointTracer->setLayer( |
|
274 | impl->m_PointTracer->setLayer( | |
278 | impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer |
|
275 | impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer | |
279 | impl->m_PointTracer->setVisible(true); |
|
276 | impl->m_PointTracer->setVisible(true); | |
280 | impl->m_Plot.replot(); |
|
277 | impl->m_Plot.replot(); | |
281 | } |
|
278 | } | |
282 | } |
|
279 | } | |
283 | else if (auto colorMap = qobject_cast<QCPColorMap*>(impl->m_Plot.plottableAt(eventPos))) |
|
280 | else if (auto colorMap = qobject_cast<QCPColorMap*>(impl->m_Plot.plottableAt(eventPos))) | |
284 | { |
|
281 | { | |
285 | // Gets x and y coords |
|
282 | // Gets x and y coords | |
286 | auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x()); |
|
283 | auto x = colorMap->keyAxis()->pixelToCoord(eventPos.x()); | |
287 | auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y()); |
|
284 | auto y = colorMap->valueAxis()->pixelToCoord(eventPos.y()); | |
288 |
|
285 | |||
289 | // Calculates x and y cell indexes, and retrieves the underlying value |
|
286 | // Calculates x and y cell indexes, and retrieves the underlying value | |
290 | auto xCellIndex = colorMapCellIndex(*colorMap, x, true); |
|
287 | auto xCellIndex = colorMapCellIndex(*colorMap, x, true); | |
291 | auto yCellIndex = colorMapCellIndex(*colorMap, y, false); |
|
288 | auto yCellIndex = colorMapCellIndex(*colorMap, y, false); | |
292 | auto value = colorMap->data()->cell(xCellIndex, yCellIndex); |
|
289 | auto value = colorMap->data()->cell(xCellIndex, yCellIndex); | |
293 |
|
290 | |||
294 | // Sets tooltips |
|
291 | // Sets tooltips | |
295 | tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()), |
|
292 | tooltip = COLORMAP_TOOLTIP_FORMAT.arg(formatValue(x, *colorMap->keyAxis()), | |
296 | formatValue(y, *colorMap->valueAxis()), |
|
293 | formatValue(y, *colorMap->valueAxis()), | |
297 | formatValue(value, *colorMap->colorScale()->axis())); |
|
294 | formatValue(value, *colorMap->colorScale()->axis())); | |
298 | } |
|
295 | } | |
299 |
|
296 | |||
300 | if (!tooltip.isEmpty()) |
|
297 | if (!tooltip.isEmpty()) | |
301 | { |
|
298 | { | |
302 | // Starts timer to show tooltip after timeout |
|
299 | // Starts timer to show tooltip after timeout | |
303 | auto showTooltip = [tooltip, eventPos, this]() { |
|
300 | auto showTooltip = [tooltip, eventPos, this]() { | |
304 | QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip, |
|
301 | QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip, | |
305 | &impl->m_Plot, TOOLTIP_RECT); |
|
302 | &impl->m_Plot, TOOLTIP_RECT); | |
306 | }; |
|
303 | }; | |
307 |
|
304 | |||
308 | QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip); |
|
305 | QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip); | |
309 | impl->m_TracerTimer.start(); |
|
306 | impl->m_TracerTimer.start(); | |
310 | } |
|
307 | } | |
311 | } |
|
308 | } | |
312 |
|
309 | |||
313 | void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept |
|
310 | void VisualizationGraphRenderingDelegate::onPlotUpdated() noexcept | |
314 | { |
|
311 | { | |
315 | // Updates color scale bounds |
|
312 | // Updates color scale bounds | |
316 | impl->m_ColorScale.updateDataRange(); |
|
313 | impl->m_ColorScale.updateDataRange(); | |
317 | impl->m_Plot.replot(); |
|
314 | impl->m_Plot.replot(); | |
318 | } |
|
315 | } | |
319 |
|
316 | |||
320 | void VisualizationGraphRenderingDelegate::setAxesUnits(Variable2& variable) noexcept |
|
317 | void VisualizationGraphRenderingDelegate::setAxesUnits(Variable2& variable) noexcept | |
321 | { |
|
318 | { | |
322 |
|
319 | |||
323 | auto axisHelper = IAxisHelperFactory::create(variable); |
|
320 | auto axisHelper = IAxisHelperFactory::create(variable); | |
324 | axisHelper->setUnits(impl->m_Plot, impl->m_ColorScale); |
|
321 | axisHelper->setUnits(impl->m_Plot, impl->m_ColorScale); | |
325 |
|
322 | |||
326 | // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected |
|
323 | // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected | |
327 | impl->m_XAxisLabel = impl->m_Plot.xAxis->label(); |
|
324 | impl->m_XAxisLabel = impl->m_Plot.xAxis->label(); | |
328 |
|
325 | |||
329 | // Updates x-axis state |
|
326 | // Updates x-axis state | |
330 | impl->updateXAxisState(); |
|
327 | impl->updateXAxisState(); | |
331 |
|
328 | |||
332 | impl->m_Plot.layer(AXES_LAYER)->replot(); |
|
329 | impl->m_Plot.layer(AXES_LAYER)->replot(); | |
333 | } |
|
330 | } | |
334 |
|
331 | |||
335 | void VisualizationGraphRenderingDelegate::setGraphProperties( |
|
332 | void VisualizationGraphRenderingDelegate::setGraphProperties( | |
336 | Variable2& variable, PlottablesMap& plottables) noexcept |
|
333 | Variable2& variable, PlottablesMap& plottables) noexcept | |
337 | { |
|
334 | { | |
338 | // Axes' properties |
|
335 | // Axes' properties | |
339 | auto axisHelper = IAxisHelperFactory::create(variable); |
|
336 | auto axisHelper = IAxisHelperFactory::create(variable); | |
340 | axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale); |
|
337 | axisHelper->setProperties(impl->m_Plot, impl->m_ColorScale); | |
341 |
|
338 | |||
342 | // Plottables' properties |
|
339 | // Plottables' properties | |
343 | auto plottablesHelper = IPlottablesHelperFactory::create(variable); |
|
340 | auto plottablesHelper = IPlottablesHelperFactory::create(variable); | |
344 | plottablesHelper->setProperties(plottables); |
|
341 | plottablesHelper->setProperties(plottables); | |
345 | } |
|
342 | } | |
346 |
|
343 | |||
347 | void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept |
|
344 | void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept | |
348 | { |
|
345 | { | |
349 | auto overlay = impl->m_Plot.layer(OVERLAY_LAYER); |
|
346 | auto overlay = impl->m_Plot.layer(OVERLAY_LAYER); | |
350 | overlay->setVisible(show); |
|
347 | overlay->setVisible(show); | |
351 | overlay->replot(); |
|
348 | overlay->replot(); | |
352 | } |
|
349 | } |
@@ -1,1580 +1,1577 | |||||
1 | #include "Visualization/VisualizationGraphWidget.h" |
|
1 | #include "Visualization/VisualizationGraphWidget.h" | |
2 | #include "Visualization/IVisualizationWidgetVisitor.h" |
|
2 | #include "Visualization/IVisualizationWidgetVisitor.h" | |
3 | #include "Visualization/VisualizationCursorItem.h" |
|
3 | #include "Visualization/VisualizationCursorItem.h" | |
4 | #include "Visualization/VisualizationDefs.h" |
|
4 | #include "Visualization/VisualizationDefs.h" | |
5 | #include "Visualization/VisualizationGraphHelper.h" |
|
5 | #include "Visualization/VisualizationGraphHelper.h" | |
6 | #include "Visualization/VisualizationGraphRenderingDelegate.h" |
|
6 | #include "Visualization/VisualizationGraphRenderingDelegate.h" | |
7 | #include "Visualization/VisualizationMultiZoneSelectionDialog.h" |
|
7 | #include "Visualization/VisualizationMultiZoneSelectionDialog.h" | |
8 | #include "Visualization/VisualizationSelectionZoneItem.h" |
|
8 | #include "Visualization/VisualizationSelectionZoneItem.h" | |
9 | #include "Visualization/VisualizationSelectionZoneManager.h" |
|
9 | #include "Visualization/VisualizationSelectionZoneManager.h" | |
10 | #include "Visualization/VisualizationWidget.h" |
|
10 | #include "Visualization/VisualizationWidget.h" | |
11 | #include "Visualization/VisualizationZoneWidget.h" |
|
11 | #include "Visualization/VisualizationZoneWidget.h" | |
12 | #include "ui_VisualizationGraphWidget.h" |
|
12 | #include "ui_VisualizationGraphWidget.h" | |
13 |
|
13 | |||
14 | #include <Actions/ActionsGuiController.h> |
|
14 | #include <Actions/ActionsGuiController.h> | |
15 | #include <Actions/FilteringAction.h> |
|
15 | #include <Actions/FilteringAction.h> | |
16 | #include <Common/MimeTypesDef.h> |
|
16 | #include <Common/MimeTypesDef.h> | |
17 | #include <Common/containers.h> |
|
17 | #include <Common/containers.h> | |
18 | #include <Data/ArrayData.h> |
|
|||
19 | #include <Data/DateTimeRangeHelper.h> |
|
18 | #include <Data/DateTimeRangeHelper.h> | |
20 | #include <Data/IDataSeries.h> |
|
|||
21 | #include <Data/SpectrogramSeries.h> |
|
|||
22 | #include <DragAndDrop/DragDropGuiController.h> |
|
19 | #include <DragAndDrop/DragDropGuiController.h> | |
23 | #include <Settings/SqpSettingsDefs.h> |
|
20 | #include <Settings/SqpSettingsDefs.h> | |
24 | #include <SqpApplication.h> |
|
21 | #include <SqpApplication.h> | |
25 | #include <Time/TimeController.h> |
|
22 | #include <Time/TimeController.h> | |
26 | #include <Variable/Variable2.h> |
|
23 | #include <Variable/Variable2.h> | |
27 | #include <Variable/VariableController2.h> |
|
24 | #include <Variable/VariableController2.h> | |
28 |
|
25 | |||
29 | #include <unordered_map> |
|
26 | #include <unordered_map> | |
30 |
|
27 | |||
31 | Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget") |
|
28 | Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget") | |
32 |
|
29 | |||
33 | namespace |
|
30 | namespace | |
34 | { |
|
31 | { | |
35 |
|
32 | |||
36 | /// Key pressed to enable drag&drop in all modes |
|
33 | /// Key pressed to enable drag&drop in all modes | |
37 | const auto DRAG_DROP_MODIFIER = Qt::AltModifier; |
|
34 | const auto DRAG_DROP_MODIFIER = Qt::AltModifier; | |
38 |
|
35 | |||
39 | /// Key pressed to enable zoom on horizontal axis |
|
36 | /// Key pressed to enable zoom on horizontal axis | |
40 | const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier; |
|
37 | const auto HORIZONTAL_ZOOM_MODIFIER = Qt::ControlModifier; | |
41 |
|
38 | |||
42 | /// Key pressed to enable zoom on vertical axis |
|
39 | /// Key pressed to enable zoom on vertical axis | |
43 | const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier; |
|
40 | const auto VERTICAL_ZOOM_MODIFIER = Qt::ShiftModifier; | |
44 |
|
41 | |||
45 | /// Speed of a step of a wheel event for a pan, in percentage of the axis range |
|
42 | /// Speed of a step of a wheel event for a pan, in percentage of the axis range | |
46 | const auto PAN_SPEED = 5; |
|
43 | const auto PAN_SPEED = 5; | |
47 |
|
44 | |||
48 | /// Key pressed to enable a calibration pan |
|
45 | /// Key pressed to enable a calibration pan | |
49 | const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier; |
|
46 | const auto VERTICAL_PAN_MODIFIER = Qt::AltModifier; | |
50 |
|
47 | |||
51 | /// Key pressed to enable multi selection of selection zones |
|
48 | /// Key pressed to enable multi selection of selection zones | |
52 | const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier; |
|
49 | const auto MULTI_ZONE_SELECTION_MODIFIER = Qt::ControlModifier; | |
53 |
|
50 | |||
54 | /// Minimum size for the zoom box, in percentage of the axis range |
|
51 | /// Minimum size for the zoom box, in percentage of the axis range | |
55 | const auto ZOOM_BOX_MIN_SIZE = 0.8; |
|
52 | const auto ZOOM_BOX_MIN_SIZE = 0.8; | |
56 |
|
53 | |||
57 | /// Format of the dates appearing in the label of a cursor |
|
54 | /// Format of the dates appearing in the label of a cursor | |
58 | const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz"); |
|
55 | const auto CURSOR_LABELS_DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd\nhh:mm:ss:zzz"); | |
59 |
|
56 | |||
60 | } // namespace |
|
57 | } // namespace | |
61 |
|
58 | |||
62 | struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate |
|
59 | struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate | |
63 | { |
|
60 | { | |
64 |
|
61 | |||
65 | explicit VisualizationGraphWidgetPrivate(const QString& name) |
|
62 | explicit VisualizationGraphWidgetPrivate(const QString& name) | |
66 | : m_Name { name } |
|
63 | : m_Name { name } | |
67 | , m_Flags { GraphFlag::EnableAll } |
|
64 | , m_Flags { GraphFlag::EnableAll } | |
68 | , m_IsCalibration { false } |
|
65 | , m_IsCalibration { false } | |
69 | , m_RenderingDelegate { nullptr } |
|
66 | , m_RenderingDelegate { nullptr } | |
70 | { |
|
67 | { | |
71 | m_plot = new QCustomPlot(); |
|
68 | m_plot = new QCustomPlot(); | |
72 | // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable. |
|
69 | // Necessary for all platform since Qt::AA_EnableHighDpiScaling is enable. | |
73 | m_plot->setPlottingHint(QCP::phFastPolylines, true); |
|
70 | m_plot->setPlottingHint(QCP::phFastPolylines, true); | |
74 | } |
|
71 | } | |
75 |
|
72 | |||
76 | void updateData( |
|
73 | void updateData( | |
77 | PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& range) |
|
74 | PlottablesMap& plottables, std::shared_ptr<Variable2> variable, const DateTimeRange& range) | |
78 | { |
|
75 | { | |
79 | VisualizationGraphHelper::updateData(plottables, variable, range); |
|
76 | VisualizationGraphHelper::updateData(plottables, variable, range); | |
80 |
|
77 | |||
81 | // Prevents that data has changed to update rendering |
|
78 | // Prevents that data has changed to update rendering | |
82 | m_RenderingDelegate->onPlotUpdated(); |
|
79 | m_RenderingDelegate->onPlotUpdated(); | |
83 | } |
|
80 | } | |
84 |
|
81 | |||
85 | QString m_Name; |
|
82 | QString m_Name; | |
86 | // 1 variable -> n qcpplot |
|
83 | // 1 variable -> n qcpplot | |
87 | std::map<std::shared_ptr<Variable2>, PlottablesMap> m_VariableToPlotMultiMap; |
|
84 | std::map<std::shared_ptr<Variable2>, PlottablesMap> m_VariableToPlotMultiMap; | |
88 | GraphFlags m_Flags; |
|
85 | GraphFlags m_Flags; | |
89 | bool m_IsCalibration; |
|
86 | bool m_IsCalibration; | |
90 | QCustomPlot* m_plot; |
|
87 | QCustomPlot* m_plot; | |
91 | QPoint m_lastMousePos; |
|
88 | QPoint m_lastMousePos; | |
92 | QCPRange m_lastXRange; |
|
89 | QCPRange m_lastXRange; | |
93 | QCPRange m_lastYRange; |
|
90 | QCPRange m_lastYRange; | |
94 | /// Delegate used to attach rendering features to the plot |
|
91 | /// Delegate used to attach rendering features to the plot | |
95 | std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate; |
|
92 | std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate; | |
96 |
|
93 | |||
97 | QCPItemRect* m_DrawingZoomRect = nullptr; |
|
94 | QCPItemRect* m_DrawingZoomRect = nullptr; | |
98 | QStack<QPair<QCPRange, QCPRange>> m_ZoomStack; |
|
95 | QStack<QPair<QCPRange, QCPRange>> m_ZoomStack; | |
99 |
|
96 | |||
100 | std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr; |
|
97 | std::unique_ptr<VisualizationCursorItem> m_HorizontalCursor = nullptr; | |
101 | std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr; |
|
98 | std::unique_ptr<VisualizationCursorItem> m_VerticalCursor = nullptr; | |
102 |
|
99 | |||
103 | VisualizationSelectionZoneItem* m_DrawingZone = nullptr; |
|
100 | VisualizationSelectionZoneItem* m_DrawingZone = nullptr; | |
104 | VisualizationSelectionZoneItem* m_HoveredZone = nullptr; |
|
101 | VisualizationSelectionZoneItem* m_HoveredZone = nullptr; | |
105 | QVector<VisualizationSelectionZoneItem*> m_SelectionZones; |
|
102 | QVector<VisualizationSelectionZoneItem*> m_SelectionZones; | |
106 |
|
103 | |||
107 | bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even |
|
104 | bool m_HasMovedMouse = false; // Indicates if the mouse moved in a releaseMouse even | |
108 |
|
105 | |||
109 | bool m_VariableAutoRangeOnInit = true; |
|
106 | bool m_VariableAutoRangeOnInit = true; | |
110 |
|
107 | |||
111 | inline void enterPlotDrag(const QPoint& position) |
|
108 | inline void enterPlotDrag(const QPoint& position) | |
112 | { |
|
109 | { | |
113 | m_lastMousePos = m_plot->mapFromParent(position); |
|
110 | m_lastMousePos = m_plot->mapFromParent(position); | |
114 | m_lastXRange = m_plot->xAxis->range(); |
|
111 | m_lastXRange = m_plot->xAxis->range(); | |
115 | m_lastYRange = m_plot->yAxis->range(); |
|
112 | m_lastYRange = m_plot->yAxis->range(); | |
116 | } |
|
113 | } | |
117 |
|
114 | |||
118 | inline bool isDrawingZoomRect() { return m_DrawingZoomRect != nullptr; } |
|
115 | inline bool isDrawingZoomRect() { return m_DrawingZoomRect != nullptr; } | |
119 | void updateZoomRect(const QPoint& newPos) |
|
116 | void updateZoomRect(const QPoint& newPos) | |
120 | { |
|
117 | { | |
121 | QPointF pos { m_plot->xAxis->pixelToCoord(newPos.x()), |
|
118 | QPointF pos { m_plot->xAxis->pixelToCoord(newPos.x()), | |
122 | m_plot->yAxis->pixelToCoord(newPos.y()) }; |
|
119 | m_plot->yAxis->pixelToCoord(newPos.y()) }; | |
123 | m_DrawingZoomRect->bottomRight->setCoords(pos); |
|
120 | m_DrawingZoomRect->bottomRight->setCoords(pos); | |
124 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
121 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
125 | } |
|
122 | } | |
126 |
|
123 | |||
127 | void applyZoomRect() |
|
124 | void applyZoomRect() | |
128 | { |
|
125 | { | |
129 | auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom); |
|
126 | auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom); | |
130 | auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft); |
|
127 | auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft); | |
131 |
|
128 | |||
132 | auto newAxisXRange = QCPRange { m_DrawingZoomRect->topLeft->coords().x(), |
|
129 | auto newAxisXRange = QCPRange { m_DrawingZoomRect->topLeft->coords().x(), | |
133 | m_DrawingZoomRect->bottomRight->coords().x() }; |
|
130 | m_DrawingZoomRect->bottomRight->coords().x() }; | |
134 |
|
131 | |||
135 | auto newAxisYRange = QCPRange { m_DrawingZoomRect->topLeft->coords().y(), |
|
132 | auto newAxisYRange = QCPRange { m_DrawingZoomRect->topLeft->coords().y(), | |
136 | m_DrawingZoomRect->bottomRight->coords().y() }; |
|
133 | m_DrawingZoomRect->bottomRight->coords().y() }; | |
137 |
|
134 | |||
138 | removeDrawingRect(); |
|
135 | removeDrawingRect(); | |
139 |
|
136 | |||
140 | if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0) |
|
137 | if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0) | |
141 | && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) |
|
138 | && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) | |
142 | { |
|
139 | { | |
143 | m_ZoomStack.push(qMakePair(axisX->range(), axisY->range())); |
|
140 | m_ZoomStack.push(qMakePair(axisX->range(), axisY->range())); | |
144 | axisX->setRange(newAxisXRange); |
|
141 | axisX->setRange(newAxisXRange); | |
145 | axisY->setRange(newAxisYRange); |
|
142 | axisY->setRange(newAxisYRange); | |
146 |
|
143 | |||
147 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
144 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
148 | } |
|
145 | } | |
149 | } |
|
146 | } | |
150 |
|
147 | |||
151 | inline bool isDrawingZoneRect() { return m_DrawingZone != nullptr; } |
|
148 | inline bool isDrawingZoneRect() { return m_DrawingZone != nullptr; } | |
152 | void updateZoneRect(const QPoint& newPos) |
|
149 | void updateZoneRect(const QPoint& newPos) | |
153 | { |
|
150 | { | |
154 | m_DrawingZone->setEnd(m_plot->xAxis->pixelToCoord(newPos.x())); |
|
151 | m_DrawingZone->setEnd(m_plot->xAxis->pixelToCoord(newPos.x())); | |
155 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
152 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
156 | } |
|
153 | } | |
157 |
|
154 | |||
158 | void startDrawingRect(const QPoint& pos) |
|
155 | void startDrawingRect(const QPoint& pos) | |
159 | { |
|
156 | { | |
160 | removeDrawingRect(); |
|
157 | removeDrawingRect(); | |
161 |
|
158 | |||
162 | auto axisPos = posToAxisPos(pos); |
|
159 | auto axisPos = posToAxisPos(pos); | |
163 |
|
160 | |||
164 | m_DrawingZoomRect = new QCPItemRect { m_plot }; |
|
161 | m_DrawingZoomRect = new QCPItemRect { m_plot }; | |
165 | QPen p; |
|
162 | QPen p; | |
166 | p.setWidth(2); |
|
163 | p.setWidth(2); | |
167 | m_DrawingZoomRect->setPen(p); |
|
164 | m_DrawingZoomRect->setPen(p); | |
168 |
|
165 | |||
169 | m_DrawingZoomRect->topLeft->setCoords(axisPos); |
|
166 | m_DrawingZoomRect->topLeft->setCoords(axisPos); | |
170 | m_DrawingZoomRect->bottomRight->setCoords(axisPos); |
|
167 | m_DrawingZoomRect->bottomRight->setCoords(axisPos); | |
171 | } |
|
168 | } | |
172 |
|
169 | |||
173 | void removeDrawingRect() |
|
170 | void removeDrawingRect() | |
174 | { |
|
171 | { | |
175 | if (m_DrawingZoomRect) |
|
172 | if (m_DrawingZoomRect) | |
176 | { |
|
173 | { | |
177 | m_plot->removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot |
|
174 | m_plot->removeItem(m_DrawingZoomRect); // the item is deleted by QCustomPlot | |
178 | m_DrawingZoomRect = nullptr; |
|
175 | m_DrawingZoomRect = nullptr; | |
179 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
176 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
180 | } |
|
177 | } | |
181 | } |
|
178 | } | |
182 |
|
179 | |||
183 | void selectZone(const QPoint& pos) |
|
180 | void selectZone(const QPoint& pos) | |
184 | { |
|
181 | { | |
185 | auto zoneAtPos = selectionZoneAt(pos); |
|
182 | auto zoneAtPos = selectionZoneAt(pos); | |
186 | setSelectionZonesEditionEnabled( |
|
183 | setSelectionZonesEditionEnabled( | |
187 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones); |
|
184 | sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones); | |
188 | } |
|
185 | } | |
189 |
|
186 | |||
190 | void startDrawingZone(const QPoint& pos) |
|
187 | void startDrawingZone(const QPoint& pos) | |
191 | { |
|
188 | { | |
192 | endDrawingZone(); |
|
189 | endDrawingZone(); | |
193 |
|
190 | |||
194 | auto axisPos = posToAxisPos(pos); |
|
191 | auto axisPos = posToAxisPos(pos); | |
195 |
|
192 | |||
196 | m_DrawingZone = new VisualizationSelectionZoneItem { m_plot }; |
|
193 | m_DrawingZone = new VisualizationSelectionZoneItem { m_plot }; | |
197 | m_DrawingZone->setRange(axisPos.x(), axisPos.x()); |
|
194 | m_DrawingZone->setRange(axisPos.x(), axisPos.x()); | |
198 | m_DrawingZone->setEditionEnabled(false); |
|
195 | m_DrawingZone->setEditionEnabled(false); | |
199 | } |
|
196 | } | |
200 |
|
197 | |||
201 | void endDrawingZone() |
|
198 | void endDrawingZone() | |
202 | { |
|
199 | { | |
203 | if (m_DrawingZone) |
|
200 | if (m_DrawingZone) | |
204 | { |
|
201 | { | |
205 | auto drawingZoneRange = m_DrawingZone->range(); |
|
202 | auto drawingZoneRange = m_DrawingZone->range(); | |
206 | if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) |
|
203 | if (qAbs(drawingZoneRange.m_TEnd - drawingZoneRange.m_TStart) > 0) | |
207 | { |
|
204 | { | |
208 | m_DrawingZone->setEditionEnabled(true); |
|
205 | m_DrawingZone->setEditionEnabled(true); | |
209 | addSelectionZone(m_DrawingZone); |
|
206 | addSelectionZone(m_DrawingZone); | |
210 | } |
|
207 | } | |
211 | else |
|
208 | else | |
212 | { |
|
209 | { | |
213 | m_plot->removeItem(m_DrawingZone); |
|
210 | m_plot->removeItem(m_DrawingZone); | |
214 | } |
|
211 | } | |
215 |
|
212 | |||
216 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
213 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
217 | m_DrawingZone = nullptr; |
|
214 | m_DrawingZone = nullptr; | |
218 | } |
|
215 | } | |
219 | } |
|
216 | } | |
220 |
|
217 | |||
221 | void moveSelectionZone(const QPoint& destination) |
|
218 | void moveSelectionZone(const QPoint& destination) | |
222 | { |
|
219 | { | |
223 | /* |
|
220 | /* | |
224 | * I give up on this for now |
|
221 | * I give up on this for now | |
225 | * @TODO implement this, the difficulty is that selection zones have their own |
|
222 | * @TODO implement this, the difficulty is that selection zones have their own | |
226 | * event handling code which seems to rely on QCP GUI event handling propagation |
|
223 | * event handling code which seems to rely on QCP GUI event handling propagation | |
227 | * which was a realy bad design choice. |
|
224 | * which was a realy bad design choice. | |
228 | */ |
|
225 | */ | |
229 | } |
|
226 | } | |
230 |
|
227 | |||
231 | void setSelectionZonesEditionEnabled(bool value) |
|
228 | void setSelectionZonesEditionEnabled(bool value) | |
232 | { |
|
229 | { | |
233 | for (auto s : m_SelectionZones) |
|
230 | for (auto s : m_SelectionZones) | |
234 | { |
|
231 | { | |
235 | s->setEditionEnabled(value); |
|
232 | s->setEditionEnabled(value); | |
236 | } |
|
233 | } | |
237 | } |
|
234 | } | |
238 |
|
235 | |||
239 | void addSelectionZone(VisualizationSelectionZoneItem* zone) { m_SelectionZones << zone; } |
|
236 | void addSelectionZone(VisualizationSelectionZoneItem* zone) { m_SelectionZones << zone; } | |
240 |
|
237 | |||
241 | VisualizationSelectionZoneItem* selectionZoneAt(const QPoint& pos) const |
|
238 | VisualizationSelectionZoneItem* selectionZoneAt(const QPoint& pos) const | |
242 | { |
|
239 | { | |
243 | VisualizationSelectionZoneItem* selectionZoneItemUnderCursor = nullptr; |
|
240 | VisualizationSelectionZoneItem* selectionZoneItemUnderCursor = nullptr; | |
244 | auto minDistanceToZone = -1; |
|
241 | auto minDistanceToZone = -1; | |
245 | for (auto zone : m_SelectionZones) |
|
242 | for (auto zone : m_SelectionZones) | |
246 | { |
|
243 | { | |
247 | auto distanceToZone = zone->selectTest(pos, false); |
|
244 | auto distanceToZone = zone->selectTest(pos, false); | |
248 | if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone) |
|
245 | if ((minDistanceToZone < 0 || distanceToZone <= minDistanceToZone) | |
249 | && distanceToZone >= 0 && distanceToZone < m_plot->selectionTolerance()) |
|
246 | && distanceToZone >= 0 && distanceToZone < m_plot->selectionTolerance()) | |
250 | { |
|
247 | { | |
251 | selectionZoneItemUnderCursor = zone; |
|
248 | selectionZoneItemUnderCursor = zone; | |
252 | } |
|
249 | } | |
253 | } |
|
250 | } | |
254 |
|
251 | |||
255 | return selectionZoneItemUnderCursor; |
|
252 | return selectionZoneItemUnderCursor; | |
256 | } |
|
253 | } | |
257 |
|
254 | |||
258 | QVector<VisualizationSelectionZoneItem*> selectionZonesAt( |
|
255 | QVector<VisualizationSelectionZoneItem*> selectionZonesAt( | |
259 | const QPoint& pos, const QCustomPlot& plot) const |
|
256 | const QPoint& pos, const QCustomPlot& plot) const | |
260 | { |
|
257 | { | |
261 | QVector<VisualizationSelectionZoneItem*> zones; |
|
258 | QVector<VisualizationSelectionZoneItem*> zones; | |
262 | for (auto zone : m_SelectionZones) |
|
259 | for (auto zone : m_SelectionZones) | |
263 | { |
|
260 | { | |
264 | auto distanceToZone = zone->selectTest(pos, false); |
|
261 | auto distanceToZone = zone->selectTest(pos, false); | |
265 | if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) |
|
262 | if (distanceToZone >= 0 && distanceToZone < plot.selectionTolerance()) | |
266 | { |
|
263 | { | |
267 | zones << zone; |
|
264 | zones << zone; | |
268 | } |
|
265 | } | |
269 | } |
|
266 | } | |
270 |
|
267 | |||
271 | return zones; |
|
268 | return zones; | |
272 | } |
|
269 | } | |
273 |
|
270 | |||
274 | void moveSelectionZoneOnTop(VisualizationSelectionZoneItem* zone, QCustomPlot& plot) |
|
271 | void moveSelectionZoneOnTop(VisualizationSelectionZoneItem* zone, QCustomPlot& plot) | |
275 | { |
|
272 | { | |
276 | if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) |
|
273 | if (!m_SelectionZones.isEmpty() && m_SelectionZones.last() != zone) | |
277 | { |
|
274 | { | |
278 | zone->moveToTop(); |
|
275 | zone->moveToTop(); | |
279 | m_SelectionZones.removeAll(zone); |
|
276 | m_SelectionZones.removeAll(zone); | |
280 | m_SelectionZones.append(zone); |
|
277 | m_SelectionZones.append(zone); | |
281 | } |
|
278 | } | |
282 | } |
|
279 | } | |
283 |
|
280 | |||
284 | QPointF posToAxisPos(const QPoint& pos) const |
|
281 | QPointF posToAxisPos(const QPoint& pos) const | |
285 | { |
|
282 | { | |
286 | auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom); |
|
283 | auto axisX = m_plot->axisRect()->axis(QCPAxis::atBottom); | |
287 | auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft); |
|
284 | auto axisY = m_plot->axisRect()->axis(QCPAxis::atLeft); | |
288 | return QPointF { axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y()) }; |
|
285 | return QPointF { axisX->pixelToCoord(pos.x()), axisY->pixelToCoord(pos.y()) }; | |
289 | } |
|
286 | } | |
290 |
|
287 | |||
291 | bool pointIsInAxisRect(const QPointF& axisPoint, QCustomPlot& plot) const |
|
288 | bool pointIsInAxisRect(const QPointF& axisPoint, QCustomPlot& plot) const | |
292 | { |
|
289 | { | |
293 | auto axisX = plot.axisRect()->axis(QCPAxis::atBottom); |
|
290 | auto axisX = plot.axisRect()->axis(QCPAxis::atBottom); | |
294 | auto axisY = plot.axisRect()->axis(QCPAxis::atLeft); |
|
291 | auto axisY = plot.axisRect()->axis(QCPAxis::atLeft); | |
295 | return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y()); |
|
292 | return axisX->range().contains(axisPoint.x()) && axisY->range().contains(axisPoint.y()); | |
296 | } |
|
293 | } | |
297 |
|
294 | |||
298 | inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis* axis) |
|
295 | inline QCPRange _pixDistanceToRange(double pos1, double pos2, QCPAxis* axis) | |
299 | { |
|
296 | { | |
300 | if (axis->scaleType() == QCPAxis::stLinear) |
|
297 | if (axis->scaleType() == QCPAxis::stLinear) | |
301 | { |
|
298 | { | |
302 | auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2); |
|
299 | auto diff = axis->pixelToCoord(pos1) - axis->pixelToCoord(pos2); | |
303 | return QCPRange { axis->range().lower + diff, axis->range().upper + diff }; |
|
300 | return QCPRange { axis->range().lower + diff, axis->range().upper + diff }; | |
304 | } |
|
301 | } | |
305 | else |
|
302 | else | |
306 | { |
|
303 | { | |
307 | auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2); |
|
304 | auto diff = axis->pixelToCoord(pos1) / axis->pixelToCoord(pos2); | |
308 | return QCPRange { axis->range().lower * diff, axis->range().upper * diff }; |
|
305 | return QCPRange { axis->range().lower * diff, axis->range().upper * diff }; | |
309 | } |
|
306 | } | |
310 | } |
|
307 | } | |
311 |
|
308 | |||
312 | void setRange(const DateTimeRange& newRange, bool updateVar = true) |
|
309 | void setRange(const DateTimeRange& newRange, bool updateVar = true) | |
313 | { |
|
310 | { | |
314 | this->m_plot->xAxis->setRange(newRange.m_TStart, newRange.m_TEnd); |
|
311 | this->m_plot->xAxis->setRange(newRange.m_TStart, newRange.m_TEnd); | |
315 | if (updateVar) |
|
312 | if (updateVar) | |
316 | { |
|
313 | { | |
317 | for (auto it = m_VariableToPlotMultiMap.begin(), end = m_VariableToPlotMultiMap.end(); |
|
314 | for (auto it = m_VariableToPlotMultiMap.begin(), end = m_VariableToPlotMultiMap.end(); | |
318 | it != end; it = m_VariableToPlotMultiMap.upper_bound(it->first)) |
|
315 | it != end; it = m_VariableToPlotMultiMap.upper_bound(it->first)) | |
319 | { |
|
316 | { | |
320 | sqpApp->variableController().asyncChangeRange(it->first, newRange); |
|
317 | sqpApp->variableController().asyncChangeRange(it->first, newRange); | |
321 | } |
|
318 | } | |
322 | } |
|
319 | } | |
323 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
320 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
324 | } |
|
321 | } | |
325 |
|
322 | |||
326 | void setRange(const QCPRange& newRange) |
|
323 | void setRange(const QCPRange& newRange) | |
327 | { |
|
324 | { | |
328 | auto graphRange = DateTimeRange { newRange.lower, newRange.upper }; |
|
325 | auto graphRange = DateTimeRange { newRange.lower, newRange.upper }; | |
329 | setRange(graphRange); |
|
326 | setRange(graphRange); | |
330 | } |
|
327 | } | |
331 |
|
328 | |||
332 | void rescaleY() { m_plot->yAxis->rescale(true); } |
|
329 | void rescaleY() { m_plot->yAxis->rescale(true); } | |
333 |
|
330 | |||
334 | std::tuple<double, double> moveGraph(const QPoint& destination) |
|
331 | std::tuple<double, double> moveGraph(const QPoint& destination) | |
335 | { |
|
332 | { | |
336 | auto currentPos = m_plot->mapFromParent(destination); |
|
333 | auto currentPos = m_plot->mapFromParent(destination); | |
337 | auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal); |
|
334 | auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal); | |
338 | auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical); |
|
335 | auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical); | |
339 | auto oldXRange = xAxis->range(); |
|
336 | auto oldXRange = xAxis->range(); | |
340 | auto oldYRange = yAxis->range(); |
|
337 | auto oldYRange = yAxis->range(); | |
341 | double dx = xAxis->pixelToCoord(m_lastMousePos.x()) - xAxis->pixelToCoord(currentPos.x()); |
|
338 | double dx = xAxis->pixelToCoord(m_lastMousePos.x()) - xAxis->pixelToCoord(currentPos.x()); | |
342 | xAxis->setRange(m_lastXRange.lower + dx, m_lastXRange.upper + dx); |
|
339 | xAxis->setRange(m_lastXRange.lower + dx, m_lastXRange.upper + dx); | |
343 | if (yAxis->scaleType() == QCPAxis::stLinear) |
|
340 | if (yAxis->scaleType() == QCPAxis::stLinear) | |
344 | { |
|
341 | { | |
345 | double dy |
|
342 | double dy | |
346 | = yAxis->pixelToCoord(m_lastMousePos.y()) - yAxis->pixelToCoord(currentPos.y()); |
|
343 | = yAxis->pixelToCoord(m_lastMousePos.y()) - yAxis->pixelToCoord(currentPos.y()); | |
347 | yAxis->setRange(m_lastYRange.lower + dy, m_lastYRange.upper + dy); |
|
344 | yAxis->setRange(m_lastYRange.lower + dy, m_lastYRange.upper + dy); | |
348 | } |
|
345 | } | |
349 | else |
|
346 | else | |
350 | { |
|
347 | { | |
351 | double dy |
|
348 | double dy | |
352 | = yAxis->pixelToCoord(m_lastMousePos.y()) / yAxis->pixelToCoord(currentPos.y()); |
|
349 | = yAxis->pixelToCoord(m_lastMousePos.y()) / yAxis->pixelToCoord(currentPos.y()); | |
353 | yAxis->setRange(m_lastYRange.lower * dy, m_lastYRange.upper * dy); |
|
350 | yAxis->setRange(m_lastYRange.lower * dy, m_lastYRange.upper * dy); | |
354 | } |
|
351 | } | |
355 | auto newXRange = xAxis->range(); |
|
352 | auto newXRange = xAxis->range(); | |
356 | auto newYRange = yAxis->range(); |
|
353 | auto newYRange = yAxis->range(); | |
357 | setRange(xAxis->range()); |
|
354 | setRange(xAxis->range()); | |
358 | // m_lastMousePos = currentPos; |
|
355 | // m_lastMousePos = currentPos; | |
359 | return { newXRange.lower - oldXRange.lower, newYRange.lower - oldYRange.lower }; |
|
356 | return { newXRange.lower - oldXRange.lower, newYRange.lower - oldYRange.lower }; | |
360 | } |
|
357 | } | |
361 |
|
358 | |||
362 | void zoom(double factor, int center, Qt::Orientation orientation) |
|
359 | void zoom(double factor, int center, Qt::Orientation orientation) | |
363 | { |
|
360 | { | |
364 | QCPAxis* axis = m_plot->axisRect()->rangeZoomAxis(orientation); |
|
361 | QCPAxis* axis = m_plot->axisRect()->rangeZoomAxis(orientation); | |
365 | axis->scaleRange(factor, axis->pixelToCoord(center)); |
|
362 | axis->scaleRange(factor, axis->pixelToCoord(center)); | |
366 | if (orientation == Qt::Horizontal) |
|
363 | if (orientation == Qt::Horizontal) | |
367 | setRange(axis->range()); |
|
364 | setRange(axis->range()); | |
368 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
365 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
369 | } |
|
366 | } | |
370 |
|
367 | |||
371 | void transform(const DateTimeRangeTransformation& tranformation) |
|
368 | void transform(const DateTimeRangeTransformation& tranformation) | |
372 | { |
|
369 | { | |
373 | auto graphRange = m_plot->xAxis->range(); |
|
370 | auto graphRange = m_plot->xAxis->range(); | |
374 | DateTimeRange range { graphRange.lower, graphRange.upper }; |
|
371 | DateTimeRange range { graphRange.lower, graphRange.upper }; | |
375 | range = range.transform(tranformation); |
|
372 | range = range.transform(tranformation); | |
376 | setRange(range); |
|
373 | setRange(range); | |
377 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
374 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
378 | } |
|
375 | } | |
379 |
|
376 | |||
380 | void move(double dx, double dy) |
|
377 | void move(double dx, double dy) | |
381 | { |
|
378 | { | |
382 | auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal); |
|
379 | auto xAxis = m_plot->axisRect()->rangeDragAxis(Qt::Horizontal); | |
383 | auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical); |
|
380 | auto yAxis = m_plot->axisRect()->rangeDragAxis(Qt::Vertical); | |
384 | xAxis->setRange(QCPRange(xAxis->range().lower + dx, xAxis->range().upper + dx)); |
|
381 | xAxis->setRange(QCPRange(xAxis->range().lower + dx, xAxis->range().upper + dx)); | |
385 | yAxis->setRange(QCPRange(yAxis->range().lower + dy, yAxis->range().upper + dy)); |
|
382 | yAxis->setRange(QCPRange(yAxis->range().lower + dy, yAxis->range().upper + dy)); | |
386 | setRange(xAxis->range()); |
|
383 | setRange(xAxis->range()); | |
387 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
384 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
388 | } |
|
385 | } | |
389 |
|
386 | |||
390 | void move(double factor, Qt::Orientation orientation) |
|
387 | void move(double factor, Qt::Orientation orientation) | |
391 | { |
|
388 | { | |
392 | auto oldRange = m_plot->xAxis->range(); |
|
389 | auto oldRange = m_plot->xAxis->range(); | |
393 | QCPAxis* axis = m_plot->axisRect()->rangeDragAxis(orientation); |
|
390 | QCPAxis* axis = m_plot->axisRect()->rangeDragAxis(orientation); | |
394 | if (m_plot->xAxis->scaleType() == QCPAxis::stLinear) |
|
391 | if (m_plot->xAxis->scaleType() == QCPAxis::stLinear) | |
395 | { |
|
392 | { | |
396 | double rg = (axis->range().upper - axis->range().lower) * (factor / 10); |
|
393 | double rg = (axis->range().upper - axis->range().lower) * (factor / 10); | |
397 | axis->setRange(axis->range().lower + (rg), axis->range().upper + (rg)); |
|
394 | axis->setRange(axis->range().lower + (rg), axis->range().upper + (rg)); | |
398 | } |
|
395 | } | |
399 | else if (m_plot->xAxis->scaleType() == QCPAxis::stLogarithmic) |
|
396 | else if (m_plot->xAxis->scaleType() == QCPAxis::stLogarithmic) | |
400 | { |
|
397 | { | |
401 | int start = 0, stop = 0; |
|
398 | int start = 0, stop = 0; | |
402 | double diff = 0.; |
|
399 | double diff = 0.; | |
403 | if (factor > 0.0) |
|
400 | if (factor > 0.0) | |
404 | { |
|
401 | { | |
405 | stop = m_plot->width() * factor / 10; |
|
402 | stop = m_plot->width() * factor / 10; | |
406 | start = 2 * m_plot->width() * factor / 10; |
|
403 | start = 2 * m_plot->width() * factor / 10; | |
407 | } |
|
404 | } | |
408 | if (factor < 0.0) |
|
405 | if (factor < 0.0) | |
409 | { |
|
406 | { | |
410 | factor *= -1.0; |
|
407 | factor *= -1.0; | |
411 | start = m_plot->width() * factor / 10; |
|
408 | start = m_plot->width() * factor / 10; | |
412 | stop = 2 * m_plot->width() * factor / 10; |
|
409 | stop = 2 * m_plot->width() * factor / 10; | |
413 | } |
|
410 | } | |
414 | diff = axis->pixelToCoord(start) / axis->pixelToCoord(stop); |
|
411 | diff = axis->pixelToCoord(start) / axis->pixelToCoord(stop); | |
415 | axis->setRange(m_plot->axisRect()->rangeDragAxis(orientation)->range().lower * diff, |
|
412 | axis->setRange(m_plot->axisRect()->rangeDragAxis(orientation)->range().lower * diff, | |
416 | m_plot->axisRect()->rangeDragAxis(orientation)->range().upper * diff); |
|
413 | m_plot->axisRect()->rangeDragAxis(orientation)->range().upper * diff); | |
417 | } |
|
414 | } | |
418 | if (orientation == Qt::Horizontal) |
|
415 | if (orientation == Qt::Horizontal) | |
419 | setRange(axis->range()); |
|
416 | setRange(axis->range()); | |
420 | m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
417 | m_plot->replot(QCustomPlot::rpQueuedReplot); | |
421 | } |
|
418 | } | |
422 | }; |
|
419 | }; | |
423 |
|
420 | |||
424 | VisualizationGraphWidget::VisualizationGraphWidget(const QString& name, QWidget* parent) |
|
421 | VisualizationGraphWidget::VisualizationGraphWidget(const QString& name, QWidget* parent) | |
425 | : VisualizationDragWidget { parent } |
|
422 | : VisualizationDragWidget { parent } | |
426 | , ui { new Ui::VisualizationGraphWidget } |
|
423 | , ui { new Ui::VisualizationGraphWidget } | |
427 | , impl { spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name) } |
|
424 | , impl { spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name) } | |
428 | { |
|
425 | { | |
429 | ui->setupUi(this); |
|
426 | ui->setupUi(this); | |
430 | this->layout()->addWidget(impl->m_plot); |
|
427 | this->layout()->addWidget(impl->m_plot); | |
431 | // 'Close' options : widget is deleted when closed |
|
428 | // 'Close' options : widget is deleted when closed | |
432 | setAttribute(Qt::WA_DeleteOnClose); |
|
429 | setAttribute(Qt::WA_DeleteOnClose); | |
433 |
|
430 | |||
434 | // The delegate must be initialized after the ui as it uses the plot |
|
431 | // The delegate must be initialized after the ui as it uses the plot | |
435 | impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this); |
|
432 | impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this); | |
436 |
|
433 | |||
437 | // Init the cursors |
|
434 | // Init the cursors | |
438 | impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot()); |
|
435 | impl->m_HorizontalCursor = std::make_unique<VisualizationCursorItem>(&plot()); | |
439 | impl->m_HorizontalCursor->setOrientation(Qt::Horizontal); |
|
436 | impl->m_HorizontalCursor->setOrientation(Qt::Horizontal); | |
440 | impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot()); |
|
437 | impl->m_VerticalCursor = std::make_unique<VisualizationCursorItem>(&plot()); | |
441 | impl->m_VerticalCursor->setOrientation(Qt::Vertical); |
|
438 | impl->m_VerticalCursor->setOrientation(Qt::Vertical); | |
442 |
|
439 | |||
443 | this->setFocusPolicy(Qt::WheelFocus); |
|
440 | this->setFocusPolicy(Qt::WheelFocus); | |
444 | this->setMouseTracking(true); |
|
441 | this->setMouseTracking(true); | |
445 | impl->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents); |
|
442 | impl->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents); | |
446 | impl->m_plot->setContextMenuPolicy(Qt::CustomContextMenu); |
|
443 | impl->m_plot->setContextMenuPolicy(Qt::CustomContextMenu); | |
447 | impl->m_plot->setParent(this); |
|
444 | impl->m_plot->setParent(this); | |
448 |
|
445 | |||
449 | connect(&sqpApp->variableController(), &VariableController2::variableDeleted, this, |
|
446 | connect(&sqpApp->variableController(), &VariableController2::variableDeleted, this, | |
450 | &VisualizationGraphWidget::variableDeleted); |
|
447 | &VisualizationGraphWidget::variableDeleted); | |
451 | } |
|
448 | } | |
452 |
|
449 | |||
453 |
|
450 | |||
454 | VisualizationGraphWidget::~VisualizationGraphWidget() |
|
451 | VisualizationGraphWidget::~VisualizationGraphWidget() | |
455 | { |
|
452 | { | |
456 | delete ui; |
|
453 | delete ui; | |
457 | } |
|
454 | } | |
458 |
|
455 | |||
459 | VisualizationZoneWidget* VisualizationGraphWidget::parentZoneWidget() const noexcept |
|
456 | VisualizationZoneWidget* VisualizationGraphWidget::parentZoneWidget() const noexcept | |
460 | { |
|
457 | { | |
461 | auto parent = parentWidget(); |
|
458 | auto parent = parentWidget(); | |
462 | while (parent != nullptr && !qobject_cast<VisualizationZoneWidget*>(parent)) |
|
459 | while (parent != nullptr && !qobject_cast<VisualizationZoneWidget*>(parent)) | |
463 | { |
|
460 | { | |
464 | parent = parent->parentWidget(); |
|
461 | parent = parent->parentWidget(); | |
465 | } |
|
462 | } | |
466 |
|
463 | |||
467 | return qobject_cast<VisualizationZoneWidget*>(parent); |
|
464 | return qobject_cast<VisualizationZoneWidget*>(parent); | |
468 | } |
|
465 | } | |
469 |
|
466 | |||
470 | VisualizationWidget* VisualizationGraphWidget::parentVisualizationWidget() const |
|
467 | VisualizationWidget* VisualizationGraphWidget::parentVisualizationWidget() const | |
471 | { |
|
468 | { | |
472 | auto parent = parentWidget(); |
|
469 | auto parent = parentWidget(); | |
473 | while (parent != nullptr && !qobject_cast<VisualizationWidget*>(parent)) |
|
470 | while (parent != nullptr && !qobject_cast<VisualizationWidget*>(parent)) | |
474 | { |
|
471 | { | |
475 | parent = parent->parentWidget(); |
|
472 | parent = parent->parentWidget(); | |
476 | } |
|
473 | } | |
477 |
|
474 | |||
478 | return qobject_cast<VisualizationWidget*>(parent); |
|
475 | return qobject_cast<VisualizationWidget*>(parent); | |
479 | } |
|
476 | } | |
480 |
|
477 | |||
481 | void VisualizationGraphWidget::setFlags(GraphFlags flags) |
|
478 | void VisualizationGraphWidget::setFlags(GraphFlags flags) | |
482 | { |
|
479 | { | |
483 | impl->m_Flags = std::move(flags); |
|
480 | impl->m_Flags = std::move(flags); | |
484 | } |
|
481 | } | |
485 |
|
482 | |||
486 | void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable2> variable, DateTimeRange range) |
|
483 | void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable2> variable, DateTimeRange range) | |
487 | { |
|
484 | { | |
488 | // Uses delegate to create the qcpplot components according to the variable |
|
485 | // Uses delegate to create the qcpplot components according to the variable | |
489 | auto createdPlottables = VisualizationGraphHelper::create(variable, *impl->m_plot); |
|
486 | auto createdPlottables = VisualizationGraphHelper::create(variable, *impl->m_plot); | |
490 |
|
487 | |||
491 | // Sets graph properties |
|
488 | // Sets graph properties | |
492 | impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables); |
|
489 | impl->m_RenderingDelegate->setGraphProperties(*variable, createdPlottables); | |
493 |
|
490 | |||
494 | impl->m_VariableToPlotMultiMap.insert({ variable, std::move(createdPlottables) }); |
|
491 | impl->m_VariableToPlotMultiMap.insert({ variable, std::move(createdPlottables) }); | |
495 |
|
492 | |||
496 | setGraphRange(range); |
|
493 | setGraphRange(range); | |
497 | // If the variable already has its data loaded, load its units and its range in the graph |
|
494 | // If the variable already has its data loaded, load its units and its range in the graph | |
498 | if (variable->data() != nullptr) |
|
495 | if (variable->data() != nullptr) | |
499 | { |
|
496 | { | |
500 | impl->m_RenderingDelegate->setAxesUnits(*variable); |
|
497 | impl->m_RenderingDelegate->setAxesUnits(*variable); | |
501 | } |
|
498 | } | |
502 | else |
|
499 | else | |
503 | { |
|
500 | { | |
504 | auto context = new QObject { this }; |
|
501 | auto context = new QObject { this }; | |
505 | connect( |
|
502 | connect( | |
506 | variable.get(), &Variable2::updated, context, [this, variable, context, range](QUuid) { |
|
503 | variable.get(), &Variable2::updated, context, [this, variable, context, range](QUuid) { | |
507 | this->impl->m_RenderingDelegate->setAxesUnits(*variable); |
|
504 | this->impl->m_RenderingDelegate->setAxesUnits(*variable); | |
508 | this->impl->m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
505 | this->impl->m_plot->replot(QCustomPlot::rpQueuedReplot); | |
509 | delete context; |
|
506 | delete context; | |
510 | }); |
|
507 | }); | |
511 | } |
|
508 | } | |
512 | //@TODO this is bad! when variable is moved to another graph it still fires |
|
509 | //@TODO this is bad! when variable is moved to another graph it still fires | |
513 | // even if this has been deleted |
|
510 | // even if this has been deleted | |
514 | connect(variable.get(), &Variable2::updated, this, &VisualizationGraphWidget::variableUpdated); |
|
511 | connect(variable.get(), &Variable2::updated, this, &VisualizationGraphWidget::variableUpdated); | |
515 | this->onUpdateVarDisplaying(variable, range); // My bullshit |
|
512 | this->onUpdateVarDisplaying(variable, range); // My bullshit | |
516 | emit variableAdded(variable); |
|
513 | emit variableAdded(variable); | |
517 | } |
|
514 | } | |
518 |
|
515 | |||
519 | void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable2> variable) noexcept |
|
516 | void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable2> variable) noexcept | |
520 | { |
|
517 | { | |
521 | // Each component associated to the variable : |
|
518 | // Each component associated to the variable : | |
522 | // - is removed from qcpplot (which deletes it) |
|
519 | // - is removed from qcpplot (which deletes it) | |
523 | // - is no longer referenced in the map |
|
520 | // - is no longer referenced in the map | |
524 | auto variableIt = impl->m_VariableToPlotMultiMap.find(variable); |
|
521 | auto variableIt = impl->m_VariableToPlotMultiMap.find(variable); | |
525 | if (variableIt != impl->m_VariableToPlotMultiMap.cend()) |
|
522 | if (variableIt != impl->m_VariableToPlotMultiMap.cend()) | |
526 | { |
|
523 | { | |
527 | emit variableAboutToBeRemoved(variable); |
|
524 | emit variableAboutToBeRemoved(variable); | |
528 |
|
525 | |||
529 | auto& plottablesMap = variableIt->second; |
|
526 | auto& plottablesMap = variableIt->second; | |
530 |
|
527 | |||
531 | for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend(); |
|
528 | for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend(); | |
532 | plottableIt != plottableEnd;) |
|
529 | plottableIt != plottableEnd;) | |
533 | { |
|
530 | { | |
534 | impl->m_plot->removePlottable(plottableIt->second); |
|
531 | impl->m_plot->removePlottable(plottableIt->second); | |
535 | plottableIt = plottablesMap.erase(plottableIt); |
|
532 | plottableIt = plottablesMap.erase(plottableIt); | |
536 | } |
|
533 | } | |
537 |
|
534 | |||
538 | impl->m_VariableToPlotMultiMap.erase(variableIt); |
|
535 | impl->m_VariableToPlotMultiMap.erase(variableIt); | |
539 | } |
|
536 | } | |
540 |
|
537 | |||
541 | // Updates graph |
|
538 | // Updates graph | |
542 | impl->m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
539 | impl->m_plot->replot(QCustomPlot::rpQueuedReplot); | |
543 | } |
|
540 | } | |
544 |
|
541 | |||
545 | std::vector<std::shared_ptr<Variable2>> VisualizationGraphWidget::variables() const |
|
542 | std::vector<std::shared_ptr<Variable2>> VisualizationGraphWidget::variables() const | |
546 | { |
|
543 | { | |
547 | auto variables = std::vector<std::shared_ptr<Variable2>> {}; |
|
544 | auto variables = std::vector<std::shared_ptr<Variable2>> {}; | |
548 | for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap); |
|
545 | for (auto it = std::cbegin(impl->m_VariableToPlotMultiMap); | |
549 | it != std::cend(impl->m_VariableToPlotMultiMap); ++it) |
|
546 | it != std::cend(impl->m_VariableToPlotMultiMap); ++it) | |
550 | { |
|
547 | { | |
551 | variables.push_back(it->first); |
|
548 | variables.push_back(it->first); | |
552 | } |
|
549 | } | |
553 |
|
550 | |||
554 | return variables; |
|
551 | return variables; | |
555 | } |
|
552 | } | |
556 |
|
553 | |||
557 | void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable2> variable) |
|
554 | void VisualizationGraphWidget::setYRange(std::shared_ptr<Variable2> variable) | |
558 | { |
|
555 | { | |
559 | if (!variable) |
|
556 | if (!variable) | |
560 | { |
|
557 | { | |
561 | qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null"; |
|
558 | qCCritical(LOG_VisualizationGraphWidget()) << "Can't set y-axis range: variable is null"; | |
562 | return; |
|
559 | return; | |
563 | } |
|
560 | } | |
564 |
|
561 | |||
565 | VisualizationGraphHelper::setYAxisRange(variable, *impl->m_plot); |
|
562 | VisualizationGraphHelper::setYAxisRange(variable, *impl->m_plot); | |
566 | } |
|
563 | } | |
567 |
|
564 | |||
568 | DateTimeRange VisualizationGraphWidget::graphRange() const noexcept |
|
565 | DateTimeRange VisualizationGraphWidget::graphRange() const noexcept | |
569 | { |
|
566 | { | |
570 | auto graphRange = impl->m_plot->xAxis->range(); |
|
567 | auto graphRange = impl->m_plot->xAxis->range(); | |
571 | return DateTimeRange { graphRange.lower, graphRange.upper }; |
|
568 | return DateTimeRange { graphRange.lower, graphRange.upper }; | |
572 | } |
|
569 | } | |
573 |
|
570 | |||
574 | void VisualizationGraphWidget::setGraphRange( |
|
571 | void VisualizationGraphWidget::setGraphRange( | |
575 | const DateTimeRange& range, bool updateVar, bool forward) |
|
572 | const DateTimeRange& range, bool updateVar, bool forward) | |
576 | { |
|
573 | { | |
577 | impl->setRange(range, updateVar); |
|
574 | impl->setRange(range, updateVar); | |
578 | if (forward) |
|
575 | if (forward) | |
579 | { |
|
576 | { | |
580 | emit this->setrange_sig(this->graphRange(), true, false); |
|
577 | emit this->setrange_sig(this->graphRange(), true, false); | |
581 | } |
|
578 | } | |
582 | } |
|
579 | } | |
583 |
|
580 | |||
584 | void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value) |
|
581 | void VisualizationGraphWidget::setAutoRangeOnVariableInitialization(bool value) | |
585 | { |
|
582 | { | |
586 | impl->m_VariableAutoRangeOnInit = value; |
|
583 | impl->m_VariableAutoRangeOnInit = value; | |
587 | } |
|
584 | } | |
588 |
|
585 | |||
589 | QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const |
|
586 | QVector<DateTimeRange> VisualizationGraphWidget::selectionZoneRanges() const | |
590 | { |
|
587 | { | |
591 | QVector<DateTimeRange> ranges; |
|
588 | QVector<DateTimeRange> ranges; | |
592 | for (auto zone : impl->m_SelectionZones) |
|
589 | for (auto zone : impl->m_SelectionZones) | |
593 | { |
|
590 | { | |
594 | ranges << zone->range(); |
|
591 | ranges << zone->range(); | |
595 | } |
|
592 | } | |
596 |
|
593 | |||
597 | return ranges; |
|
594 | return ranges; | |
598 | } |
|
595 | } | |
599 |
|
596 | |||
600 | void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange>& ranges) |
|
597 | void VisualizationGraphWidget::addSelectionZones(const QVector<DateTimeRange>& ranges) | |
601 | { |
|
598 | { | |
602 | for (const auto& range : ranges) |
|
599 | for (const auto& range : ranges) | |
603 | { |
|
600 | { | |
604 | // note: ownership is transfered to QCustomPlot |
|
601 | // note: ownership is transfered to QCustomPlot | |
605 | auto zone = new VisualizationSelectionZoneItem(&plot()); |
|
602 | auto zone = new VisualizationSelectionZoneItem(&plot()); | |
606 | zone->setRange(range.m_TStart, range.m_TEnd); |
|
603 | zone->setRange(range.m_TStart, range.m_TEnd); | |
607 | impl->addSelectionZone(zone); |
|
604 | impl->addSelectionZone(zone); | |
608 | } |
|
605 | } | |
609 |
|
606 | |||
610 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
607 | plot().replot(QCustomPlot::rpQueuedReplot); | |
611 | } |
|
608 | } | |
612 |
|
609 | |||
613 | VisualizationSelectionZoneItem* VisualizationGraphWidget::addSelectionZone( |
|
610 | VisualizationSelectionZoneItem* VisualizationGraphWidget::addSelectionZone( | |
614 | const QString& name, const DateTimeRange& range) |
|
611 | const QString& name, const DateTimeRange& range) | |
615 | { |
|
612 | { | |
616 | // note: ownership is transfered to QCustomPlot |
|
613 | // note: ownership is transfered to QCustomPlot | |
617 | auto zone = new VisualizationSelectionZoneItem(&plot()); |
|
614 | auto zone = new VisualizationSelectionZoneItem(&plot()); | |
618 | zone->setName(name); |
|
615 | zone->setName(name); | |
619 | zone->setRange(range.m_TStart, range.m_TEnd); |
|
616 | zone->setRange(range.m_TStart, range.m_TEnd); | |
620 | impl->addSelectionZone(zone); |
|
617 | impl->addSelectionZone(zone); | |
621 |
|
618 | |||
622 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
619 | plot().replot(QCustomPlot::rpQueuedReplot); | |
623 |
|
620 | |||
624 | return zone; |
|
621 | return zone; | |
625 | } |
|
622 | } | |
626 |
|
623 | |||
627 | void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem* selectionZone) |
|
624 | void VisualizationGraphWidget::removeSelectionZone(VisualizationSelectionZoneItem* selectionZone) | |
628 | { |
|
625 | { | |
629 | parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false); |
|
626 | parentVisualizationWidget()->selectionZoneManager().setSelected(selectionZone, false); | |
630 |
|
627 | |||
631 | if (impl->m_HoveredZone == selectionZone) |
|
628 | if (impl->m_HoveredZone == selectionZone) | |
632 | { |
|
629 | { | |
633 | impl->m_HoveredZone = nullptr; |
|
630 | impl->m_HoveredZone = nullptr; | |
634 | setCursor(Qt::ArrowCursor); |
|
631 | setCursor(Qt::ArrowCursor); | |
635 | } |
|
632 | } | |
636 |
|
633 | |||
637 | impl->m_SelectionZones.removeAll(selectionZone); |
|
634 | impl->m_SelectionZones.removeAll(selectionZone); | |
638 | plot().removeItem(selectionZone); |
|
635 | plot().removeItem(selectionZone); | |
639 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
636 | plot().replot(QCustomPlot::rpQueuedReplot); | |
640 | } |
|
637 | } | |
641 |
|
638 | |||
642 | void VisualizationGraphWidget::undoZoom() |
|
639 | void VisualizationGraphWidget::undoZoom() | |
643 | { |
|
640 | { | |
644 | auto zoom = impl->m_ZoomStack.pop(); |
|
641 | auto zoom = impl->m_ZoomStack.pop(); | |
645 | auto axisX = plot().axisRect()->axis(QCPAxis::atBottom); |
|
642 | auto axisX = plot().axisRect()->axis(QCPAxis::atBottom); | |
646 | auto axisY = plot().axisRect()->axis(QCPAxis::atLeft); |
|
643 | auto axisY = plot().axisRect()->axis(QCPAxis::atLeft); | |
647 |
|
644 | |||
648 | axisX->setRange(zoom.first); |
|
645 | axisX->setRange(zoom.first); | |
649 | axisY->setRange(zoom.second); |
|
646 | axisY->setRange(zoom.second); | |
650 |
|
647 | |||
651 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
648 | plot().replot(QCustomPlot::rpQueuedReplot); | |
652 | } |
|
649 | } | |
653 |
|
650 | |||
654 | void VisualizationGraphWidget::zoom( |
|
651 | void VisualizationGraphWidget::zoom( | |
655 | double factor, int center, Qt::Orientation orientation, bool forward) |
|
652 | double factor, int center, Qt::Orientation orientation, bool forward) | |
656 | { |
|
653 | { | |
657 | impl->zoom(factor, center, orientation); |
|
654 | impl->zoom(factor, center, orientation); | |
658 | if (forward && orientation == Qt::Horizontal) |
|
655 | if (forward && orientation == Qt::Horizontal) | |
659 | emit this->setrange_sig(this->graphRange(), true, false); |
|
656 | emit this->setrange_sig(this->graphRange(), true, false); | |
660 | } |
|
657 | } | |
661 |
|
658 | |||
662 | void VisualizationGraphWidget::move(double factor, Qt::Orientation orientation, bool forward) |
|
659 | void VisualizationGraphWidget::move(double factor, Qt::Orientation orientation, bool forward) | |
663 | { |
|
660 | { | |
664 | impl->move(factor, orientation); |
|
661 | impl->move(factor, orientation); | |
665 | if (forward) |
|
662 | if (forward) | |
666 | emit this->setrange_sig(this->graphRange(), true, false); |
|
663 | emit this->setrange_sig(this->graphRange(), true, false); | |
667 | } |
|
664 | } | |
668 |
|
665 | |||
669 | void VisualizationGraphWidget::move(double dx, double dy, bool forward) |
|
666 | void VisualizationGraphWidget::move(double dx, double dy, bool forward) | |
670 | { |
|
667 | { | |
671 | impl->move(dx, dy); |
|
668 | impl->move(dx, dy); | |
672 | if (forward) |
|
669 | if (forward) | |
673 | emit this->setrange_sig(this->graphRange(), true, false); |
|
670 | emit this->setrange_sig(this->graphRange(), true, false); | |
674 | } |
|
671 | } | |
675 |
|
672 | |||
676 | void VisualizationGraphWidget::transform( |
|
673 | void VisualizationGraphWidget::transform( | |
677 | const DateTimeRangeTransformation& tranformation, bool forward) |
|
674 | const DateTimeRangeTransformation& tranformation, bool forward) | |
678 | { |
|
675 | { | |
679 | impl->transform(tranformation); |
|
676 | impl->transform(tranformation); | |
680 | if (forward) |
|
677 | if (forward) | |
681 | emit this->setrange_sig(this->graphRange(), true, false); |
|
678 | emit this->setrange_sig(this->graphRange(), true, false); | |
682 | } |
|
679 | } | |
683 |
|
680 | |||
684 | void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor* visitor) |
|
681 | void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor* visitor) | |
685 | { |
|
682 | { | |
686 | if (visitor) |
|
683 | if (visitor) | |
687 | { |
|
684 | { | |
688 | visitor->visit(this); |
|
685 | visitor->visit(this); | |
689 | } |
|
686 | } | |
690 | else |
|
687 | else | |
691 | { |
|
688 | { | |
692 | qCCritical(LOG_VisualizationGraphWidget()) |
|
689 | qCCritical(LOG_VisualizationGraphWidget()) | |
693 | << tr("Can't visit widget : the visitor is null"); |
|
690 | << tr("Can't visit widget : the visitor is null"); | |
694 | } |
|
691 | } | |
695 | } |
|
692 | } | |
696 |
|
693 | |||
697 | bool VisualizationGraphWidget::canDrop(Variable2& variable) const |
|
694 | bool VisualizationGraphWidget::canDrop(Variable2& variable) const | |
698 | { |
|
695 | { | |
699 | auto isSpectrogram |
|
696 | auto isSpectrogram | |
700 | = [](auto& variable) { return variable.type() == DataSeriesType::SPECTROGRAM; }; |
|
697 | = [](auto& variable) { return variable.type() == DataSeriesType::SPECTROGRAM; }; | |
701 |
|
698 | |||
702 | // - A spectrogram series can't be dropped on graph with existing plottables |
|
699 | // - A spectrogram series can't be dropped on graph with existing plottables | |
703 | // - No data series can be dropped on graph with existing spectrogram series |
|
700 | // - No data series can be dropped on graph with existing spectrogram series | |
704 | return isSpectrogram(variable) |
|
701 | return isSpectrogram(variable) | |
705 | ? impl->m_VariableToPlotMultiMap.empty() |
|
702 | ? impl->m_VariableToPlotMultiMap.empty() | |
706 | : std::none_of(impl->m_VariableToPlotMultiMap.cbegin(), |
|
703 | : std::none_of(impl->m_VariableToPlotMultiMap.cbegin(), | |
707 | impl->m_VariableToPlotMultiMap.cend(), |
|
704 | impl->m_VariableToPlotMultiMap.cend(), | |
708 | [isSpectrogram](const auto& entry) { return isSpectrogram(*entry.first); }); |
|
705 | [isSpectrogram](const auto& entry) { return isSpectrogram(*entry.first); }); | |
709 | } |
|
706 | } | |
710 |
|
707 | |||
711 | bool VisualizationGraphWidget::contains(Variable2& variable) const |
|
708 | bool VisualizationGraphWidget::contains(Variable2& variable) const | |
712 | { |
|
709 | { | |
713 | // Finds the variable among the keys of the map |
|
710 | // Finds the variable among the keys of the map | |
714 | auto variablePtr = &variable; |
|
711 | auto variablePtr = &variable; | |
715 | auto findVariable |
|
712 | auto findVariable | |
716 | = [variablePtr](const auto& entry) { return variablePtr == entry.first.get(); }; |
|
713 | = [variablePtr](const auto& entry) { return variablePtr == entry.first.get(); }; | |
717 |
|
714 | |||
718 | auto end = impl->m_VariableToPlotMultiMap.cend(); |
|
715 | auto end = impl->m_VariableToPlotMultiMap.cend(); | |
719 | auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable); |
|
716 | auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable); | |
720 | return it != end; |
|
717 | return it != end; | |
721 | } |
|
718 | } | |
722 |
|
719 | |||
723 | QString VisualizationGraphWidget::name() const |
|
720 | QString VisualizationGraphWidget::name() const | |
724 | { |
|
721 | { | |
725 | return impl->m_Name; |
|
722 | return impl->m_Name; | |
726 | } |
|
723 | } | |
727 |
|
724 | |||
728 | QMimeData* VisualizationGraphWidget::mimeData(const QPoint& position) const |
|
725 | QMimeData* VisualizationGraphWidget::mimeData(const QPoint& position) const | |
729 | { |
|
726 | { | |
730 | auto mimeData = new QMimeData; |
|
727 | auto mimeData = new QMimeData; | |
731 |
|
728 | |||
732 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position); |
|
729 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(position); | |
733 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones |
|
730 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones | |
734 | && selectionZoneItemUnderCursor) |
|
731 | && selectionZoneItemUnderCursor) | |
735 | { |
|
732 | { | |
736 | mimeData->setData(MIME_TYPE_TIME_RANGE, |
|
733 | mimeData->setData(MIME_TYPE_TIME_RANGE, | |
737 | TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range())); |
|
734 | TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range())); | |
738 | mimeData->setData(MIME_TYPE_SELECTION_ZONE, |
|
735 | mimeData->setData(MIME_TYPE_SELECTION_ZONE, | |
739 | TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range())); |
|
736 | TimeController::mimeDataForTimeRange(selectionZoneItemUnderCursor->range())); | |
740 | } |
|
737 | } | |
741 | else |
|
738 | else | |
742 | { |
|
739 | { | |
743 | mimeData->setData(MIME_TYPE_GRAPH, QByteArray {}); |
|
740 | mimeData->setData(MIME_TYPE_GRAPH, QByteArray {}); | |
744 |
|
741 | |||
745 | auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange()); |
|
742 | auto timeRangeData = TimeController::mimeDataForTimeRange(graphRange()); | |
746 | mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData); |
|
743 | mimeData->setData(MIME_TYPE_TIME_RANGE, timeRangeData); | |
747 | } |
|
744 | } | |
748 |
|
745 | |||
749 | return mimeData; |
|
746 | return mimeData; | |
750 | } |
|
747 | } | |
751 |
|
748 | |||
752 | QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint& dragPosition) |
|
749 | QPixmap VisualizationGraphWidget::customDragPixmap(const QPoint& dragPosition) | |
753 | { |
|
750 | { | |
754 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition); |
|
751 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(dragPosition); | |
755 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones |
|
752 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones | |
756 | && selectionZoneItemUnderCursor) |
|
753 | && selectionZoneItemUnderCursor) | |
757 | { |
|
754 | { | |
758 |
|
755 | |||
759 | auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition(); |
|
756 | auto zoneTopLeft = selectionZoneItemUnderCursor->topLeft->pixelPosition(); | |
760 | auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition(); |
|
757 | auto zoneBottomRight = selectionZoneItemUnderCursor->bottomRight->pixelPosition(); | |
761 |
|
758 | |||
762 | auto zoneSize = QSizeF { qAbs(zoneBottomRight.x() - zoneTopLeft.x()), |
|
759 | auto zoneSize = QSizeF { qAbs(zoneBottomRight.x() - zoneTopLeft.x()), | |
763 | qAbs(zoneBottomRight.y() - zoneTopLeft.y()) } |
|
760 | qAbs(zoneBottomRight.y() - zoneTopLeft.y()) } | |
764 | .toSize(); |
|
761 | .toSize(); | |
765 |
|
762 | |||
766 | auto pixmap = QPixmap(zoneSize); |
|
763 | auto pixmap = QPixmap(zoneSize); | |
767 | render(&pixmap, QPoint(), QRegion { QRect { zoneTopLeft.toPoint(), zoneSize } }); |
|
764 | render(&pixmap, QPoint(), QRegion { QRect { zoneTopLeft.toPoint(), zoneSize } }); | |
768 |
|
765 | |||
769 | return pixmap; |
|
766 | return pixmap; | |
770 | } |
|
767 | } | |
771 |
|
768 | |||
772 | return QPixmap(); |
|
769 | return QPixmap(); | |
773 | } |
|
770 | } | |
774 |
|
771 | |||
775 | bool VisualizationGraphWidget::isDragAllowed() const |
|
772 | bool VisualizationGraphWidget::isDragAllowed() const | |
776 | { |
|
773 | { | |
777 | return true; |
|
774 | return true; | |
778 | } |
|
775 | } | |
779 |
|
776 | |||
780 | void VisualizationGraphWidget::highlightForMerge(bool highlighted) |
|
777 | void VisualizationGraphWidget::highlightForMerge(bool highlighted) | |
781 | { |
|
778 | { | |
782 | if (highlighted) |
|
779 | if (highlighted) | |
783 | { |
|
780 | { | |
784 | plot().setBackground(QBrush(QColor("#BBD5EE"))); |
|
781 | plot().setBackground(QBrush(QColor("#BBD5EE"))); | |
785 | } |
|
782 | } | |
786 | else |
|
783 | else | |
787 | { |
|
784 | { | |
788 | plot().setBackground(QBrush(Qt::white)); |
|
785 | plot().setBackground(QBrush(Qt::white)); | |
789 | } |
|
786 | } | |
790 |
|
787 | |||
791 | plot().update(); |
|
788 | plot().update(); | |
792 | } |
|
789 | } | |
793 |
|
790 | |||
794 | void VisualizationGraphWidget::addVerticalCursor(double time) |
|
791 | void VisualizationGraphWidget::addVerticalCursor(double time) | |
795 | { |
|
792 | { | |
796 | impl->m_VerticalCursor->setPosition(time); |
|
793 | impl->m_VerticalCursor->setPosition(time); | |
797 | impl->m_VerticalCursor->setVisible(true); |
|
794 | impl->m_VerticalCursor->setVisible(true); | |
798 |
|
795 | |||
799 | auto text |
|
796 | auto text | |
800 | = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n'); |
|
797 | = DateUtils::dateTime(time).toString(CURSOR_LABELS_DATETIME_FORMAT).replace(' ', '\n'); | |
801 | impl->m_VerticalCursor->setLabelText(text); |
|
798 | impl->m_VerticalCursor->setLabelText(text); | |
802 | } |
|
799 | } | |
803 |
|
800 | |||
804 | void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position) |
|
801 | void VisualizationGraphWidget::addVerticalCursorAtViewportPosition(double position) | |
805 | { |
|
802 | { | |
806 | impl->m_VerticalCursor->setAbsolutePosition(position); |
|
803 | impl->m_VerticalCursor->setAbsolutePosition(position); | |
807 | impl->m_VerticalCursor->setVisible(true); |
|
804 | impl->m_VerticalCursor->setVisible(true); | |
808 |
|
805 | |||
809 | auto axis = plot().axisRect()->axis(QCPAxis::atBottom); |
|
806 | auto axis = plot().axisRect()->axis(QCPAxis::atBottom); | |
810 | auto text |
|
807 | auto text | |
811 | = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT); |
|
808 | = DateUtils::dateTime(axis->pixelToCoord(position)).toString(CURSOR_LABELS_DATETIME_FORMAT); | |
812 | impl->m_VerticalCursor->setLabelText(text); |
|
809 | impl->m_VerticalCursor->setLabelText(text); | |
813 | } |
|
810 | } | |
814 |
|
811 | |||
815 | void VisualizationGraphWidget::removeVerticalCursor() |
|
812 | void VisualizationGraphWidget::removeVerticalCursor() | |
816 | { |
|
813 | { | |
817 | impl->m_VerticalCursor->setVisible(false); |
|
814 | impl->m_VerticalCursor->setVisible(false); | |
818 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
815 | plot().replot(QCustomPlot::rpQueuedReplot); | |
819 | } |
|
816 | } | |
820 |
|
817 | |||
821 | void VisualizationGraphWidget::addHorizontalCursor(double value) |
|
818 | void VisualizationGraphWidget::addHorizontalCursor(double value) | |
822 | { |
|
819 | { | |
823 | impl->m_HorizontalCursor->setPosition(value); |
|
820 | impl->m_HorizontalCursor->setPosition(value); | |
824 | impl->m_HorizontalCursor->setVisible(true); |
|
821 | impl->m_HorizontalCursor->setVisible(true); | |
825 | impl->m_HorizontalCursor->setLabelText(QString::number(value)); |
|
822 | impl->m_HorizontalCursor->setLabelText(QString::number(value)); | |
826 | } |
|
823 | } | |
827 |
|
824 | |||
828 | void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position) |
|
825 | void VisualizationGraphWidget::addHorizontalCursorAtViewportPosition(double position) | |
829 | { |
|
826 | { | |
830 | impl->m_HorizontalCursor->setAbsolutePosition(position); |
|
827 | impl->m_HorizontalCursor->setAbsolutePosition(position); | |
831 | impl->m_HorizontalCursor->setVisible(true); |
|
828 | impl->m_HorizontalCursor->setVisible(true); | |
832 |
|
829 | |||
833 | auto axis = plot().axisRect()->axis(QCPAxis::atLeft); |
|
830 | auto axis = plot().axisRect()->axis(QCPAxis::atLeft); | |
834 | impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position))); |
|
831 | impl->m_HorizontalCursor->setLabelText(QString::number(axis->pixelToCoord(position))); | |
835 | } |
|
832 | } | |
836 |
|
833 | |||
837 | void VisualizationGraphWidget::removeHorizontalCursor() |
|
834 | void VisualizationGraphWidget::removeHorizontalCursor() | |
838 | { |
|
835 | { | |
839 | impl->m_HorizontalCursor->setVisible(false); |
|
836 | impl->m_HorizontalCursor->setVisible(false); | |
840 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
837 | plot().replot(QCustomPlot::rpQueuedReplot); | |
841 | } |
|
838 | } | |
842 |
|
839 | |||
843 | void VisualizationGraphWidget::closeEvent(QCloseEvent* event) |
|
840 | void VisualizationGraphWidget::closeEvent(QCloseEvent* event) | |
844 | { |
|
841 | { | |
845 | Q_UNUSED(event); |
|
842 | Q_UNUSED(event); | |
846 |
|
843 | |||
847 | for (auto i : impl->m_SelectionZones) |
|
844 | for (auto i : impl->m_SelectionZones) | |
848 | { |
|
845 | { | |
849 | parentVisualizationWidget()->selectionZoneManager().setSelected(i, false); |
|
846 | parentVisualizationWidget()->selectionZoneManager().setSelected(i, false); | |
850 | } |
|
847 | } | |
851 |
|
848 | |||
852 | // Prevents that all variables will be removed from graph when it will be closed |
|
849 | // Prevents that all variables will be removed from graph when it will be closed | |
853 | for (auto& variableEntry : impl->m_VariableToPlotMultiMap) |
|
850 | for (auto& variableEntry : impl->m_VariableToPlotMultiMap) | |
854 | { |
|
851 | { | |
855 | emit variableAboutToBeRemoved(variableEntry.first); |
|
852 | emit variableAboutToBeRemoved(variableEntry.first); | |
856 | } |
|
853 | } | |
857 | } |
|
854 | } | |
858 |
|
855 | |||
859 | void VisualizationGraphWidget::enterEvent(QEvent* event) |
|
856 | void VisualizationGraphWidget::enterEvent(QEvent* event) | |
860 | { |
|
857 | { | |
861 | Q_UNUSED(event); |
|
858 | Q_UNUSED(event); | |
862 | impl->m_RenderingDelegate->showGraphOverlay(true); |
|
859 | impl->m_RenderingDelegate->showGraphOverlay(true); | |
863 | } |
|
860 | } | |
864 |
|
861 | |||
865 | void VisualizationGraphWidget::leaveEvent(QEvent* event) |
|
862 | void VisualizationGraphWidget::leaveEvent(QEvent* event) | |
866 | { |
|
863 | { | |
867 | Q_UNUSED(event); |
|
864 | Q_UNUSED(event); | |
868 | impl->m_RenderingDelegate->showGraphOverlay(false); |
|
865 | impl->m_RenderingDelegate->showGraphOverlay(false); | |
869 |
|
866 | |||
870 | if (auto parentZone = parentZoneWidget()) |
|
867 | if (auto parentZone = parentZoneWidget()) | |
871 | { |
|
868 | { | |
872 | parentZone->notifyMouseLeaveGraph(this); |
|
869 | parentZone->notifyMouseLeaveGraph(this); | |
873 | } |
|
870 | } | |
874 | else |
|
871 | else | |
875 | { |
|
872 | { | |
876 | qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget"; |
|
873 | qCWarning(LOG_VisualizationGraphWidget()) << "leaveEvent: No parent zone widget"; | |
877 | } |
|
874 | } | |
878 |
|
875 | |||
879 | if (impl->m_HoveredZone) |
|
876 | if (impl->m_HoveredZone) | |
880 | { |
|
877 | { | |
881 | impl->m_HoveredZone->setHovered(false); |
|
878 | impl->m_HoveredZone->setHovered(false); | |
882 | impl->m_HoveredZone = nullptr; |
|
879 | impl->m_HoveredZone = nullptr; | |
883 | } |
|
880 | } | |
884 | } |
|
881 | } | |
885 |
|
882 | |||
886 | void VisualizationGraphWidget::wheelEvent(QWheelEvent* event) |
|
883 | void VisualizationGraphWidget::wheelEvent(QWheelEvent* event) | |
887 | { |
|
884 | { | |
888 | double factor; |
|
885 | double factor; | |
889 | double wheelSteps = event->delta() / 120.0; // a single step delta is +/-120 usually |
|
886 | double wheelSteps = event->delta() / 120.0; // a single step delta is +/-120 usually | |
890 | if (event->modifiers() == Qt::ControlModifier) |
|
887 | if (event->modifiers() == Qt::ControlModifier) | |
891 | { |
|
888 | { | |
892 | if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical)) |
|
889 | if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical)) | |
893 | { |
|
890 | { | |
894 | setCursor(Qt::SizeVerCursor); |
|
891 | setCursor(Qt::SizeVerCursor); | |
895 | factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps); |
|
892 | factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps); | |
896 | zoom(factor, event->pos().y(), Qt::Vertical); |
|
893 | zoom(factor, event->pos().y(), Qt::Vertical); | |
897 | } |
|
894 | } | |
898 | } |
|
895 | } | |
899 | else if (event->modifiers() == Qt::ShiftModifier) |
|
896 | else if (event->modifiers() == Qt::ShiftModifier) | |
900 | { |
|
897 | { | |
901 | if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical)) |
|
898 | if (event->orientation() == Qt::Vertical) // mRangeZoom.testFlag(Qt::Vertical)) | |
902 | { |
|
899 | { | |
903 | setCursor(Qt::SizeHorCursor); |
|
900 | setCursor(Qt::SizeHorCursor); | |
904 | factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps); |
|
901 | factor = pow(impl->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps); | |
905 | zoom(factor, event->pos().x(), Qt::Horizontal); |
|
902 | zoom(factor, event->pos().x(), Qt::Horizontal); | |
906 | } |
|
903 | } | |
907 | } |
|
904 | } | |
908 | else |
|
905 | else | |
909 | { |
|
906 | { | |
910 | move(wheelSteps, Qt::Horizontal); |
|
907 | move(wheelSteps, Qt::Horizontal); | |
911 | } |
|
908 | } | |
912 | event->accept(); |
|
909 | event->accept(); | |
913 | } |
|
910 | } | |
914 |
|
911 | |||
915 |
|
912 | |||
916 | void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent* event) |
|
913 | void VisualizationGraphWidget::mouseMoveEvent(QMouseEvent* event) | |
917 | { |
|
914 | { | |
918 | if (impl->isDrawingZoomRect()) |
|
915 | if (impl->isDrawingZoomRect()) | |
919 | { |
|
916 | { | |
920 | impl->updateZoomRect(event->pos()); |
|
917 | impl->updateZoomRect(event->pos()); | |
921 | } |
|
918 | } | |
922 | else if (impl->isDrawingZoneRect()) |
|
919 | else if (impl->isDrawingZoneRect()) | |
923 | { |
|
920 | { | |
924 | impl->updateZoneRect(event->pos()); |
|
921 | impl->updateZoneRect(event->pos()); | |
925 | } |
|
922 | } | |
926 | else if (event->buttons() == Qt::LeftButton) |
|
923 | else if (event->buttons() == Qt::LeftButton) | |
927 | { |
|
924 | { | |
928 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None) |
|
925 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::None) | |
929 | { |
|
926 | { | |
930 | auto [dx, dy] = impl->moveGraph(event->pos()); |
|
927 | auto [dx, dy] = impl->moveGraph(event->pos()); | |
931 | emit this->setrange_sig(this->graphRange(), true, false); |
|
928 | emit this->setrange_sig(this->graphRange(), true, false); | |
932 | } |
|
929 | } | |
933 | else if (sqpApp->plotsInteractionMode() |
|
930 | else if (sqpApp->plotsInteractionMode() | |
934 | == SqpApplication::PlotsInteractionMode::SelectionZones) |
|
931 | == SqpApplication::PlotsInteractionMode::SelectionZones) | |
935 | { |
|
932 | { | |
936 | auto posInPlot = this->impl->m_plot->mapFromParent(event->pos()); |
|
933 | auto posInPlot = this->impl->m_plot->mapFromParent(event->pos()); | |
937 | if (auto item = impl->m_plot->itemAt(posInPlot)) |
|
934 | if (auto item = impl->m_plot->itemAt(posInPlot)) | |
938 | { |
|
935 | { | |
939 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) |
|
936 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) | |
940 | { |
|
937 | { | |
941 | QMouseEvent e { QEvent::MouseMove, posInPlot, event->button(), event->buttons(), |
|
938 | QMouseEvent e { QEvent::MouseMove, posInPlot, event->button(), event->buttons(), | |
942 | event->modifiers() }; |
|
939 | event->modifiers() }; | |
943 | sqpApp->sendEvent(this->impl->m_plot, &e); |
|
940 | sqpApp->sendEvent(this->impl->m_plot, &e); | |
944 | this->impl->m_plot->replot(QCustomPlot::rpImmediateRefresh); |
|
941 | this->impl->m_plot->replot(QCustomPlot::rpImmediateRefresh); | |
945 | } |
|
942 | } | |
946 | } |
|
943 | } | |
947 | } |
|
944 | } | |
948 | } |
|
945 | } | |
949 | else |
|
946 | else | |
950 | { |
|
947 | { | |
951 | impl->m_RenderingDelegate->updateTooltip(event); |
|
948 | impl->m_RenderingDelegate->updateTooltip(event); | |
952 | } |
|
949 | } | |
953 | // event->accept(); |
|
950 | // event->accept(); | |
954 | QWidget::mouseMoveEvent(event); |
|
951 | QWidget::mouseMoveEvent(event); | |
955 | } |
|
952 | } | |
956 |
|
953 | |||
957 | void VisualizationGraphWidget::mouseReleaseEvent(QMouseEvent* event) |
|
954 | void VisualizationGraphWidget::mouseReleaseEvent(QMouseEvent* event) | |
958 | { |
|
955 | { | |
959 | if (impl->isDrawingZoomRect()) |
|
956 | if (impl->isDrawingZoomRect()) | |
960 | { |
|
957 | { | |
961 | auto oldRange = this->graphRange(); |
|
958 | auto oldRange = this->graphRange(); | |
962 | impl->applyZoomRect(); |
|
959 | impl->applyZoomRect(); | |
963 | auto newRange = this->graphRange(); |
|
960 | auto newRange = this->graphRange(); | |
964 | if (auto tf = DateTimeRangeHelper::computeTransformation(oldRange, newRange)) |
|
961 | if (auto tf = DateTimeRangeHelper::computeTransformation(oldRange, newRange)) | |
965 | emit this->transform_sig(tf.value(), false); |
|
962 | emit this->transform_sig(tf.value(), false); | |
966 | } |
|
963 | } | |
967 | else if (impl->isDrawingZoneRect()) |
|
964 | else if (impl->isDrawingZoneRect()) | |
968 | { |
|
965 | { | |
969 | impl->endDrawingZone(); |
|
966 | impl->endDrawingZone(); | |
970 | } |
|
967 | } | |
971 | else |
|
968 | else | |
972 | { |
|
969 | { | |
973 | setCursor(Qt::ArrowCursor); |
|
970 | setCursor(Qt::ArrowCursor); | |
974 | } |
|
971 | } | |
975 | auto posInPlot = this->impl->m_plot->mapFromParent(event->pos()); |
|
972 | auto posInPlot = this->impl->m_plot->mapFromParent(event->pos()); | |
976 | if (auto item = impl->m_plot->itemAt(posInPlot)) |
|
973 | if (auto item = impl->m_plot->itemAt(posInPlot)) | |
977 | { |
|
974 | { | |
978 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) |
|
975 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) | |
979 | { |
|
976 | { | |
980 | QMouseEvent e { QEvent::MouseButtonRelease, posInPlot, event->button(), |
|
977 | QMouseEvent e { QEvent::MouseButtonRelease, posInPlot, event->button(), | |
981 | event->buttons(), event->modifiers() }; |
|
978 | event->buttons(), event->modifiers() }; | |
982 | sqpApp->sendEvent(this->impl->m_plot, &e); |
|
979 | sqpApp->sendEvent(this->impl->m_plot, &e); | |
983 | } |
|
980 | } | |
984 | } |
|
981 | } | |
985 | event->accept(); |
|
982 | event->accept(); | |
986 | } |
|
983 | } | |
987 |
|
984 | |||
988 | void VisualizationGraphWidget::mousePressEvent(QMouseEvent* event) |
|
985 | void VisualizationGraphWidget::mousePressEvent(QMouseEvent* event) | |
989 | { |
|
986 | { | |
990 | if (event->button() == Qt::RightButton) |
|
987 | if (event->button() == Qt::RightButton) | |
991 | { |
|
988 | { | |
992 | onGraphMenuRequested(event->pos()); |
|
989 | onGraphMenuRequested(event->pos()); | |
993 | } |
|
990 | } | |
994 | else |
|
991 | else | |
995 | { |
|
992 | { | |
996 | auto selectedZone = impl->selectionZoneAt(event->pos()); |
|
993 | auto selectedZone = impl->selectionZoneAt(event->pos()); | |
997 | switch (sqpApp->plotsInteractionMode()) |
|
994 | switch (sqpApp->plotsInteractionMode()) | |
998 | { |
|
995 | { | |
999 | case SqpApplication::PlotsInteractionMode::DragAndDrop: |
|
996 | case SqpApplication::PlotsInteractionMode::DragAndDrop: | |
1000 | break; |
|
997 | break; | |
1001 | case SqpApplication::PlotsInteractionMode::SelectionZones: |
|
998 | case SqpApplication::PlotsInteractionMode::SelectionZones: | |
1002 | impl->setSelectionZonesEditionEnabled(true); |
|
999 | impl->setSelectionZonesEditionEnabled(true); | |
1003 | if ((event->modifiers() == Qt::ControlModifier) && (selectedZone != nullptr)) |
|
1000 | if ((event->modifiers() == Qt::ControlModifier) && (selectedZone != nullptr)) | |
1004 | { |
|
1001 | { | |
1005 | auto alreadySelectedZones |
|
1002 | auto alreadySelectedZones | |
1006 | = parentVisualizationWidget()->selectionZoneManager().selectedItems(); |
|
1003 | = parentVisualizationWidget()->selectionZoneManager().selectedItems(); | |
1007 | selectedZone->setAssociatedEditedZones(alreadySelectedZones); |
|
1004 | selectedZone->setAssociatedEditedZones(alreadySelectedZones); | |
1008 | if (SciQLop::containers::contains(alreadySelectedZones, selectedZone)) |
|
1005 | if (SciQLop::containers::contains(alreadySelectedZones, selectedZone)) | |
1009 | { |
|
1006 | { | |
1010 | alreadySelectedZones.removeOne(selectedZone); |
|
1007 | alreadySelectedZones.removeOne(selectedZone); | |
1011 | } |
|
1008 | } | |
1012 | else |
|
1009 | else | |
1013 | { |
|
1010 | { | |
1014 | alreadySelectedZones.append(selectedZone); |
|
1011 | alreadySelectedZones.append(selectedZone); | |
1015 | } |
|
1012 | } | |
1016 | parentVisualizationWidget()->selectionZoneManager().select( |
|
1013 | parentVisualizationWidget()->selectionZoneManager().select( | |
1017 | alreadySelectedZones); |
|
1014 | alreadySelectedZones); | |
1018 | } |
|
1015 | } | |
1019 | else |
|
1016 | else | |
1020 | { |
|
1017 | { | |
1021 | if (!selectedZone) |
|
1018 | if (!selectedZone) | |
1022 | { |
|
1019 | { | |
1023 | parentVisualizationWidget()->selectionZoneManager().clearSelection(); |
|
1020 | parentVisualizationWidget()->selectionZoneManager().clearSelection(); | |
1024 | impl->startDrawingZone(event->pos()); |
|
1021 | impl->startDrawingZone(event->pos()); | |
1025 | } |
|
1022 | } | |
1026 | else |
|
1023 | else | |
1027 | { |
|
1024 | { | |
1028 | parentVisualizationWidget()->selectionZoneManager().select( |
|
1025 | parentVisualizationWidget()->selectionZoneManager().select( | |
1029 | { selectedZone }); |
|
1026 | { selectedZone }); | |
1030 | } |
|
1027 | } | |
1031 | } |
|
1028 | } | |
1032 | { |
|
1029 | { | |
1033 | auto posInPlot = this->impl->m_plot->mapFromParent(event->pos()); |
|
1030 | auto posInPlot = this->impl->m_plot->mapFromParent(event->pos()); | |
1034 | if (auto item = impl->m_plot->itemAt(posInPlot)) |
|
1031 | if (auto item = impl->m_plot->itemAt(posInPlot)) | |
1035 | { |
|
1032 | { | |
1036 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) |
|
1033 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) | |
1037 | { |
|
1034 | { | |
1038 | QMouseEvent e { QEvent::MouseButtonPress, posInPlot, event->button(), |
|
1035 | QMouseEvent e { QEvent::MouseButtonPress, posInPlot, event->button(), | |
1039 | event->buttons(), event->modifiers() }; |
|
1036 | event->buttons(), event->modifiers() }; | |
1040 | sqpApp->sendEvent(this->impl->m_plot, &e); |
|
1037 | sqpApp->sendEvent(this->impl->m_plot, &e); | |
1041 | } |
|
1038 | } | |
1042 | } |
|
1039 | } | |
1043 | } |
|
1040 | } | |
1044 | break; |
|
1041 | break; | |
1045 | case SqpApplication::PlotsInteractionMode::ZoomBox: |
|
1042 | case SqpApplication::PlotsInteractionMode::ZoomBox: | |
1046 | impl->startDrawingRect(event->pos()); |
|
1043 | impl->startDrawingRect(event->pos()); | |
1047 | break; |
|
1044 | break; | |
1048 | default: |
|
1045 | default: | |
1049 | if (auto item = impl->m_plot->itemAt(event->pos())) |
|
1046 | if (auto item = impl->m_plot->itemAt(event->pos())) | |
1050 | { |
|
1047 | { | |
1051 | emit impl->m_plot->itemClick(item, event); |
|
1048 | emit impl->m_plot->itemClick(item, event); | |
1052 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) |
|
1049 | if (qobject_cast<VisualizationSelectionZoneItem*>(item)) | |
1053 | { |
|
1050 | { | |
1054 | setCursor(Qt::ClosedHandCursor); |
|
1051 | setCursor(Qt::ClosedHandCursor); | |
1055 | impl->enterPlotDrag(event->pos()); |
|
1052 | impl->enterPlotDrag(event->pos()); | |
1056 | } |
|
1053 | } | |
1057 | } |
|
1054 | } | |
1058 | else |
|
1055 | else | |
1059 | { |
|
1056 | { | |
1060 | setCursor(Qt::ClosedHandCursor); |
|
1057 | setCursor(Qt::ClosedHandCursor); | |
1061 | impl->enterPlotDrag(event->pos()); |
|
1058 | impl->enterPlotDrag(event->pos()); | |
1062 | } |
|
1059 | } | |
1063 | } |
|
1060 | } | |
1064 | } |
|
1061 | } | |
1065 | // event->accept(); |
|
1062 | // event->accept(); | |
1066 | QWidget::mousePressEvent(event); |
|
1063 | QWidget::mousePressEvent(event); | |
1067 | } |
|
1064 | } | |
1068 |
|
1065 | |||
1069 | void VisualizationGraphWidget::mouseDoubleClickEvent(QMouseEvent* event) |
|
1066 | void VisualizationGraphWidget::mouseDoubleClickEvent(QMouseEvent* event) | |
1070 | { |
|
1067 | { | |
1071 | impl->m_RenderingDelegate->onMouseDoubleClick(event); |
|
1068 | impl->m_RenderingDelegate->onMouseDoubleClick(event); | |
1072 | } |
|
1069 | } | |
1073 |
|
1070 | |||
1074 | void VisualizationGraphWidget::keyReleaseEvent(QKeyEvent* event) |
|
1071 | void VisualizationGraphWidget::keyReleaseEvent(QKeyEvent* event) | |
1075 | { |
|
1072 | { | |
1076 | switch (event->key()) |
|
1073 | switch (event->key()) | |
1077 | { |
|
1074 | { | |
1078 | case Qt::Key_Control: |
|
1075 | case Qt::Key_Control: | |
1079 | event->accept(); |
|
1076 | event->accept(); | |
1080 | break; |
|
1077 | break; | |
1081 | case Qt::Key_Shift: |
|
1078 | case Qt::Key_Shift: | |
1082 | event->accept(); |
|
1079 | event->accept(); | |
1083 | break; |
|
1080 | break; | |
1084 | default: |
|
1081 | default: | |
1085 | QWidget::keyReleaseEvent(event); |
|
1082 | QWidget::keyReleaseEvent(event); | |
1086 | break; |
|
1083 | break; | |
1087 | } |
|
1084 | } | |
1088 | setCursor(Qt::ArrowCursor); |
|
1085 | setCursor(Qt::ArrowCursor); | |
1089 | // event->accept(); |
|
1086 | // event->accept(); | |
1090 | } |
|
1087 | } | |
1091 |
|
1088 | |||
1092 | void VisualizationGraphWidget::keyPressEvent(QKeyEvent* event) |
|
1089 | void VisualizationGraphWidget::keyPressEvent(QKeyEvent* event) | |
1093 | { |
|
1090 | { | |
1094 | switch (event->key()) |
|
1091 | switch (event->key()) | |
1095 | { |
|
1092 | { | |
1096 | case Qt::Key_Control: |
|
1093 | case Qt::Key_Control: | |
1097 | setCursor(Qt::CrossCursor); |
|
1094 | setCursor(Qt::CrossCursor); | |
1098 | break; |
|
1095 | break; | |
1099 | case Qt::Key_Shift: |
|
1096 | case Qt::Key_Shift: | |
1100 | break; |
|
1097 | break; | |
1101 | case Qt::Key_M: |
|
1098 | case Qt::Key_M: | |
1102 | impl->rescaleY(); |
|
1099 | impl->rescaleY(); | |
1103 | impl->m_plot->replot(QCustomPlot::rpQueuedReplot); |
|
1100 | impl->m_plot->replot(QCustomPlot::rpQueuedReplot); | |
1104 | break; |
|
1101 | break; | |
1105 | case Qt::Key_Left: |
|
1102 | case Qt::Key_Left: | |
1106 | if (event->modifiers() != Qt::ControlModifier) |
|
1103 | if (event->modifiers() != Qt::ControlModifier) | |
1107 | { |
|
1104 | { | |
1108 | move(-0.1, Qt::Horizontal); |
|
1105 | move(-0.1, Qt::Horizontal); | |
1109 | } |
|
1106 | } | |
1110 | else |
|
1107 | else | |
1111 | { |
|
1108 | { | |
1112 | zoom(2, this->width() / 2, Qt::Horizontal); |
|
1109 | zoom(2, this->width() / 2, Qt::Horizontal); | |
1113 | } |
|
1110 | } | |
1114 | break; |
|
1111 | break; | |
1115 | case Qt::Key_Right: |
|
1112 | case Qt::Key_Right: | |
1116 | if (event->modifiers() != Qt::ControlModifier) |
|
1113 | if (event->modifiers() != Qt::ControlModifier) | |
1117 | { |
|
1114 | { | |
1118 | move(0.1, Qt::Horizontal); |
|
1115 | move(0.1, Qt::Horizontal); | |
1119 | } |
|
1116 | } | |
1120 | else |
|
1117 | else | |
1121 | { |
|
1118 | { | |
1122 | zoom(0.5, this->width() / 2, Qt::Horizontal); |
|
1119 | zoom(0.5, this->width() / 2, Qt::Horizontal); | |
1123 | } |
|
1120 | } | |
1124 | break; |
|
1121 | break; | |
1125 | case Qt::Key_Up: |
|
1122 | case Qt::Key_Up: | |
1126 | if (event->modifiers() != Qt::ControlModifier) |
|
1123 | if (event->modifiers() != Qt::ControlModifier) | |
1127 | { |
|
1124 | { | |
1128 | move(0.1, Qt::Vertical); |
|
1125 | move(0.1, Qt::Vertical); | |
1129 | } |
|
1126 | } | |
1130 | else |
|
1127 | else | |
1131 | { |
|
1128 | { | |
1132 | zoom(0.5, this->height() / 2, Qt::Vertical); |
|
1129 | zoom(0.5, this->height() / 2, Qt::Vertical); | |
1133 | } |
|
1130 | } | |
1134 | break; |
|
1131 | break; | |
1135 | case Qt::Key_Down: |
|
1132 | case Qt::Key_Down: | |
1136 | if (event->modifiers() != Qt::ControlModifier) |
|
1133 | if (event->modifiers() != Qt::ControlModifier) | |
1137 | { |
|
1134 | { | |
1138 | move(-0.1, Qt::Vertical); |
|
1135 | move(-0.1, Qt::Vertical); | |
1139 | } |
|
1136 | } | |
1140 | else |
|
1137 | else | |
1141 | { |
|
1138 | { | |
1142 | zoom(2, this->height() / 2, Qt::Vertical); |
|
1139 | zoom(2, this->height() / 2, Qt::Vertical); | |
1143 | } |
|
1140 | } | |
1144 | break; |
|
1141 | break; | |
1145 | default: |
|
1142 | default: | |
1146 | QWidget::keyPressEvent(event); |
|
1143 | QWidget::keyPressEvent(event); | |
1147 | break; |
|
1144 | break; | |
1148 | } |
|
1145 | } | |
1149 | } |
|
1146 | } | |
1150 |
|
1147 | |||
1151 | QCustomPlot& VisualizationGraphWidget::plot() const noexcept |
|
1148 | QCustomPlot& VisualizationGraphWidget::plot() const noexcept | |
1152 | { |
|
1149 | { | |
1153 | return *impl->m_plot; |
|
1150 | return *impl->m_plot; | |
1154 | } |
|
1151 | } | |
1155 |
|
1152 | |||
1156 | void VisualizationGraphWidget::onGraphMenuRequested(const QPoint& pos) noexcept |
|
1153 | void VisualizationGraphWidget::onGraphMenuRequested(const QPoint& pos) noexcept | |
1157 | { |
|
1154 | { | |
1158 | QMenu graphMenu {}; |
|
1155 | QMenu graphMenu {}; | |
1159 |
|
1156 | |||
1160 | // Iterates on variables (unique keys) |
|
1157 | // Iterates on variables (unique keys) | |
1161 | for (auto it = impl->m_VariableToPlotMultiMap.cbegin(), |
|
1158 | for (auto it = impl->m_VariableToPlotMultiMap.cbegin(), | |
1162 | end = impl->m_VariableToPlotMultiMap.cend(); |
|
1159 | end = impl->m_VariableToPlotMultiMap.cend(); | |
1163 | it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) |
|
1160 | it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) | |
1164 | { |
|
1161 | { | |
1165 | // 'Remove variable' action |
|
1162 | // 'Remove variable' action | |
1166 | graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()), |
|
1163 | graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()), | |
1167 | [this, var = it->first]() { removeVariable(var); }); |
|
1164 | [this, var = it->first]() { removeVariable(var); }); | |
1168 | } |
|
1165 | } | |
1169 |
|
1166 | |||
1170 | if (!impl->m_ZoomStack.isEmpty()) |
|
1167 | if (!impl->m_ZoomStack.isEmpty()) | |
1171 | { |
|
1168 | { | |
1172 | if (!graphMenu.isEmpty()) |
|
1169 | if (!graphMenu.isEmpty()) | |
1173 | { |
|
1170 | { | |
1174 | graphMenu.addSeparator(); |
|
1171 | graphMenu.addSeparator(); | |
1175 | } |
|
1172 | } | |
1176 |
|
1173 | |||
1177 | graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); }); |
|
1174 | graphMenu.addAction(tr("Undo Zoom"), [this]() { undoZoom(); }); | |
1178 | } |
|
1175 | } | |
1179 |
|
1176 | |||
1180 | // Selection Zone Actions |
|
1177 | // Selection Zone Actions | |
1181 | auto selectionZoneItem = impl->selectionZoneAt(pos); |
|
1178 | auto selectionZoneItem = impl->selectionZoneAt(pos); | |
1182 | if (selectionZoneItem) |
|
1179 | if (selectionZoneItem) | |
1183 | { |
|
1180 | { | |
1184 | auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems(); |
|
1181 | auto selectedItems = parentVisualizationWidget()->selectionZoneManager().selectedItems(); | |
1185 | selectedItems.removeAll(selectionZoneItem); |
|
1182 | selectedItems.removeAll(selectionZoneItem); | |
1186 | selectedItems.prepend(selectionZoneItem); // Put the current selection zone first |
|
1183 | selectedItems.prepend(selectionZoneItem); // Put the current selection zone first | |
1187 |
|
1184 | |||
1188 | auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions(); |
|
1185 | auto zoneActions = sqpApp->actionsGuiController().selectionZoneActions(); | |
1189 | if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) |
|
1186 | if (!zoneActions.isEmpty() && !graphMenu.isEmpty()) | |
1190 | { |
|
1187 | { | |
1191 | graphMenu.addSeparator(); |
|
1188 | graphMenu.addSeparator(); | |
1192 | } |
|
1189 | } | |
1193 |
|
1190 | |||
1194 | QHash<QString, QMenu*> subMenus; |
|
1191 | QHash<QString, QMenu*> subMenus; | |
1195 | QHash<QString, bool> subMenusEnabled; |
|
1192 | QHash<QString, bool> subMenusEnabled; | |
1196 | QHash<QString, FilteringAction*> filteredMenu; |
|
1193 | QHash<QString, FilteringAction*> filteredMenu; | |
1197 |
|
1194 | |||
1198 | for (auto zoneAction : zoneActions) |
|
1195 | for (auto zoneAction : zoneActions) | |
1199 | { |
|
1196 | { | |
1200 |
|
1197 | |||
1201 | auto isEnabled = zoneAction->isEnabled(selectedItems); |
|
1198 | auto isEnabled = zoneAction->isEnabled(selectedItems); | |
1202 |
|
1199 | |||
1203 | auto menu = &graphMenu; |
|
1200 | auto menu = &graphMenu; | |
1204 | QString menuPath; |
|
1201 | QString menuPath; | |
1205 | for (auto subMenuName : zoneAction->subMenuList()) |
|
1202 | for (auto subMenuName : zoneAction->subMenuList()) | |
1206 | { |
|
1203 | { | |
1207 | menuPath += '/'; |
|
1204 | menuPath += '/'; | |
1208 | menuPath += subMenuName; |
|
1205 | menuPath += subMenuName; | |
1209 |
|
1206 | |||
1210 | if (!subMenus.contains(menuPath)) |
|
1207 | if (!subMenus.contains(menuPath)) | |
1211 | { |
|
1208 | { | |
1212 | menu = menu->addMenu(subMenuName); |
|
1209 | menu = menu->addMenu(subMenuName); | |
1213 | subMenus[menuPath] = menu; |
|
1210 | subMenus[menuPath] = menu; | |
1214 | subMenusEnabled[menuPath] = isEnabled; |
|
1211 | subMenusEnabled[menuPath] = isEnabled; | |
1215 | } |
|
1212 | } | |
1216 | else |
|
1213 | else | |
1217 | { |
|
1214 | { | |
1218 | menu = subMenus.value(menuPath); |
|
1215 | menu = subMenus.value(menuPath); | |
1219 | if (isEnabled) |
|
1216 | if (isEnabled) | |
1220 | { |
|
1217 | { | |
1221 | // The sub menu is enabled if at least one of its actions is enabled |
|
1218 | // The sub menu is enabled if at least one of its actions is enabled | |
1222 | subMenusEnabled[menuPath] = true; |
|
1219 | subMenusEnabled[menuPath] = true; | |
1223 | } |
|
1220 | } | |
1224 | } |
|
1221 | } | |
1225 | } |
|
1222 | } | |
1226 |
|
1223 | |||
1227 | FilteringAction* filterAction = nullptr; |
|
1224 | FilteringAction* filterAction = nullptr; | |
1228 | if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) |
|
1225 | if (sqpApp->actionsGuiController().isMenuFiltered(zoneAction->subMenuList())) | |
1229 | { |
|
1226 | { | |
1230 | filterAction = filteredMenu.value(menuPath); |
|
1227 | filterAction = filteredMenu.value(menuPath); | |
1231 | if (!filterAction) |
|
1228 | if (!filterAction) | |
1232 | { |
|
1229 | { | |
1233 | filterAction = new FilteringAction { this }; |
|
1230 | filterAction = new FilteringAction { this }; | |
1234 | filteredMenu[menuPath] = filterAction; |
|
1231 | filteredMenu[menuPath] = filterAction; | |
1235 | menu->addAction(filterAction); |
|
1232 | menu->addAction(filterAction); | |
1236 | } |
|
1233 | } | |
1237 | } |
|
1234 | } | |
1238 |
|
1235 | |||
1239 | auto action = menu->addAction(zoneAction->name()); |
|
1236 | auto action = menu->addAction(zoneAction->name()); | |
1240 | action->setEnabled(isEnabled); |
|
1237 | action->setEnabled(isEnabled); | |
1241 | action->setShortcut(zoneAction->displayedShortcut()); |
|
1238 | action->setShortcut(zoneAction->displayedShortcut()); | |
1242 | QObject::connect(action, &QAction::triggered, |
|
1239 | QObject::connect(action, &QAction::triggered, | |
1243 | [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); }); |
|
1240 | [zoneAction, selectedItems]() { zoneAction->execute(selectedItems); }); | |
1244 |
|
1241 | |||
1245 | if (filterAction && zoneAction->isFilteringAllowed()) |
|
1242 | if (filterAction && zoneAction->isFilteringAllowed()) | |
1246 | { |
|
1243 | { | |
1247 | filterAction->addActionToFilter(action); |
|
1244 | filterAction->addActionToFilter(action); | |
1248 | } |
|
1245 | } | |
1249 | } |
|
1246 | } | |
1250 |
|
1247 | |||
1251 | for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) |
|
1248 | for (auto it = subMenus.cbegin(); it != subMenus.cend(); ++it) | |
1252 | { |
|
1249 | { | |
1253 | it.value()->setEnabled(subMenusEnabled[it.key()]); |
|
1250 | it.value()->setEnabled(subMenusEnabled[it.key()]); | |
1254 | } |
|
1251 | } | |
1255 | } |
|
1252 | } | |
1256 |
|
1253 | |||
1257 | if (!graphMenu.isEmpty()) |
|
1254 | if (!graphMenu.isEmpty()) | |
1258 | { |
|
1255 | { | |
1259 | graphMenu.exec(QCursor::pos()); |
|
1256 | graphMenu.exec(QCursor::pos()); | |
1260 | } |
|
1257 | } | |
1261 | } |
|
1258 | } | |
1262 |
|
1259 | |||
1263 | void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent* event) noexcept |
|
1260 | void VisualizationGraphWidget::onMouseDoubleClick(QMouseEvent* event) noexcept | |
1264 | { |
|
1261 | { | |
1265 | impl->m_RenderingDelegate->onMouseDoubleClick(event); |
|
1262 | impl->m_RenderingDelegate->onMouseDoubleClick(event); | |
1266 | } |
|
1263 | } | |
1267 |
|
1264 | |||
1268 | void VisualizationGraphWidget::onMouseMove(QMouseEvent* event) noexcept |
|
1265 | void VisualizationGraphWidget::onMouseMove(QMouseEvent* event) noexcept | |
1269 | { |
|
1266 | { | |
1270 | // Handles plot rendering when mouse is moving |
|
1267 | // Handles plot rendering when mouse is moving | |
1271 | impl->m_RenderingDelegate->updateTooltip(event); |
|
1268 | impl->m_RenderingDelegate->updateTooltip(event); | |
1272 |
|
1269 | |||
1273 | auto axisPos = impl->posToAxisPos(event->pos()); |
|
1270 | auto axisPos = impl->posToAxisPos(event->pos()); | |
1274 |
|
1271 | |||
1275 | // Zoom box and zone drawing |
|
1272 | // Zoom box and zone drawing | |
1276 | if (impl->m_DrawingZoomRect) |
|
1273 | if (impl->m_DrawingZoomRect) | |
1277 | { |
|
1274 | { | |
1278 | impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos); |
|
1275 | impl->m_DrawingZoomRect->bottomRight->setCoords(axisPos); | |
1279 | } |
|
1276 | } | |
1280 | else if (impl->m_DrawingZone) |
|
1277 | else if (impl->m_DrawingZone) | |
1281 | { |
|
1278 | { | |
1282 | impl->m_DrawingZone->setEnd(axisPos.x()); |
|
1279 | impl->m_DrawingZone->setEnd(axisPos.x()); | |
1283 | } |
|
1280 | } | |
1284 |
|
1281 | |||
1285 | // Cursor |
|
1282 | // Cursor | |
1286 | if (auto parentZone = parentZoneWidget()) |
|
1283 | if (auto parentZone = parentZoneWidget()) | |
1287 | { |
|
1284 | { | |
1288 | if (impl->pointIsInAxisRect(axisPos, plot())) |
|
1285 | if (impl->pointIsInAxisRect(axisPos, plot())) | |
1289 | { |
|
1286 | { | |
1290 | parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this); |
|
1287 | parentZone->notifyMouseMoveInGraph(event->pos(), axisPos, this); | |
1291 | } |
|
1288 | } | |
1292 | else |
|
1289 | else | |
1293 | { |
|
1290 | { | |
1294 | parentZone->notifyMouseLeaveGraph(this); |
|
1291 | parentZone->notifyMouseLeaveGraph(this); | |
1295 | } |
|
1292 | } | |
1296 | } |
|
1293 | } | |
1297 |
|
1294 | |||
1298 | // Search for the selection zone under the mouse |
|
1295 | // Search for the selection zone under the mouse | |
1299 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos()); |
|
1296 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos()); | |
1300 | if (selectionZoneItemUnderCursor && !impl->m_DrawingZone |
|
1297 | if (selectionZoneItemUnderCursor && !impl->m_DrawingZone | |
1301 | && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) |
|
1298 | && sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones) | |
1302 | { |
|
1299 | { | |
1303 |
|
1300 | |||
1304 | // Sets the appropriate cursor shape |
|
1301 | // Sets the appropriate cursor shape | |
1305 | auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos()); |
|
1302 | auto cursorShape = selectionZoneItemUnderCursor->curshorShapeForPosition(event->pos()); | |
1306 | setCursor(cursorShape); |
|
1303 | setCursor(cursorShape); | |
1307 |
|
1304 | |||
1308 | // Manages the hovered zone |
|
1305 | // Manages the hovered zone | |
1309 | if (selectionZoneItemUnderCursor != impl->m_HoveredZone) |
|
1306 | if (selectionZoneItemUnderCursor != impl->m_HoveredZone) | |
1310 | { |
|
1307 | { | |
1311 | if (impl->m_HoveredZone) |
|
1308 | if (impl->m_HoveredZone) | |
1312 | { |
|
1309 | { | |
1313 | impl->m_HoveredZone->setHovered(false); |
|
1310 | impl->m_HoveredZone->setHovered(false); | |
1314 | } |
|
1311 | } | |
1315 | selectionZoneItemUnderCursor->setHovered(true); |
|
1312 | selectionZoneItemUnderCursor->setHovered(true); | |
1316 | impl->m_HoveredZone = selectionZoneItemUnderCursor; |
|
1313 | impl->m_HoveredZone = selectionZoneItemUnderCursor; | |
1317 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
1314 | plot().replot(QCustomPlot::rpQueuedReplot); | |
1318 | } |
|
1315 | } | |
1319 | } |
|
1316 | } | |
1320 | else |
|
1317 | else | |
1321 | { |
|
1318 | { | |
1322 | // There is no zone under the mouse or the interaction mode is not "selection zones" |
|
1319 | // There is no zone under the mouse or the interaction mode is not "selection zones" | |
1323 | if (impl->m_HoveredZone) |
|
1320 | if (impl->m_HoveredZone) | |
1324 | { |
|
1321 | { | |
1325 | impl->m_HoveredZone->setHovered(false); |
|
1322 | impl->m_HoveredZone->setHovered(false); | |
1326 | impl->m_HoveredZone = nullptr; |
|
1323 | impl->m_HoveredZone = nullptr; | |
1327 | } |
|
1324 | } | |
1328 |
|
1325 | |||
1329 | setCursor(Qt::ArrowCursor); |
|
1326 | setCursor(Qt::ArrowCursor); | |
1330 | } |
|
1327 | } | |
1331 |
|
1328 | |||
1332 | impl->m_HasMovedMouse = true; |
|
1329 | impl->m_HasMovedMouse = true; | |
1333 | VisualizationDragWidget::mouseMoveEvent(event); |
|
1330 | VisualizationDragWidget::mouseMoveEvent(event); | |
1334 | } |
|
1331 | } | |
1335 |
|
1332 | |||
1336 | void VisualizationGraphWidget::onMouseWheel(QWheelEvent* event) noexcept |
|
1333 | void VisualizationGraphWidget::onMouseWheel(QWheelEvent* event) noexcept | |
1337 | { |
|
1334 | { | |
1338 | // Processes event only if the wheel occurs on axis rect |
|
1335 | // Processes event only if the wheel occurs on axis rect | |
1339 | if (!dynamic_cast<QCPAxisRect*>(impl->m_plot->layoutElementAt(event->posF()))) |
|
1336 | if (!dynamic_cast<QCPAxisRect*>(impl->m_plot->layoutElementAt(event->posF()))) | |
1340 | { |
|
1337 | { | |
1341 | return; |
|
1338 | return; | |
1342 | } |
|
1339 | } | |
1343 |
|
1340 | |||
1344 | auto value = event->angleDelta().x() + event->angleDelta().y(); |
|
1341 | auto value = event->angleDelta().x() + event->angleDelta().y(); | |
1345 | if (value != 0) |
|
1342 | if (value != 0) | |
1346 | { |
|
1343 | { | |
1347 |
|
1344 | |||
1348 | auto direction = value > 0 ? 1.0 : -1.0; |
|
1345 | auto direction = value > 0 ? 1.0 : -1.0; | |
1349 | auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER); |
|
1346 | auto isZoomX = event->modifiers().testFlag(HORIZONTAL_ZOOM_MODIFIER); | |
1350 | auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER); |
|
1347 | auto isZoomY = event->modifiers().testFlag(VERTICAL_ZOOM_MODIFIER); | |
1351 | impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER); |
|
1348 | impl->m_IsCalibration = event->modifiers().testFlag(VERTICAL_PAN_MODIFIER); | |
1352 |
|
1349 | |||
1353 | auto zoomOrientations = QFlags<Qt::Orientation> {}; |
|
1350 | auto zoomOrientations = QFlags<Qt::Orientation> {}; | |
1354 | zoomOrientations.setFlag(Qt::Horizontal, isZoomX); |
|
1351 | zoomOrientations.setFlag(Qt::Horizontal, isZoomX); | |
1355 | zoomOrientations.setFlag(Qt::Vertical, isZoomY); |
|
1352 | zoomOrientations.setFlag(Qt::Vertical, isZoomY); | |
1356 |
|
1353 | |||
1357 | impl->m_plot->axisRect()->setRangeZoom(zoomOrientations); |
|
1354 | impl->m_plot->axisRect()->setRangeZoom(zoomOrientations); | |
1358 |
|
1355 | |||
1359 | if (!isZoomX && !isZoomY) |
|
1356 | if (!isZoomX && !isZoomY) | |
1360 | { |
|
1357 | { | |
1361 | auto axis = plot().axisRect()->axis(QCPAxis::atBottom); |
|
1358 | auto axis = plot().axisRect()->axis(QCPAxis::atBottom); | |
1362 | auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0)); |
|
1359 | auto diff = direction * (axis->range().size() * (PAN_SPEED / 100.0)); | |
1363 |
|
1360 | |||
1364 | axis->setRange(axis->range() + diff); |
|
1361 | axis->setRange(axis->range() + diff); | |
1365 |
|
1362 | |||
1366 | if (plot().noAntialiasingOnDrag()) |
|
1363 | if (plot().noAntialiasingOnDrag()) | |
1367 | { |
|
1364 | { | |
1368 | plot().setNotAntialiasedElements(QCP::aeAll); |
|
1365 | plot().setNotAntialiasedElements(QCP::aeAll); | |
1369 | } |
|
1366 | } | |
1370 |
|
1367 | |||
1371 | // plot().replot(QCustomPlot::rpQueuedReplot); |
|
1368 | // plot().replot(QCustomPlot::rpQueuedReplot); | |
1372 | } |
|
1369 | } | |
1373 | } |
|
1370 | } | |
1374 | } |
|
1371 | } | |
1375 |
|
1372 | |||
1376 | void VisualizationGraphWidget::onMousePress(QMouseEvent* event) noexcept |
|
1373 | void VisualizationGraphWidget::onMousePress(QMouseEvent* event) noexcept | |
1377 | { |
|
1374 | { | |
1378 | auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER); |
|
1375 | auto isDragDropClick = event->modifiers().testFlag(DRAG_DROP_MODIFIER); | |
1379 | auto isSelectionZoneMode |
|
1376 | auto isSelectionZoneMode | |
1380 | = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones; |
|
1377 | = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones; | |
1381 | auto isLeftClick = event->buttons().testFlag(Qt::LeftButton); |
|
1378 | auto isLeftClick = event->buttons().testFlag(Qt::LeftButton); | |
1382 |
|
1379 | |||
1383 | if (!isDragDropClick && isLeftClick) |
|
1380 | if (!isDragDropClick && isLeftClick) | |
1384 | { |
|
1381 | { | |
1385 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) |
|
1382 | if (sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::ZoomBox) | |
1386 | { |
|
1383 | { | |
1387 | // Starts a zoom box |
|
1384 | // Starts a zoom box | |
1388 | impl->startDrawingRect(event->pos()); |
|
1385 | impl->startDrawingRect(event->pos()); | |
1389 | } |
|
1386 | } | |
1390 | else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) |
|
1387 | else if (isSelectionZoneMode && impl->m_DrawingZone == nullptr) | |
1391 | { |
|
1388 | { | |
1392 | // Starts a new selection zone |
|
1389 | // Starts a new selection zone | |
1393 | auto zoneAtPos = impl->selectionZoneAt(event->pos()); |
|
1390 | auto zoneAtPos = impl->selectionZoneAt(event->pos()); | |
1394 | if (!zoneAtPos) |
|
1391 | if (!zoneAtPos) | |
1395 | { |
|
1392 | { | |
1396 | impl->startDrawingZone(event->pos()); |
|
1393 | impl->startDrawingZone(event->pos()); | |
1397 | } |
|
1394 | } | |
1398 | } |
|
1395 | } | |
1399 | } |
|
1396 | } | |
1400 |
|
1397 | |||
1401 |
|
1398 | |||
1402 | // Allows zone edition only in selection zone mode without drag&drop |
|
1399 | // Allows zone edition only in selection zone mode without drag&drop | |
1403 | impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick); |
|
1400 | impl->setSelectionZonesEditionEnabled(isSelectionZoneMode && !isDragDropClick); | |
1404 |
|
1401 | |||
1405 | // Selection / Deselection |
|
1402 | // Selection / Deselection | |
1406 | if (isSelectionZoneMode) |
|
1403 | if (isSelectionZoneMode) | |
1407 | { |
|
1404 | { | |
1408 | auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER); |
|
1405 | auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER); | |
1409 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos()); |
|
1406 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos()); | |
1410 |
|
1407 | |||
1411 |
|
1408 | |||
1412 | if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected() |
|
1409 | if (selectionZoneItemUnderCursor && !selectionZoneItemUnderCursor->selected() | |
1413 | && !isMultiSelectionClick) |
|
1410 | && !isMultiSelectionClick) | |
1414 | { |
|
1411 | { | |
1415 | parentVisualizationWidget()->selectionZoneManager().select( |
|
1412 | parentVisualizationWidget()->selectionZoneManager().select( | |
1416 | { selectionZoneItemUnderCursor }); |
|
1413 | { selectionZoneItemUnderCursor }); | |
1417 | } |
|
1414 | } | |
1418 | else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) |
|
1415 | else if (!selectionZoneItemUnderCursor && !isMultiSelectionClick && isLeftClick) | |
1419 | { |
|
1416 | { | |
1420 | parentVisualizationWidget()->selectionZoneManager().clearSelection(); |
|
1417 | parentVisualizationWidget()->selectionZoneManager().clearSelection(); | |
1421 | } |
|
1418 | } | |
1422 | else |
|
1419 | else | |
1423 | { |
|
1420 | { | |
1424 | // No selection change |
|
1421 | // No selection change | |
1425 | } |
|
1422 | } | |
1426 |
|
1423 | |||
1427 | if (selectionZoneItemUnderCursor && isLeftClick) |
|
1424 | if (selectionZoneItemUnderCursor && isLeftClick) | |
1428 | { |
|
1425 | { | |
1429 | selectionZoneItemUnderCursor->setAssociatedEditedZones( |
|
1426 | selectionZoneItemUnderCursor->setAssociatedEditedZones( | |
1430 | parentVisualizationWidget()->selectionZoneManager().selectedItems()); |
|
1427 | parentVisualizationWidget()->selectionZoneManager().selectedItems()); | |
1431 | } |
|
1428 | } | |
1432 | } |
|
1429 | } | |
1433 |
|
1430 | |||
1434 |
|
1431 | |||
1435 | impl->m_HasMovedMouse = false; |
|
1432 | impl->m_HasMovedMouse = false; | |
1436 | VisualizationDragWidget::mousePressEvent(event); |
|
1433 | VisualizationDragWidget::mousePressEvent(event); | |
1437 | } |
|
1434 | } | |
1438 |
|
1435 | |||
1439 | void VisualizationGraphWidget::onMouseRelease(QMouseEvent* event) noexcept |
|
1436 | void VisualizationGraphWidget::onMouseRelease(QMouseEvent* event) noexcept | |
1440 | { |
|
1437 | { | |
1441 | if (impl->m_DrawingZoomRect) |
|
1438 | if (impl->m_DrawingZoomRect) | |
1442 | { |
|
1439 | { | |
1443 |
|
1440 | |||
1444 | auto axisX = plot().axisRect()->axis(QCPAxis::atBottom); |
|
1441 | auto axisX = plot().axisRect()->axis(QCPAxis::atBottom); | |
1445 | auto axisY = plot().axisRect()->axis(QCPAxis::atLeft); |
|
1442 | auto axisY = plot().axisRect()->axis(QCPAxis::atLeft); | |
1446 |
|
1443 | |||
1447 | auto newAxisXRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().x(), |
|
1444 | auto newAxisXRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().x(), | |
1448 | impl->m_DrawingZoomRect->bottomRight->coords().x() }; |
|
1445 | impl->m_DrawingZoomRect->bottomRight->coords().x() }; | |
1449 |
|
1446 | |||
1450 | auto newAxisYRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().y(), |
|
1447 | auto newAxisYRange = QCPRange { impl->m_DrawingZoomRect->topLeft->coords().y(), | |
1451 | impl->m_DrawingZoomRect->bottomRight->coords().y() }; |
|
1448 | impl->m_DrawingZoomRect->bottomRight->coords().y() }; | |
1452 |
|
1449 | |||
1453 | impl->removeDrawingRect(); |
|
1450 | impl->removeDrawingRect(); | |
1454 |
|
1451 | |||
1455 | if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0) |
|
1452 | if (newAxisXRange.size() > axisX->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0) | |
1456 | && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) |
|
1453 | && newAxisYRange.size() > axisY->range().size() * (ZOOM_BOX_MIN_SIZE / 100.0)) | |
1457 | { |
|
1454 | { | |
1458 | impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range())); |
|
1455 | impl->m_ZoomStack.push(qMakePair(axisX->range(), axisY->range())); | |
1459 | axisX->setRange(newAxisXRange); |
|
1456 | axisX->setRange(newAxisXRange); | |
1460 | axisY->setRange(newAxisYRange); |
|
1457 | axisY->setRange(newAxisYRange); | |
1461 |
|
1458 | |||
1462 | plot().replot(QCustomPlot::rpQueuedReplot); |
|
1459 | plot().replot(QCustomPlot::rpQueuedReplot); | |
1463 | } |
|
1460 | } | |
1464 | } |
|
1461 | } | |
1465 |
|
1462 | |||
1466 | impl->endDrawingZone(); |
|
1463 | impl->endDrawingZone(); | |
1467 |
|
1464 | |||
1468 | // Selection / Deselection |
|
1465 | // Selection / Deselection | |
1469 | auto isSelectionZoneMode |
|
1466 | auto isSelectionZoneMode | |
1470 | = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones; |
|
1467 | = sqpApp->plotsInteractionMode() == SqpApplication::PlotsInteractionMode::SelectionZones; | |
1471 | if (isSelectionZoneMode) |
|
1468 | if (isSelectionZoneMode) | |
1472 | { |
|
1469 | { | |
1473 | auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER); |
|
1470 | auto isMultiSelectionClick = event->modifiers().testFlag(MULTI_ZONE_SELECTION_MODIFIER); | |
1474 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos()); |
|
1471 | auto selectionZoneItemUnderCursor = impl->selectionZoneAt(event->pos()); | |
1475 | if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton |
|
1472 | if (selectionZoneItemUnderCursor && event->button() == Qt::LeftButton | |
1476 | && !impl->m_HasMovedMouse) |
|
1473 | && !impl->m_HasMovedMouse) | |
1477 | { |
|
1474 | { | |
1478 |
|
1475 | |||
1479 | auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot()); |
|
1476 | auto zonesUnderCursor = impl->selectionZonesAt(event->pos(), plot()); | |
1480 | if (zonesUnderCursor.count() > 1) |
|
1477 | if (zonesUnderCursor.count() > 1) | |
1481 | { |
|
1478 | { | |
1482 | // There are multiple zones under the mouse. |
|
1479 | // There are multiple zones under the mouse. | |
1483 | // Performs the selection with a selection dialog. |
|
1480 | // Performs the selection with a selection dialog. | |
1484 | VisualizationMultiZoneSelectionDialog dialog { this }; |
|
1481 | VisualizationMultiZoneSelectionDialog dialog { this }; | |
1485 | dialog.setZones(zonesUnderCursor); |
|
1482 | dialog.setZones(zonesUnderCursor); | |
1486 | dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20))); |
|
1483 | dialog.move(mapToGlobal(event->pos() - QPoint(dialog.width() / 2, 20))); | |
1487 | dialog.activateWindow(); |
|
1484 | dialog.activateWindow(); | |
1488 | dialog.raise(); |
|
1485 | dialog.raise(); | |
1489 | if (dialog.exec() == QDialog::Accepted) |
|
1486 | if (dialog.exec() == QDialog::Accepted) | |
1490 | { |
|
1487 | { | |
1491 | auto selection = dialog.selectedZones(); |
|
1488 | auto selection = dialog.selectedZones(); | |
1492 |
|
1489 | |||
1493 | if (!isMultiSelectionClick) |
|
1490 | if (!isMultiSelectionClick) | |
1494 | { |
|
1491 | { | |
1495 | parentVisualizationWidget()->selectionZoneManager().clearSelection(); |
|
1492 | parentVisualizationWidget()->selectionZoneManager().clearSelection(); | |
1496 | } |
|
1493 | } | |
1497 |
|
1494 | |||
1498 | for (auto it = selection.cbegin(); it != selection.cend(); ++it) |
|
1495 | for (auto it = selection.cbegin(); it != selection.cend(); ++it) | |
1499 | { |
|
1496 | { | |
1500 | auto zone = it.key(); |
|
1497 | auto zone = it.key(); | |
1501 | auto isSelected = it.value(); |
|
1498 | auto isSelected = it.value(); | |
1502 | parentVisualizationWidget()->selectionZoneManager().setSelected( |
|
1499 | parentVisualizationWidget()->selectionZoneManager().setSelected( | |
1503 | zone, isSelected); |
|
1500 | zone, isSelected); | |
1504 |
|
1501 | |||
1505 | if (isSelected) |
|
1502 | if (isSelected) | |
1506 | { |
|
1503 | { | |
1507 | // Puts the zone on top of the stack so it can be moved or resized |
|
1504 | // Puts the zone on top of the stack so it can be moved or resized | |
1508 | impl->moveSelectionZoneOnTop(zone, plot()); |
|
1505 | impl->moveSelectionZoneOnTop(zone, plot()); | |
1509 | } |
|
1506 | } | |
1510 | } |
|
1507 | } | |
1511 | } |
|
1508 | } | |
1512 | } |
|
1509 | } | |
1513 | else |
|
1510 | else | |
1514 | { |
|
1511 | { | |
1515 | if (!isMultiSelectionClick) |
|
1512 | if (!isMultiSelectionClick) | |
1516 | { |
|
1513 | { | |
1517 | parentVisualizationWidget()->selectionZoneManager().select( |
|
1514 | parentVisualizationWidget()->selectionZoneManager().select( | |
1518 | { selectionZoneItemUnderCursor }); |
|
1515 | { selectionZoneItemUnderCursor }); | |
1519 | impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot()); |
|
1516 | impl->moveSelectionZoneOnTop(selectionZoneItemUnderCursor, plot()); | |
1520 | } |
|
1517 | } | |
1521 | else |
|
1518 | else | |
1522 | { |
|
1519 | { | |
1523 | parentVisualizationWidget()->selectionZoneManager().setSelected( |
|
1520 | parentVisualizationWidget()->selectionZoneManager().setSelected( | |
1524 | selectionZoneItemUnderCursor, |
|
1521 | selectionZoneItemUnderCursor, | |
1525 | !selectionZoneItemUnderCursor->selected() |
|
1522 | !selectionZoneItemUnderCursor->selected() | |
1526 | || event->button() == Qt::RightButton); |
|
1523 | || event->button() == Qt::RightButton); | |
1527 | } |
|
1524 | } | |
1528 | } |
|
1525 | } | |
1529 | } |
|
1526 | } | |
1530 | else |
|
1527 | else | |
1531 | { |
|
1528 | { | |
1532 | // No selection change |
|
1529 | // No selection change | |
1533 | } |
|
1530 | } | |
1534 | } |
|
1531 | } | |
1535 | } |
|
1532 | } | |
1536 |
|
1533 | |||
1537 | void VisualizationGraphWidget::onDataCacheVariableUpdated() |
|
1534 | void VisualizationGraphWidget::onDataCacheVariableUpdated() | |
1538 | { |
|
1535 | { | |
1539 | auto graphRange = impl->m_plot->xAxis->range(); |
|
1536 | auto graphRange = impl->m_plot->xAxis->range(); | |
1540 | auto dateTime = DateTimeRange { graphRange.lower, graphRange.upper }; |
|
1537 | auto dateTime = DateTimeRange { graphRange.lower, graphRange.upper }; | |
1541 |
|
1538 | |||
1542 | for (auto& variableEntry : impl->m_VariableToPlotMultiMap) |
|
1539 | for (auto& variableEntry : impl->m_VariableToPlotMultiMap) | |
1543 | { |
|
1540 | { | |
1544 | auto variable = variableEntry.first; |
|
1541 | auto variable = variableEntry.first; | |
1545 | qCDebug(LOG_VisualizationGraphWidget()) |
|
1542 | qCDebug(LOG_VisualizationGraphWidget()) | |
1546 | << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range(); |
|
1543 | << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range(); | |
1547 | qCDebug(LOG_VisualizationGraphWidget()) |
|
1544 | qCDebug(LOG_VisualizationGraphWidget()) | |
1548 | << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime; |
|
1545 | << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime; | |
1549 | if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) |
|
1546 | if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) | |
1550 | { |
|
1547 | { | |
1551 | impl->updateData(variableEntry.second, variable, variable->range()); |
|
1548 | impl->updateData(variableEntry.second, variable, variable->range()); | |
1552 | } |
|
1549 | } | |
1553 | } |
|
1550 | } | |
1554 | } |
|
1551 | } | |
1555 |
|
1552 | |||
1556 | void VisualizationGraphWidget::onUpdateVarDisplaying( |
|
1553 | void VisualizationGraphWidget::onUpdateVarDisplaying( | |
1557 | std::shared_ptr<Variable2> variable, const DateTimeRange& range) |
|
1554 | std::shared_ptr<Variable2> variable, const DateTimeRange& range) | |
1558 | { |
|
1555 | { | |
1559 | auto it = impl->m_VariableToPlotMultiMap.find(variable); |
|
1556 | auto it = impl->m_VariableToPlotMultiMap.find(variable); | |
1560 | if (it != impl->m_VariableToPlotMultiMap.end()) |
|
1557 | if (it != impl->m_VariableToPlotMultiMap.end()) | |
1561 | { |
|
1558 | { | |
1562 | impl->updateData(it->second, variable, range); |
|
1559 | impl->updateData(it->second, variable, range); | |
1563 | } |
|
1560 | } | |
1564 | } |
|
1561 | } | |
1565 |
|
1562 | |||
1566 | void VisualizationGraphWidget::variableUpdated(QUuid id) |
|
1563 | void VisualizationGraphWidget::variableUpdated(QUuid id) | |
1567 | { |
|
1564 | { | |
1568 | for (auto& [var, plotables] : impl->m_VariableToPlotMultiMap) |
|
1565 | for (auto& [var, plotables] : impl->m_VariableToPlotMultiMap) | |
1569 | { |
|
1566 | { | |
1570 | if (var->ID() == id) |
|
1567 | if (var->ID() == id) | |
1571 | { |
|
1568 | { | |
1572 | impl->updateData(plotables, var, this->graphRange()); |
|
1569 | impl->updateData(plotables, var, this->graphRange()); | |
1573 | } |
|
1570 | } | |
1574 | } |
|
1571 | } | |
1575 | } |
|
1572 | } | |
1576 |
|
1573 | |||
1577 | void VisualizationGraphWidget::variableDeleted(const std::shared_ptr<Variable2>& variable) |
|
1574 | void VisualizationGraphWidget::variableDeleted(const std::shared_ptr<Variable2>& variable) | |
1578 | { |
|
1575 | { | |
1579 | this->removeVariable(variable); |
|
1576 | this->removeVariable(variable); | |
1580 | } |
|
1577 | } |
@@ -1,172 +1,171 | |||||
1 | #ifndef GUITESTUTILS_H |
|
1 | #ifndef GUITESTUTILS_H | |
2 | #define GUITESTUTILS_H |
|
2 | #define GUITESTUTILS_H | |
3 |
|
3 | |||
4 | #include <Common/cpp_utils.h> |
|
4 | #include <Common/cpp_utils.h> | |
5 | #include <QCoreApplication> |
|
5 | #include <QCoreApplication> | |
6 | #include <QCursor> |
|
6 | #include <QCursor> | |
7 | #include <QDesktopWidget> |
|
7 | #include <QDesktopWidget> | |
8 | #include <QMouseEvent> |
|
8 | #include <QMouseEvent> | |
9 | #include <QPoint> |
|
9 | #include <QPoint> | |
10 | #include <QtTest> |
|
10 | #include <QtTest> | |
11 |
|
11 | |||
12 | #include <SqpApplication.h> |
|
12 | #include <SqpApplication.h> | |
13 | #include <Variable/Variable.h> |
|
|||
14 | #include <Variable/VariableController2.h> |
|
13 | #include <Variable/VariableController2.h> | |
15 | #include <qcustomplot.h> |
|
14 | #include <qcustomplot.h> | |
16 |
|
15 | |||
17 | template <typename T> |
|
16 | template <typename T> | |
18 | QPoint center(T* widget) |
|
17 | QPoint center(T* widget) | |
19 | { |
|
18 | { | |
20 | return QPoint { widget->width() / 2, widget->height() / 2 }; |
|
19 | return QPoint { widget->width() / 2, widget->height() / 2 }; | |
21 | } |
|
20 | } | |
22 |
|
21 | |||
23 | HAS_METHOD(viewport) |
|
22 | HAS_METHOD(viewport) | |
24 |
|
23 | |||
25 | template <typename T> |
|
24 | template <typename T> | |
26 | static inline constexpr bool is_QWidgetOrDerived = std::is_base_of<QWidget, T>::value; |
|
25 | static inline constexpr bool is_QWidgetOrDerived = std::is_base_of<QWidget, T>::value; | |
27 |
|
26 | |||
28 | template <typename T> |
|
27 | template <typename T> | |
29 | using viewport_type = decltype(std::declval<T>().viewport()); |
|
28 | using viewport_type = decltype(std::declval<T>().viewport()); | |
30 |
|
29 | |||
31 | HAS_METHOD(topLevelItem) |
|
30 | HAS_METHOD(topLevelItem) | |
32 |
|
31 | |||
33 | template <typename T> |
|
32 | template <typename T> | |
34 | void mouseMove(T* widget, QPoint pos, Qt::MouseButton mouseModifier) |
|
33 | void mouseMove(T* widget, QPoint pos, Qt::MouseButton mouseModifier) | |
35 | { |
|
34 | { | |
36 | QCursor::setPos(widget->mapToGlobal(pos)); |
|
35 | QCursor::setPos(widget->mapToGlobal(pos)); | |
37 | QMouseEvent event(QEvent::MouseMove, pos, Qt::NoButton, mouseModifier, Qt::NoModifier); |
|
36 | QMouseEvent event(QEvent::MouseMove, pos, Qt::NoButton, mouseModifier, Qt::NoModifier); | |
38 | if constexpr (has_viewport<T>) |
|
37 | if constexpr (has_viewport<T>) | |
39 | { |
|
38 | { | |
40 | if constexpr (is_QWidgetOrDerived<viewport_type<T>>) |
|
39 | if constexpr (is_QWidgetOrDerived<viewport_type<T>>) | |
41 | { |
|
40 | { | |
42 | qApp->sendEvent(widget->viewport(), &event); |
|
41 | qApp->sendEvent(widget->viewport(), &event); | |
43 | } |
|
42 | } | |
44 | else |
|
43 | else | |
45 | { |
|
44 | { | |
46 | qApp->sendEvent(widget, &event); |
|
45 | qApp->sendEvent(widget, &event); | |
47 | } |
|
46 | } | |
48 | } |
|
47 | } | |
49 | else |
|
48 | else | |
50 | { |
|
49 | { | |
51 | qApp->sendEvent(widget, &event); |
|
50 | qApp->sendEvent(widget, &event); | |
52 | } |
|
51 | } | |
53 | qApp->processEvents(); |
|
52 | qApp->processEvents(); | |
54 | } |
|
53 | } | |
55 |
|
54 | |||
56 |
|
55 | |||
57 | template <typename T> |
|
56 | template <typename T> | |
58 | void setMouseTracking(T* widget) |
|
57 | void setMouseTracking(T* widget) | |
59 | { |
|
58 | { | |
60 | if constexpr (has_viewport<T>) |
|
59 | if constexpr (has_viewport<T>) | |
61 | { |
|
60 | { | |
62 | if constexpr (is_QWidgetOrDerived<viewport_type<T>>) |
|
61 | if constexpr (is_QWidgetOrDerived<viewport_type<T>>) | |
63 | { |
|
62 | { | |
64 | widget->viewport()->setMouseTracking(true); |
|
63 | widget->viewport()->setMouseTracking(true); | |
65 | } |
|
64 | } | |
66 | else |
|
65 | else | |
67 | { |
|
66 | { | |
68 | widget->setMouseTracking(true); |
|
67 | widget->setMouseTracking(true); | |
69 | } |
|
68 | } | |
70 | } |
|
69 | } | |
71 | else |
|
70 | else | |
72 | { |
|
71 | { | |
73 | widget->setMouseTracking(true); |
|
72 | widget->setMouseTracking(true); | |
74 | } |
|
73 | } | |
75 | } |
|
74 | } | |
76 |
|
75 | |||
77 | template <typename T, typename T2> |
|
76 | template <typename T, typename T2> | |
78 | auto getItem(T* widget, T2 itemIndex) |
|
77 | auto getItem(T* widget, T2 itemIndex) | |
79 | { |
|
78 | { | |
80 | if constexpr (has_topLevelItem<T>) |
|
79 | if constexpr (has_topLevelItem<T>) | |
81 | { |
|
80 | { | |
82 | return widget->topLevelItem(itemIndex); |
|
81 | return widget->topLevelItem(itemIndex); | |
83 | } |
|
82 | } | |
84 | else |
|
83 | else | |
85 | { |
|
84 | { | |
86 | return widget->item(itemIndex); |
|
85 | return widget->item(itemIndex); | |
87 | } |
|
86 | } | |
88 | } |
|
87 | } | |
89 |
|
88 | |||
90 | #define SELECT_ITEM(widget, itemIndex, item) \ |
|
89 | #define SELECT_ITEM(widget, itemIndex, item) \ | |
91 | auto item = getItem(widget, itemIndex); \ |
|
90 | auto item = getItem(widget, itemIndex); \ | |
92 | { \ |
|
91 | { \ | |
93 | auto itemCenterPos = widget->visualItemRect(item).center(); \ |
|
92 | auto itemCenterPos = widget->visualItemRect(item).center(); \ | |
94 | QTest::mouseClick(widget->viewport(), Qt::LeftButton, Qt::NoModifier, itemCenterPos); \ |
|
93 | QTest::mouseClick(widget->viewport(), Qt::LeftButton, Qt::NoModifier, itemCenterPos); \ | |
95 | QVERIFY(widget->selectedItems().size() > 0); \ |
|
94 | QVERIFY(widget->selectedItems().size() > 0); \ | |
96 | QVERIFY(widget->selectedItems().contains(item)); \ |
|
95 | QVERIFY(widget->selectedItems().contains(item)); \ | |
97 | } |
|
96 | } | |
98 |
|
97 | |||
99 |
|
98 | |||
100 | #define GET_CHILD_WIDGET_FOR_GUI_TESTS(parent, child, childType, childName) \ |
|
99 | #define GET_CHILD_WIDGET_FOR_GUI_TESTS(parent, child, childType, childName) \ | |
101 | childType* child = parent.findChild<childType*>(childName); \ |
|
100 | childType* child = parent.findChild<childType*>(childName); \ | |
102 | QVERIFY(child != Q_NULLPTR); \ |
|
101 | QVERIFY(child != Q_NULLPTR); \ | |
103 | setMouseTracking(child); |
|
102 | setMouseTracking(child); | |
104 |
|
103 | |||
105 | template <typename T1, typename T2, typename T3, typename T4 = void> |
|
104 | template <typename T1, typename T2, typename T3, typename T4 = void> | |
106 | void dragnDropItem(T1* sourceWidget, T2* destWidget, T3* item, T4* destItem = Q_NULLPTR) |
|
105 | void dragnDropItem(T1* sourceWidget, T2* destWidget, T3* item, T4* destItem = Q_NULLPTR) | |
107 | { |
|
106 | { | |
108 | auto itemCenterPos = sourceWidget->visualItemRect(item).center(); |
|
107 | auto itemCenterPos = sourceWidget->visualItemRect(item).center(); | |
109 | if constexpr (has_viewport<T1>) |
|
108 | if constexpr (has_viewport<T1>) | |
110 | { |
|
109 | { | |
111 | QTest::mousePress(sourceWidget->viewport(), Qt::LeftButton, Qt::NoModifier, itemCenterPos); |
|
110 | QTest::mousePress(sourceWidget->viewport(), Qt::LeftButton, Qt::NoModifier, itemCenterPos); | |
112 | } |
|
111 | } | |
113 | else |
|
112 | else | |
114 | { |
|
113 | { | |
115 | QTest::mousePress(sourceWidget, Qt::LeftButton, Qt::NoModifier, itemCenterPos); |
|
114 | QTest::mousePress(sourceWidget, Qt::LeftButton, Qt::NoModifier, itemCenterPos); | |
116 | } |
|
115 | } | |
117 | mouseMove(sourceWidget, itemCenterPos, Qt::LeftButton); |
|
116 | mouseMove(sourceWidget, itemCenterPos, Qt::LeftButton); | |
118 | itemCenterPos += QPoint(0, -10); |
|
117 | itemCenterPos += QPoint(0, -10); | |
119 | QTimer::singleShot(100, [destWidget, destItem]() { |
|
118 | QTimer::singleShot(100, [destWidget, destItem]() { | |
120 | mouseMove(destWidget, destWidget->rect().center(), Qt::LeftButton); |
|
119 | mouseMove(destWidget, destWidget->rect().center(), Qt::LeftButton); | |
121 | mouseMove(destWidget, destWidget->rect().center() + QPoint(0, -10), Qt::LeftButton); |
|
120 | mouseMove(destWidget, destWidget->rect().center() + QPoint(0, -10), Qt::LeftButton); | |
122 | if constexpr (!std::is_same_v<void, T4>) |
|
121 | if constexpr (!std::is_same_v<void, T4>) | |
123 | { |
|
122 | { | |
124 | auto destItemCenterPos = destWidget->visualItemRect(destItem).center(); |
|
123 | auto destItemCenterPos = destWidget->visualItemRect(destItem).center(); | |
125 | QTest::mouseRelease(destWidget, Qt::LeftButton, Qt::NoModifier, destItemCenterPos); |
|
124 | QTest::mouseRelease(destWidget, Qt::LeftButton, Qt::NoModifier, destItemCenterPos); | |
126 | } |
|
125 | } | |
127 | else if constexpr (has_viewport<T2>) |
|
126 | else if constexpr (has_viewport<T2>) | |
128 | { |
|
127 | { | |
129 | QTest::mouseRelease(destWidget->viewport(), Qt::LeftButton); |
|
128 | QTest::mouseRelease(destWidget->viewport(), Qt::LeftButton); | |
130 | } |
|
129 | } | |
131 | else |
|
130 | else | |
132 | { |
|
131 | { | |
133 | QTest::mouseRelease(destWidget, Qt::LeftButton); |
|
132 | QTest::mouseRelease(destWidget, Qt::LeftButton); | |
134 | } |
|
133 | } | |
135 | QTest::mouseRelease(destWidget->viewport(), Qt::LeftButton); |
|
134 | QTest::mouseRelease(destWidget->viewport(), Qt::LeftButton); | |
136 | }); |
|
135 | }); | |
137 | mouseMove(sourceWidget, itemCenterPos, Qt::LeftButton); |
|
136 | mouseMove(sourceWidget, itemCenterPos, Qt::LeftButton); | |
138 | } |
|
137 | } | |
139 |
|
138 | |||
140 | template <typename T> |
|
139 | template <typename T> | |
141 | void scroll_graph(T* w, int dx) |
|
140 | void scroll_graph(T* w, int dx) | |
142 | { |
|
141 | { | |
143 | auto cent = center(w); |
|
142 | auto cent = center(w); | |
144 | QTest::mousePress(w, Qt::LeftButton, Qt::NoModifier, cent, 1); |
|
143 | QTest::mousePress(w, Qt::LeftButton, Qt::NoModifier, cent, 1); | |
145 | mouseMove(w, { cent.x() + dx, cent.y() }, Qt::LeftButton); |
|
144 | mouseMove(w, { cent.x() + dx, cent.y() }, Qt::LeftButton); | |
146 | QTest::mouseRelease(w, Qt::LeftButton); |
|
145 | QTest::mouseRelease(w, Qt::LeftButton); | |
147 | } |
|
146 | } | |
148 |
|
147 | |||
149 | ALIAS_TEMPLATE_FUNCTION(isReady, static_cast<SqpApplication*>(qApp)->variableController().isReady) |
|
148 | ALIAS_TEMPLATE_FUNCTION(isReady, static_cast<SqpApplication*>(qApp)->variableController().isReady) | |
150 |
|
149 | |||
151 | void waitForVar(std::shared_ptr<Variable2> var) |
|
150 | void waitForVar(std::shared_ptr<Variable2> var) | |
152 | { |
|
151 | { | |
153 | while (!isReady(var)) |
|
152 | while (!isReady(var)) | |
154 | QCoreApplication::processEvents(); |
|
153 | QCoreApplication::processEvents(); | |
155 | } |
|
154 | } | |
156 |
|
155 | |||
157 | template <typename T> |
|
156 | template <typename T> | |
158 | bool prepare_gui_test(T* w) |
|
157 | bool prepare_gui_test(T* w) | |
159 | { |
|
158 | { | |
160 | w->setGeometry(QRect( |
|
159 | w->setGeometry(QRect( | |
161 | QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), QSize(500, 500))); |
|
160 | QPoint(QApplication::desktop()->geometry().center() - QPoint(250, 250)), QSize(500, 500))); | |
162 | w->show(); |
|
161 | w->show(); | |
163 | qApp->setActiveWindow(w); |
|
162 | qApp->setActiveWindow(w); | |
164 | return QTest::qWaitForWindowActive(w); |
|
163 | return QTest::qWaitForWindowActive(w); | |
165 | } |
|
164 | } | |
166 |
|
165 | |||
167 | #define GET_CHILD_WIDGET_FOR_GUI_TESTS(parent, child, childType, childName) \ |
|
166 | #define GET_CHILD_WIDGET_FOR_GUI_TESTS(parent, child, childType, childName) \ | |
168 | childType* child = parent.findChild<childType*>(childName); \ |
|
167 | childType* child = parent.findChild<childType*>(childName); \ | |
169 | QVERIFY(child != Q_NULLPTR); \ |
|
168 | QVERIFY(child != Q_NULLPTR); \ | |
170 | setMouseTracking(child); |
|
169 | setMouseTracking(child); | |
171 |
|
170 | |||
172 | #endif |
|
171 | #endif |
General Comments 0
You need to be logged in to leave comments.
Login now