##// END OF EJS Templates
Merge pull request 277 from SCIQLOP-Initialisation develop...
leroux -
r732:0a8146754a94 merge
parent child
Show More
@@ -0,0 +1,24
1 #ifndef SCIQLOP_IGRAPHSYNCHRONIZER_H
2 #define SCIQLOP_IGRAPHSYNCHRONIZER_H
3
4 class VisualizationGraphWidget;
5
6 /**
7 * @brief The IVisualizationSynchronizer interface represents a delegate used to manage the
8 * synchronization between graphs, applying them processes or properties to ensure their
9 * synchronization
10 */
11 class IGraphSynchronizer {
12
13 public:
14 virtual ~IGraphSynchronizer() = default;
15
16 /**
17 * Adds a graph as a new synchronized element, and sets its properties so that its
18 * synchronization is maintained with all other graphs managed by the synchonizer
19 * @param graph the graph to add in the synchronization
20 */
21 virtual void addGraph(VisualizationGraphWidget &graph) const = 0;
22 };
23
24 #endif // SCIQLOP_IGRAPHSYNCHRONIZER_H
@@ -0,0 +1,26
1 #ifndef SCIQLOP_QCUSTOMPLOTSYNCHRONIZER_H
2 #define SCIQLOP_QCUSTOMPLOTSYNCHRONIZER_H
3
4 #include "Visualization/IGraphSynchronizer.h"
5
6 #include <Common/spimpl.h>
7
8 /**
9 * @brief The QCustomPlotSynchronizer class is an implementation of IGraphSynchronizer that handles
10 * graphs using QCustomPlot elements
11 * @sa IGraphSynchronizer
12 * @sa QCustomPlot
13 */
14 class QCustomPlotSynchronizer : public IGraphSynchronizer {
15 public:
16 explicit QCustomPlotSynchronizer();
17
18 /// @sa IGraphSynchronizer::addGraph()
19 virtual void addGraph(VisualizationGraphWidget &graph) const override;
20
21 private:
22 class QCustomPlotSynchronizerPrivate;
23 spimpl::unique_impl_ptr<QCustomPlotSynchronizerPrivate> impl;
24 };
25
26 #endif // SCIQLOP_QCUSTOMPLOTSYNCHRONIZER_H
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
1 NO CONTENT: new file 100644, binary diff hidden
NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,30
1 #include "Visualization/QCustomPlotSynchronizer.h"
2
3 #include "Visualization/VisualizationGraphWidget.h"
4 #include "Visualization/qcustomplot.h"
5
6 struct QCustomPlotSynchronizer::QCustomPlotSynchronizerPrivate {
7 explicit QCustomPlotSynchronizerPrivate()
8 : m_MarginGroup{std::make_unique<QCPMarginGroup>(nullptr)}
9 {
10 }
11
12 /// Sets the same margin sides for all added plot elements
13 std::unique_ptr<QCPMarginGroup> m_MarginGroup;
14 };
15
16 QCustomPlotSynchronizer::QCustomPlotSynchronizer()
17 : impl{spimpl::make_unique_impl<QCustomPlotSynchronizerPrivate>()}
18 {
19 }
20
21 void QCustomPlotSynchronizer::addGraph(VisualizationGraphWidget &graph) const
22 {
23 // Adds all plot elements of the graph to the margin group: all these elements will then have
24 // the same margin sides
25 auto &plot = graph.plot();
26 for (auto axisRect : plot.axisRects()) {
27 // Sames margin sides at left and right
28 axisRect->setMarginGroup(QCP::msLeft | QCP::msRight, impl->m_MarginGroup.get());
29 }
30 }
@@ -1,20 +1,31
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
2 #define SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
3
3
4 #include <Common/spimpl.h>
4 #include <Common/spimpl.h>
5
5
6 class QCustomPlot;
6 class QCustomPlot;
7 class QMouseEvent;
7 class QMouseEvent;
8 class Unit;
9 class VisualizationGraphWidget;
8
10
9 class VisualizationGraphRenderingDelegate {
11 class VisualizationGraphRenderingDelegate {
10 public:
12 public:
11 explicit VisualizationGraphRenderingDelegate(QCustomPlot &plot);
13 /// Ctor
14 /// @param graphWidget the graph widget to which the delegate is associated
15 /// @remarks the graph widget must exist throughout the life cycle of the delegate
16 explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget);
12
17
13 void onMouseMove(QMouseEvent *event) noexcept;
18 void onMouseMove(QMouseEvent *event) noexcept;
14
19
20 /// Sets properties of the plot's axes
21 void setAxesProperties(const Unit &xAxisUnit, const Unit &valuesUnit) noexcept;
22
23 /// Shows or hides graph overlay (name, close button, etc.)
24 void showGraphOverlay(bool show) noexcept;
25
15 private:
26 private:
16 class VisualizationGraphRenderingDelegatePrivate;
27 class VisualizationGraphRenderingDelegatePrivate;
17 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
28 spimpl::unique_impl_ptr<VisualizationGraphRenderingDelegatePrivate> impl;
18 };
29 };
19
30
20 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
31 #endif // SCIQLOP_VISUALIZATIONGRAPHRENDERINGDELEGATE_H
@@ -1,86 +1,94
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
1 #ifndef SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
2 #define SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
3
3
4 #include "Visualization/IVisualizationWidget.h"
4 #include "Visualization/IVisualizationWidget.h"
5
5
6 #include <QLoggingCategory>
6 #include <QLoggingCategory>
7 #include <QWidget>
7 #include <QWidget>
8
8
9 #include <memory>
9 #include <memory>
10
10
11 #include <Common/spimpl.h>
11 #include <Common/spimpl.h>
12
12
13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
13 Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget)
14
14
15 class QCPRange;
15 class QCPRange;
16 class QCustomPlot;
16 class SqpRange;
17 class SqpRange;
17 class Variable;
18 class Variable;
18
19
19 namespace Ui {
20 namespace Ui {
20 class VisualizationGraphWidget;
21 class VisualizationGraphWidget;
21 } // namespace Ui
22 } // namespace Ui
22
23
23 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 class VisualizationGraphWidget : public QWidget, public IVisualizationWidget {
24 Q_OBJECT
25 Q_OBJECT
25
26
27 friend class QCustomPlotSynchronizer;
28 friend class VisualizationGraphRenderingDelegate;
29
26 public:
30 public:
27 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
31 explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0);
28 virtual ~VisualizationGraphWidget();
32 virtual ~VisualizationGraphWidget();
29
33
30 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
34 /// If acquisition isn't enable, requestDataLoading signal cannot be emit
31 void enableAcquisition(bool enable);
35 void enableAcquisition(bool enable);
32
36
33 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
37 void addVariable(std::shared_ptr<Variable> variable, SqpRange range);
34
38
35 /// Removes a variable from the graph
39 /// Removes a variable from the graph
36 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
40 void removeVariable(std::shared_ptr<Variable> variable) noexcept;
37
41
38 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
42 void setRange(std::shared_ptr<Variable> variable, const SqpRange &range);
39 void setYRange(const SqpRange &range);
43 void setYRange(const SqpRange &range);
40 SqpRange graphRange() const noexcept;
44 SqpRange graphRange() const noexcept;
41 void setGraphRange(const SqpRange &range);
45 void setGraphRange(const SqpRange &range);
42
46
43 // IVisualizationWidget interface
47 // IVisualizationWidget interface
44 void accept(IVisualizationWidgetVisitor *visitor) override;
48 void accept(IVisualizationWidgetVisitor *visitor) override;
45 bool canDrop(const Variable &variable) const override;
49 bool canDrop(const Variable &variable) const override;
46 bool contains(const Variable &variable) const override;
50 bool contains(const Variable &variable) const override;
47 QString name() const override;
51 QString name() const override;
48
52
49
53
50 signals:
54 signals:
51 void synchronize(const SqpRange &range, const SqpRange &oldRange);
55 void synchronize(const SqpRange &range, const SqpRange &oldRange);
52 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
56 void requestDataLoading(QVector<std::shared_ptr<Variable> > variable, const SqpRange &range,
53 const SqpRange &oldRange, bool synchronise);
57 const SqpRange &oldRange, bool synchronise);
54
58
55
56 void variableAdded(std::shared_ptr<Variable> var);
59 void variableAdded(std::shared_ptr<Variable> var);
57
60
61 protected:
62 void enterEvent(QEvent *event) override;
63 void leaveEvent(QEvent *event) override;
64
65 QCustomPlot &plot() noexcept;
58
66
59 private:
67 private:
60 Ui::VisualizationGraphWidget *ui;
68 Ui::VisualizationGraphWidget *ui;
61
69
62 class VisualizationGraphWidgetPrivate;
70 class VisualizationGraphWidgetPrivate;
63 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
71 spimpl::unique_impl_ptr<VisualizationGraphWidgetPrivate> impl;
64
72
65 private slots:
73 private slots:
66 /// Slot called when right clicking on the graph (displays a menu)
74 /// Slot called when right clicking on the graph (displays a menu)
67 void onGraphMenuRequested(const QPoint &pos) noexcept;
75 void onGraphMenuRequested(const QPoint &pos) noexcept;
68
76
69 /// Rescale the X axe to range parameter
77 /// Rescale the X axe to range parameter
70 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
78 void onRangeChanged(const QCPRange &t1, const QCPRange &t2);
71
79
72 /// Slot called when a mouse move was made
80 /// Slot called when a mouse move was made
73 void onMouseMove(QMouseEvent *event) noexcept;
81 void onMouseMove(QMouseEvent *event) noexcept;
74 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
82 /// Slot called when a mouse wheel was made, to perform some processing before the zoom is done
75 void onMouseWheel(QWheelEvent *event) noexcept;
83 void onMouseWheel(QWheelEvent *event) noexcept;
76 /// Slot called when a mouse press was made, to activate the calibration of a graph
84 /// Slot called when a mouse press was made, to activate the calibration of a graph
77 void onMousePress(QMouseEvent *event) noexcept;
85 void onMousePress(QMouseEvent *event) noexcept;
78 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
86 /// Slot called when a mouse release was made, to deactivate the calibration of a graph
79 void onMouseRelease(QMouseEvent *event) noexcept;
87 void onMouseRelease(QMouseEvent *event) noexcept;
80
88
81 void onDataCacheVariableUpdated();
89 void onDataCacheVariableUpdated();
82
90
83 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
91 void onUpdateVarDisplaying(std::shared_ptr<Variable> variable, const SqpRange &range);
84 };
92 };
85
93
86 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
94 #endif // SCIQLOP_VISUALIZATIONGRAPHWIDGET_H
@@ -1,78 +1,79
1
1
2 gui_moc_headers = [
2 gui_moc_headers = [
3 'include/DataSource/DataSourceWidget.h',
3 'include/DataSource/DataSourceWidget.h',
4 'include/Settings/SqpSettingsDialog.h',
4 'include/Settings/SqpSettingsDialog.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
5 'include/Settings/SqpSettingsGeneralWidget.h',
6 'include/SidePane/SqpSidePane.h',
6 'include/SidePane/SqpSidePane.h',
7 'include/SqpApplication.h',
7 'include/SqpApplication.h',
8 'include/TimeWidget/TimeWidget.h',
8 'include/TimeWidget/TimeWidget.h',
9 'include/Variable/VariableInspectorWidget.h',
9 'include/Variable/VariableInspectorWidget.h',
10 'include/Variable/RenameVariableDialog.h',
10 'include/Variable/RenameVariableDialog.h',
11 'include/Visualization/qcustomplot.h',
11 'include/Visualization/qcustomplot.h',
12 'include/Visualization/VisualizationGraphWidget.h',
12 'include/Visualization/VisualizationGraphWidget.h',
13 'include/Visualization/VisualizationTabWidget.h',
13 'include/Visualization/VisualizationTabWidget.h',
14 'include/Visualization/VisualizationWidget.h',
14 'include/Visualization/VisualizationWidget.h',
15 'include/Visualization/VisualizationZoneWidget.h'
15 'include/Visualization/VisualizationZoneWidget.h'
16 ]
16 ]
17
17
18 gui_ui_files = [
18 gui_ui_files = [
19 'ui/DataSource/DataSourceWidget.ui',
19 'ui/DataSource/DataSourceWidget.ui',
20 'ui/Settings/SqpSettingsDialog.ui',
20 'ui/Settings/SqpSettingsDialog.ui',
21 'ui/Settings/SqpSettingsGeneralWidget.ui',
21 'ui/Settings/SqpSettingsGeneralWidget.ui',
22 'ui/SidePane/SqpSidePane.ui',
22 'ui/SidePane/SqpSidePane.ui',
23 'ui/TimeWidget/TimeWidget.ui',
23 'ui/TimeWidget/TimeWidget.ui',
24 'ui/Variable/VariableInspectorWidget.ui',
24 'ui/Variable/VariableInspectorWidget.ui',
25 'ui/Variable/VariableMenuHeaderWidget.ui',
25 'ui/Variable/VariableMenuHeaderWidget.ui',
26 'ui/Variable/RenameVariableDialog.ui',
26 'ui/Variable/RenameVariableDialog.ui',
27 'ui/Visualization/VisualizationGraphWidget.ui',
27 'ui/Visualization/VisualizationGraphWidget.ui',
28 'ui/Visualization/VisualizationTabWidget.ui',
28 'ui/Visualization/VisualizationTabWidget.ui',
29 'ui/Visualization/VisualizationWidget.ui',
29 'ui/Visualization/VisualizationWidget.ui',
30 'ui/Visualization/VisualizationZoneWidget.ui'
30 'ui/Visualization/VisualizationZoneWidget.ui'
31 ]
31 ]
32
32
33 gui_qresources = ['resources/sqpguiresources.qrc']
33 gui_qresources = ['resources/sqpguiresources.qrc']
34
34
35 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
35 gui_moc_files = qt5.preprocess(moc_headers : gui_moc_headers,
36 ui_files : gui_ui_files,
36 ui_files : gui_ui_files,
37 qresources : gui_qresources)
37 qresources : gui_qresources)
38
38
39 gui_sources = [
39 gui_sources = [
40 'src/SqpApplication.cpp',
40 'src/SqpApplication.cpp',
41 'src/Common/ColorUtils.cpp',
41 'src/Common/ColorUtils.cpp',
42 'src/DataSource/DataSourceTreeWidgetItem.cpp',
42 'src/DataSource/DataSourceTreeWidgetItem.cpp',
43 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
43 'src/DataSource/DataSourceTreeWidgetHelper.cpp',
44 'src/DataSource/DataSourceWidget.cpp',
44 'src/DataSource/DataSourceWidget.cpp',
45 'src/Settings/SqpSettingsDialog.cpp',
45 'src/Settings/SqpSettingsDialog.cpp',
46 'src/Settings/SqpSettingsGeneralWidget.cpp',
46 'src/Settings/SqpSettingsGeneralWidget.cpp',
47 'src/SidePane/SqpSidePane.cpp',
47 'src/SidePane/SqpSidePane.cpp',
48 'src/TimeWidget/TimeWidget.cpp',
48 'src/TimeWidget/TimeWidget.cpp',
49 'src/Variable/VariableInspectorWidget.cpp',
49 'src/Variable/VariableInspectorWidget.cpp',
50 'src/Variable/VariableMenuHeaderWidget.cpp',
50 'src/Variable/VariableMenuHeaderWidget.cpp',
51 'src/Variable/RenameVariableDialog.cpp',
51 'src/Variable/RenameVariableDialog.cpp',
52 'src/Visualization/VisualizationGraphHelper.cpp',
52 'src/Visualization/VisualizationGraphHelper.cpp',
53 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
53 'src/Visualization/VisualizationGraphRenderingDelegate.cpp',
54 'src/Visualization/VisualizationGraphWidget.cpp',
54 'src/Visualization/VisualizationGraphWidget.cpp',
55 'src/Visualization/VisualizationTabWidget.cpp',
55 'src/Visualization/VisualizationTabWidget.cpp',
56 'src/Visualization/VisualizationWidget.cpp',
56 'src/Visualization/VisualizationWidget.cpp',
57 'src/Visualization/VisualizationZoneWidget.cpp',
57 'src/Visualization/VisualizationZoneWidget.cpp',
58 'src/Visualization/qcustomplot.cpp',
58 'src/Visualization/qcustomplot.cpp',
59 'src/Visualization/QCustomPlotSynchronizer.cpp',
59 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
60 'src/Visualization/operations/GenerateVariableMenuOperation.cpp',
60 'src/Visualization/operations/MenuBuilder.cpp',
61 'src/Visualization/operations/MenuBuilder.cpp',
61 'src/Visualization/operations/RemoveVariableOperation.cpp',
62 'src/Visualization/operations/RemoveVariableOperation.cpp',
62 'src/Visualization/operations/RescaleAxeOperation.cpp'
63 'src/Visualization/operations/RescaleAxeOperation.cpp'
63 ]
64 ]
64
65
65 gui_inc = include_directories(['include'])
66 gui_inc = include_directories(['include'])
66
67
67 sciqlop_gui_lib = library('sciqlopgui',
68 sciqlop_gui_lib = library('sciqlopgui',
68 gui_sources,
69 gui_sources,
69 gui_moc_files,
70 gui_moc_files,
70 include_directories : [gui_inc],
71 include_directories : [gui_inc],
71 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
72 dependencies : [ qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core],
72 install : true
73 install : true
73 )
74 )
74
75
75 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
76 sciqlop_gui = declare_dependency(link_with : sciqlop_gui_lib,
76 include_directories : gui_inc,
77 include_directories : gui_inc,
77 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
78 dependencies : [qt5printsupport, qt5gui, qt5widgets, qt5svg, sciqlop_core])
78
79
@@ -1,14 +1,16
1 <RCC>
1 <RCC>
2 <qresource prefix="/">
2 <qresource prefix="/">
3 <file>icones/dataSourceComponent.png</file>
3 <file>icones/dataSourceComponent.png</file>
4 <file>icones/dataSourceNode.png</file>
4 <file>icones/dataSourceNode.png</file>
5 <file>icones/dataSourceProduct.png</file>
5 <file>icones/dataSourceProduct.png</file>
6 <file>icones/dataSourceRoot.png</file>
6 <file>icones/dataSourceRoot.png</file>
7 <file>icones/delete.png</file>
7 <file>icones/delete.png</file>
8 <file>icones/down.png</file>
8 <file>icones/openInspector.png</file>
9 <file>icones/openInspector.png</file>
9 <file>icones/next.png</file>
10 <file>icones/next.png</file>
10 <file>icones/plot.png</file>
11 <file>icones/plot.png</file>
11 <file>icones/previous.png</file>
12 <file>icones/previous.png</file>
12 <file>icones/unplot.png</file>
13 <file>icones/unplot.png</file>
14 <file>icones/up.png</file>
13 </qresource>
15 </qresource>
14 </RCC>
16 </RCC>
@@ -1,247 +1,204
1 #include "Visualization/VisualizationGraphHelper.h"
1 #include "Visualization/VisualizationGraphHelper.h"
2 #include "Visualization/qcustomplot.h"
2 #include "Visualization/qcustomplot.h"
3
3
4 #include <Common/ColorUtils.h>
4 #include <Common/ColorUtils.h>
5
5
6 #include <Data/ScalarSeries.h>
6 #include <Data/ScalarSeries.h>
7 #include <Data/VectorSeries.h>
7 #include <Data/VectorSeries.h>
8
8
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10
10
11 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
11 Q_LOGGING_CATEGORY(LOG_VisualizationGraphHelper, "VisualizationGraphHelper")
12
12
13 namespace {
13 namespace {
14
14
15 class SqpDataContainer : public QCPGraphDataContainer {
15 class SqpDataContainer : public QCPGraphDataContainer {
16 public:
16 public:
17 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
17 void appendGraphData(const QCPGraphData &data) { mData.append(data); }
18 };
18 };
19
19
20
21 /// Format for datetimes on a axis
22 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
23
24 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
25 /// non-time data
26 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
27 {
28 if (isTimeAxis) {
29 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
30 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
31 dateTicker->setDateTimeSpec(Qt::UTC);
32
33 return dateTicker;
34 }
35 else {
36 // default ticker
37 return QSharedPointer<QCPAxisTicker>::create();
38 }
39 }
40
41 /// Sets axes properties according to the properties of a data series. Not thread safe
42 template <int Dim>
43 void setAxesProperties(const DataSeries<Dim> &dataSeries, QCustomPlot &plot) noexcept
44 {
45 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
46 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
47 auto setAxisProperties = [](auto axis, const auto &unit) {
48 // label (unit name)
49 axis->setLabel(unit.m_Name);
50
51 // ticker (depending on the type of unit)
52 axis->setTicker(axisTicker(unit.m_TimeUnit));
53 };
54 setAxisProperties(plot.xAxis, dataSeries.xAxisUnit());
55 setAxisProperties(plot.yAxis, dataSeries.valuesUnit());
56 }
57
58 /**
20 /**
59 * Struct used to create plottables, depending on the type of the data series from which to create
21 * Struct used to create plottables, depending on the type of the data series from which to create
60 * them
22 * them
61 * @tparam T the data series' type
23 * @tparam T the data series' type
62 * @remarks Default implementation can't create plottables
24 * @remarks Default implementation can't create plottables
63 */
25 */
64 template <typename T, typename Enabled = void>
26 template <typename T, typename Enabled = void>
65 struct PlottablesCreator {
27 struct PlottablesCreator {
66 static PlottablesMap createPlottables(T &, QCustomPlot &)
28 static PlottablesMap createPlottables(T &, QCustomPlot &)
67 {
29 {
68 qCCritical(LOG_DataSeries())
30 qCCritical(LOG_DataSeries())
69 << QObject::tr("Can't create plottables: unmanaged data series type");
31 << QObject::tr("Can't create plottables: unmanaged data series type");
70 return {};
32 return {};
71 }
33 }
72 };
34 };
73
35
74 /**
36 /**
75 * Specialization of PlottablesCreator for scalars and vectors
37 * Specialization of PlottablesCreator for scalars and vectors
76 * @sa ScalarSeries
38 * @sa ScalarSeries
77 * @sa VectorSeries
39 * @sa VectorSeries
78 */
40 */
79 template <typename T>
41 template <typename T>
80 struct PlottablesCreator<T,
42 struct PlottablesCreator<T,
81 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
43 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
82 or std::is_base_of<VectorSeries, T>::value> > {
44 or std::is_base_of<VectorSeries, T>::value> > {
83 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
45 static PlottablesMap createPlottables(T &dataSeries, QCustomPlot &plot)
84 {
46 {
85 PlottablesMap result{};
47 PlottablesMap result{};
86
48
87 // Gets the number of components of the data series
49 // Gets the number of components of the data series
88 dataSeries.lockRead();
50 dataSeries.lockRead();
89 auto componentCount = dataSeries.valuesData()->componentCount();
51 auto componentCount = dataSeries.valuesData()->componentCount();
90 dataSeries.unlock();
52 dataSeries.unlock();
91
53
92 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
54 auto colors = ColorUtils::colors(Qt::blue, Qt::red, componentCount);
93
55
94 // For each component of the data series, creates a QCPGraph to add to the plot
56 // For each component of the data series, creates a QCPGraph to add to the plot
95 for (auto i = 0; i < componentCount; ++i) {
57 for (auto i = 0; i < componentCount; ++i) {
96 auto graph = plot.addGraph();
58 auto graph = plot.addGraph();
97 graph->setPen(QPen{colors.at(i)});
59 graph->setPen(QPen{colors.at(i)});
98
60
99 result.insert({i, graph});
61 result.insert({i, graph});
100 }
62 }
101
63
102 // Axes properties
103 dataSeries.lockRead();
104 setAxesProperties(dataSeries, plot);
105 dataSeries.unlock();
106
107 plot.replot();
64 plot.replot();
108
65
109 return result;
66 return result;
110 }
67 }
111 };
68 };
112
69
113 /**
70 /**
114 * Struct used to update plottables, depending on the type of the data series from which to update
71 * Struct used to update plottables, depending on the type of the data series from which to update
115 * them
72 * them
116 * @tparam T the data series' type
73 * @tparam T the data series' type
117 * @remarks Default implementation can't update plottables
74 * @remarks Default implementation can't update plottables
118 */
75 */
119 template <typename T, typename Enabled = void>
76 template <typename T, typename Enabled = void>
120 struct PlottablesUpdater {
77 struct PlottablesUpdater {
121 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
78 static void updatePlottables(T &, PlottablesMap &, const SqpRange &, bool)
122 {
79 {
123 qCCritical(LOG_DataSeries())
80 qCCritical(LOG_DataSeries())
124 << QObject::tr("Can't update plottables: unmanaged data series type");
81 << QObject::tr("Can't update plottables: unmanaged data series type");
125 }
82 }
126 };
83 };
127
84
128 /**
85 /**
129 * Specialization of PlottablesUpdater for scalars and vectors
86 * Specialization of PlottablesUpdater for scalars and vectors
130 * @sa ScalarSeries
87 * @sa ScalarSeries
131 * @sa VectorSeries
88 * @sa VectorSeries
132 */
89 */
133 template <typename T>
90 template <typename T>
134 struct PlottablesUpdater<T,
91 struct PlottablesUpdater<T,
135 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
92 typename std::enable_if_t<std::is_base_of<ScalarSeries, T>::value
136 or std::is_base_of<VectorSeries, T>::value> > {
93 or std::is_base_of<VectorSeries, T>::value> > {
137 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
94 static void updatePlottables(T &dataSeries, PlottablesMap &plottables, const SqpRange &range,
138 bool rescaleAxes)
95 bool rescaleAxes)
139 {
96 {
140
97
141 // For each plottable to update, resets its data
98 // For each plottable to update, resets its data
142 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
99 std::map<int, QSharedPointer<SqpDataContainer> > dataContainers{};
143 for (const auto &plottable : plottables) {
100 for (const auto &plottable : plottables) {
144 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
101 if (auto graph = dynamic_cast<QCPGraph *>(plottable.second)) {
145 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
102 auto dataContainer = QSharedPointer<SqpDataContainer>::create();
146 graph->setData(dataContainer);
103 graph->setData(dataContainer);
147
104
148 dataContainers.insert({plottable.first, dataContainer});
105 dataContainers.insert({plottable.first, dataContainer});
149 }
106 }
150 }
107 }
151 dataSeries.lockRead();
108 dataSeries.lockRead();
152
109
153 // - Gets the data of the series included in the current range
110 // - Gets the data of the series included in the current range
154 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
111 // - Updates each plottable by adding, for each data item, a point that takes x-axis data
155 // and value data. The correct value is retrieved according to the index of the component
112 // and value data. The correct value is retrieved according to the index of the component
156 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
113 auto subDataIts = dataSeries.xAxisRange(range.m_TStart, range.m_TEnd);
157 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
114 for (auto it = subDataIts.first; it != subDataIts.second; ++it) {
158 for (const auto &dataContainer : dataContainers) {
115 for (const auto &dataContainer : dataContainers) {
159 auto componentIndex = dataContainer.first;
116 auto componentIndex = dataContainer.first;
160 dataContainer.second->appendGraphData(
117 dataContainer.second->appendGraphData(
161 QCPGraphData(it->x(), it->value(componentIndex)));
118 QCPGraphData(it->x(), it->value(componentIndex)));
162 }
119 }
163 }
120 }
164
121
165 dataSeries.unlock();
122 dataSeries.unlock();
166
123
167 if (!plottables.empty()) {
124 if (!plottables.empty()) {
168 auto plot = plottables.begin()->second->parentPlot();
125 auto plot = plottables.begin()->second->parentPlot();
169
126
170 if (rescaleAxes) {
127 if (rescaleAxes) {
171 plot->rescaleAxes();
128 plot->rescaleAxes();
172 }
129 }
173
130
174 plot->replot();
131 plot->replot();
175 }
132 }
176 }
133 }
177 };
134 };
178
135
179 /**
136 /**
180 * Helper used to create/update plottables
137 * Helper used to create/update plottables
181 */
138 */
182 struct IPlottablesHelper {
139 struct IPlottablesHelper {
183 virtual ~IPlottablesHelper() noexcept = default;
140 virtual ~IPlottablesHelper() noexcept = default;
184 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
141 virtual PlottablesMap create(QCustomPlot &plot) const = 0;
185 virtual void update(PlottablesMap &plottables, const SqpRange &range,
142 virtual void update(PlottablesMap &plottables, const SqpRange &range,
186 bool rescaleAxes = false) const = 0;
143 bool rescaleAxes = false) const = 0;
187 };
144 };
188
145
189 /**
146 /**
190 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
147 * Default implementation of IPlottablesHelper, which takes data series to create/update plottables
191 * @tparam T the data series' type
148 * @tparam T the data series' type
192 */
149 */
193 template <typename T>
150 template <typename T>
194 struct PlottablesHelper : public IPlottablesHelper {
151 struct PlottablesHelper : public IPlottablesHelper {
195 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
152 explicit PlottablesHelper(T &dataSeries) : m_DataSeries{dataSeries} {}
196
153
197 PlottablesMap create(QCustomPlot &plot) const override
154 PlottablesMap create(QCustomPlot &plot) const override
198 {
155 {
199 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
156 return PlottablesCreator<T>::createPlottables(m_DataSeries, plot);
200 }
157 }
201
158
202 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
159 void update(PlottablesMap &plottables, const SqpRange &range, bool rescaleAxes) const override
203 {
160 {
204 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
161 PlottablesUpdater<T>::updatePlottables(m_DataSeries, plottables, range, rescaleAxes);
205 }
162 }
206
163
207 T &m_DataSeries;
164 T &m_DataSeries;
208 };
165 };
209
166
210 /// Creates IPlottablesHelper according to a data series
167 /// Creates IPlottablesHelper according to a data series
211 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
168 std::unique_ptr<IPlottablesHelper> createHelper(std::shared_ptr<IDataSeries> dataSeries) noexcept
212 {
169 {
213 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
170 if (auto scalarSeries = std::dynamic_pointer_cast<ScalarSeries>(dataSeries)) {
214 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
171 return std::make_unique<PlottablesHelper<ScalarSeries> >(*scalarSeries);
215 }
172 }
216 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
173 else if (auto vectorSeries = std::dynamic_pointer_cast<VectorSeries>(dataSeries)) {
217 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
174 return std::make_unique<PlottablesHelper<VectorSeries> >(*vectorSeries);
218 }
175 }
219 else {
176 else {
220 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
177 return std::make_unique<PlottablesHelper<IDataSeries> >(*dataSeries);
221 }
178 }
222 }
179 }
223
180
224 } // namespace
181 } // namespace
225
182
226 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
183 PlottablesMap VisualizationGraphHelper::create(std::shared_ptr<Variable> variable,
227 QCustomPlot &plot) noexcept
184 QCustomPlot &plot) noexcept
228 {
185 {
229 if (variable) {
186 if (variable) {
230 auto helper = createHelper(variable->dataSeries());
187 auto helper = createHelper(variable->dataSeries());
231 auto plottables = helper->create(plot);
188 auto plottables = helper->create(plot);
232 return plottables;
189 return plottables;
233 }
190 }
234 else {
191 else {
235 qCDebug(LOG_VisualizationGraphHelper())
192 qCDebug(LOG_VisualizationGraphHelper())
236 << QObject::tr("Can't create graph plottables : the variable is null");
193 << QObject::tr("Can't create graph plottables : the variable is null");
237 return PlottablesMap{};
194 return PlottablesMap{};
238 }
195 }
239 }
196 }
240
197
241 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
198 void VisualizationGraphHelper::updateData(PlottablesMap &plottables,
242 std::shared_ptr<IDataSeries> dataSeries,
199 std::shared_ptr<IDataSeries> dataSeries,
243 const SqpRange &dateTime)
200 const SqpRange &dateTime)
244 {
201 {
245 auto helper = createHelper(dataSeries);
202 auto helper = createHelper(dataSeries);
246 helper->update(plottables, dateTime);
203 helper->update(plottables, dateTime);
247 }
204 }
@@ -1,105 +1,275
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
1 #include "Visualization/VisualizationGraphRenderingDelegate.h"
2 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/qcustomplot.h"
3 #include "Visualization/qcustomplot.h"
3
4
4 #include <Common/DateUtils.h>
5 #include <Common/DateUtils.h>
5
6
7 #include <Data/IDataSeries.h>
8
9 #include <SqpApplication.h>
10
6 namespace {
11 namespace {
7
12
13 /// Name of the axes layer in QCustomPlot
14 const auto AXES_LAYER = QStringLiteral("axes");
15
8 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
16 const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz");
9
17
18 /// Format for datetimes on a axis
19 const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss");
20
21 /// Icon used to show x-axis properties
22 const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png");
23
24 /// Name of the overlay layer in QCustomPlot
25 const auto OVERLAY_LAYER = QStringLiteral("overlay");
26
27 /// Pixmap used to show x-axis properties
28 const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png");
29
10 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
30 const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2");
11
31
12 /// Offset used to shift the tooltip of the mouse
32 /// Offset used to shift the tooltip of the mouse
13 const auto TOOLTIP_OFFSET = QPoint{20, 20};
33 const auto TOOLTIP_OFFSET = QPoint{20, 20};
14
34
15 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
35 /// Tooltip display rectangle (the tooltip is hidden when the mouse leaves this rectangle)
16 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
36 const auto TOOLTIP_RECT = QRect{10, 10, 10, 10};
17
37
18 /// Timeout after which the tooltip is displayed
38 /// Timeout after which the tooltip is displayed
19 const auto TOOLTIP_TIMEOUT = 500;
39 const auto TOOLTIP_TIMEOUT = 500;
20
40
41 /// Generates the appropriate ticker for an axis, depending on whether the axis displays time or
42 /// non-time data
43 QSharedPointer<QCPAxisTicker> axisTicker(bool isTimeAxis)
44 {
45 if (isTimeAxis) {
46 auto dateTicker = QSharedPointer<QCPAxisTickerDateTime>::create();
47 dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT);
48 dateTicker->setDateTimeSpec(Qt::UTC);
49
50 return dateTicker;
51 }
52 else {
53 // default ticker
54 return QSharedPointer<QCPAxisTicker>::create();
55 }
56 }
57
21 /// Formats a data value according to the axis on which it is present
58 /// Formats a data value according to the axis on which it is present
22 QString formatValue(double value, const QCPAxis &axis)
59 QString formatValue(double value, const QCPAxis &axis)
23 {
60 {
24 // If the axis is a time axis, formats the value as a date
61 // If the axis is a time axis, formats the value as a date
25 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
62 if (auto axisTicker = qSharedPointerDynamicCast<QCPAxisTickerDateTime>(axis.ticker())) {
26 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
63 return DateUtils::dateTime(value, axisTicker->dateTimeSpec()).toString(DATETIME_FORMAT);
27 }
64 }
28 else {
65 else {
29 return QString::number(value);
66 return QString::number(value);
30 }
67 }
31 }
68 }
32
69
33 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
70 void initPointTracerStyle(QCPItemTracer &tracer) noexcept
34 {
71 {
35 tracer.setInterpolating(false);
72 tracer.setInterpolating(false);
36 tracer.setStyle(QCPItemTracer::tsCircle);
73 tracer.setStyle(QCPItemTracer::tsCircle);
37 tracer.setSize(3);
74 tracer.setSize(3);
38 tracer.setPen(QPen(Qt::black));
75 tracer.setPen(QPen(Qt::black));
39 tracer.setBrush(Qt::black);
76 tracer.setBrush(Qt::black);
40 }
77 }
41
78
79 QPixmap pixmap(const QString &iconPath) noexcept
80 {
81 return QIcon{iconPath}.pixmap(QSize{16, 16});
82 }
83
84 void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept
85 {
86 // Icon
87 pixmap.setPixmap(
88 sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16}));
89
90 // Position
91 pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
92 pixmap.topLeft->setCoords(1, 0);
93 pixmap.setClipToAxisRect(false);
94
95 // Can be selected
96 pixmap.setSelectable(true);
97 }
98
99 void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept
100 {
101 // Icon
102 itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH));
103
104 // Position
105 itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio);
106 itemPixmap.topLeft->setCoords(0, 1);
107 itemPixmap.setClipToAxisRect(false);
108
109 // Can be selected
110 itemPixmap.setSelectable(true);
111 }
112
113 void initTitleTextStyle(QCPItemText &text) noexcept
114 {
115 // Font and background styles
116 text.setColor(Qt::gray);
117 text.setBrush(Qt::white);
118
119 // Position
120 text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft);
121 text.position->setType(QCPItemPosition::ptAxisRectRatio);
122 text.position->setCoords(0.5, 0);
123 }
124
42 } // namespace
125 } // namespace
43
126
44 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
127 struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate {
45 explicit VisualizationGraphRenderingDelegatePrivate(QCustomPlot &plot)
128 explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget)
46 : m_Plot{plot}, m_PointTracer{new QCPItemTracer{&plot}}, m_TracerTimer{}
129 : m_Plot{graphWidget.plot()},
130 m_PointTracer{new QCPItemTracer{&m_Plot}},
131 m_TracerTimer{},
132 m_ClosePixmap{new QCPItemPixmap{&m_Plot}},
133 m_TitleText{new QCPItemText{&m_Plot}},
134 m_XAxisPixmap{new QCPItemPixmap{&m_Plot}},
135 m_ShowXAxis{true},
136 m_XAxisLabel{}
47 {
137 {
48 initPointTracerStyle(*m_PointTracer);
138 initPointTracerStyle(*m_PointTracer);
49
139
50 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
140 m_TracerTimer.setInterval(TOOLTIP_TIMEOUT);
51 m_TracerTimer.setSingleShot(true);
141 m_TracerTimer.setSingleShot(true);
142
143 // Inits "close button" in plot overlay
144 m_ClosePixmap->setLayer(OVERLAY_LAYER);
145 initClosePixmapStyle(*m_ClosePixmap);
146
147 // Connects pixmap selection to graph widget closing
148 QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged,
149 [&graphWidget](bool selected) {
150 if (selected) {
151 graphWidget.close();
152 }
153 });
154
155 // Inits graph name in plot overlay
156 m_TitleText->setLayer(OVERLAY_LAYER);
157 m_TitleText->setText(graphWidget.name());
158 initTitleTextStyle(*m_TitleText);
159
160 // Inits "show x-axis button" in plot overlay
161 m_XAxisPixmap->setLayer(OVERLAY_LAYER);
162 initXAxisPixmapStyle(*m_XAxisPixmap);
163
164 // Connects pixmap selection to graph x-axis showing/hiding
165 QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() {
166 if (m_XAxisPixmap->selected()) {
167 // Changes the selection state and refreshes the x-axis
168 m_ShowXAxis = !m_ShowXAxis;
169 updateXAxisState();
170 m_Plot.layer(AXES_LAYER)->replot();
171
172 // Deselects the x-axis pixmap and updates icon
173 m_XAxisPixmap->setSelected(false);
174 m_XAxisPixmap->setPixmap(
175 pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH));
176 m_Plot.layer(OVERLAY_LAYER)->replot();
177 }
178 });
179 }
180
181 /// Updates state of x-axis according to the current selection of x-axis pixmap
182 /// @remarks the method doesn't call plot refresh
183 void updateXAxisState() noexcept
184 {
185 m_Plot.xAxis->setTickLabels(m_ShowXAxis);
186 m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{});
52 }
187 }
53
188
54 QCustomPlot &m_Plot;
189 QCustomPlot &m_Plot;
55 QCPItemTracer *m_PointTracer;
190 QCPItemTracer *m_PointTracer;
56 QTimer m_TracerTimer;
191 QTimer m_TracerTimer;
192 QCPItemPixmap *m_ClosePixmap; /// Graph's close button
193 QCPItemText *m_TitleText; /// Graph's title
194 QCPItemPixmap *m_XAxisPixmap;
195 bool m_ShowXAxis; /// X-axis properties are shown or hidden
196 QString m_XAxisLabel;
57 };
197 };
58
198
59 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(QCustomPlot &plot)
199 VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(
60 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(plot)}
200 VisualizationGraphWidget &graphWidget)
201 : impl{spimpl::make_unique_impl<VisualizationGraphRenderingDelegatePrivate>(graphWidget)}
61 {
202 {
62 }
203 }
63
204
64 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
205 void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexcept
65 {
206 {
66 // Cancels pending refresh
207 // Cancels pending refresh
67 impl->m_TracerTimer.disconnect();
208 impl->m_TracerTimer.disconnect();
68
209
69 // Reinits tracers
210 // Reinits tracers
70 impl->m_PointTracer->setGraph(nullptr);
211 impl->m_PointTracer->setGraph(nullptr);
71 impl->m_PointTracer->setVisible(false);
212 impl->m_PointTracer->setVisible(false);
72 impl->m_Plot.replot();
213 impl->m_Plot.replot();
73
214
74 // Gets the graph under the mouse position
215 // Gets the graph under the mouse position
75 auto eventPos = event->pos();
216 auto eventPos = event->pos();
76 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
217 if (auto graph = qobject_cast<QCPGraph *>(impl->m_Plot.plottableAt(eventPos))) {
77 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
218 auto mouseKey = graph->keyAxis()->pixelToCoord(eventPos.x());
78 auto graphData = graph->data();
219 auto graphData = graph->data();
79
220
80 // Gets the closest data point to the mouse
221 // Gets the closest data point to the mouse
81 auto graphDataIt = graphData->findBegin(mouseKey);
222 auto graphDataIt = graphData->findBegin(mouseKey);
82 if (graphDataIt != graphData->constEnd()) {
223 if (graphDataIt != graphData->constEnd()) {
83 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
224 auto key = formatValue(graphDataIt->key, *graph->keyAxis());
84 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
225 auto value = formatValue(graphDataIt->value, *graph->valueAxis());
85
226
86 // Displays point tracer
227 // Displays point tracer
87 impl->m_PointTracer->setGraph(graph);
228 impl->m_PointTracer->setGraph(graph);
88 impl->m_PointTracer->setGraphKey(graphDataIt->key);
229 impl->m_PointTracer->setGraphKey(graphDataIt->key);
89 impl->m_PointTracer->setLayer(
230 impl->m_PointTracer->setLayer(
90 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
231 impl->m_Plot.layer("main")); // Tracer is set on top of the plot's main layer
91 impl->m_PointTracer->setVisible(true);
232 impl->m_PointTracer->setVisible(true);
92 impl->m_Plot.replot();
233 impl->m_Plot.replot();
93
234
94 // Starts timer to show tooltip after timeout
235 // Starts timer to show tooltip after timeout
95 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
236 auto showTooltip = [ tooltip = TOOLTIP_FORMAT.arg(key, value), eventPos, this ]()
96 {
237 {
97 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
238 QToolTip::showText(impl->m_Plot.mapToGlobal(eventPos) + TOOLTIP_OFFSET, tooltip,
98 &impl->m_Plot, TOOLTIP_RECT);
239 &impl->m_Plot, TOOLTIP_RECT);
99 };
240 };
100
241
101 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
242 QObject::connect(&impl->m_TracerTimer, &QTimer::timeout, showTooltip);
102 impl->m_TracerTimer.start();
243 impl->m_TracerTimer.start();
103 }
244 }
104 }
245 }
105 }
246 }
247
248 void VisualizationGraphRenderingDelegate::setAxesProperties(const Unit &xAxisUnit,
249 const Unit &valuesUnit) noexcept
250 {
251 // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected
252 impl->m_XAxisLabel = xAxisUnit.m_Name;
253
254 auto setAxisProperties = [](auto axis, const auto &unit) {
255 // label (unit name)
256 axis->setLabel(unit.m_Name);
257
258 // ticker (depending on the type of unit)
259 axis->setTicker(axisTicker(unit.m_TimeUnit));
260 };
261 setAxisProperties(impl->m_Plot.xAxis, xAxisUnit);
262 setAxisProperties(impl->m_Plot.yAxis, valuesUnit);
263
264 // Updates x-axis state
265 impl->updateXAxisState();
266
267 impl->m_Plot.layer(AXES_LAYER)->replot();
268 }
269
270 void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept
271 {
272 auto overlay = impl->m_Plot.layer(OVERLAY_LAYER);
273 overlay->setVisible(show);
274 overlay->replot();
275 }
@@ -1,313 +1,344
1 #include "Visualization/VisualizationGraphWidget.h"
1 #include "Visualization/VisualizationGraphWidget.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
2 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/VisualizationDefs.h"
3 #include "Visualization/VisualizationDefs.h"
4 #include "Visualization/VisualizationGraphHelper.h"
4 #include "Visualization/VisualizationGraphHelper.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
5 #include "Visualization/VisualizationGraphRenderingDelegate.h"
6 #include "ui_VisualizationGraphWidget.h"
6 #include "ui_VisualizationGraphWidget.h"
7
7
8 #include <Data/ArrayData.h>
8 #include <Data/ArrayData.h>
9 #include <Data/IDataSeries.h>
9 #include <Data/IDataSeries.h>
10 #include <Settings/SqpSettingsDefs.h>
10 #include <Settings/SqpSettingsDefs.h>
11 #include <SqpApplication.h>
11 #include <SqpApplication.h>
12 #include <Variable/Variable.h>
12 #include <Variable/Variable.h>
13 #include <Variable/VariableController.h>
13 #include <Variable/VariableController.h>
14
14
15 #include <unordered_map>
15 #include <unordered_map>
16
16
17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
17 Q_LOGGING_CATEGORY(LOG_VisualizationGraphWidget, "VisualizationGraphWidget")
18
18
19 namespace {
19 namespace {
20
20
21 /// Key pressed to enable zoom on horizontal axis
21 /// Key pressed to enable zoom on horizontal axis
22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
22 const auto HORIZONTAL_ZOOM_MODIFIER = Qt::NoModifier;
23
23
24 /// Key pressed to enable zoom on vertical axis
24 /// Key pressed to enable zoom on vertical axis
25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
25 const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier;
26
26
27 } // namespace
27 } // namespace
28
28
29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
29 struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate {
30
30
31 explicit VisualizationGraphWidgetPrivate()
31 explicit VisualizationGraphWidgetPrivate(const QString &name)
32 : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr}
32 : m_Name{name},
33 m_DoAcquisition{true},
34 m_IsCalibration{false},
35 m_RenderingDelegate{nullptr}
33 {
36 {
34 }
37 }
35
38
39 QString m_Name;
36 // 1 variable -> n qcpplot
40 // 1 variable -> n qcpplot
37 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
41 std::map<std::shared_ptr<Variable>, PlottablesMap> m_VariableToPlotMultiMap;
38 bool m_DoAcquisition;
42 bool m_DoAcquisition;
39 bool m_IsCalibration;
43 bool m_IsCalibration;
40 QCPItemTracer *m_TextTracer;
44 QCPItemTracer *m_TextTracer;
41 /// Delegate used to attach rendering features to the plot
45 /// Delegate used to attach rendering features to the plot
42 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
46 std::unique_ptr<VisualizationGraphRenderingDelegate> m_RenderingDelegate;
43 };
47 };
44
48
45 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
49 VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent)
46 : QWidget{parent},
50 : QWidget{parent},
47 ui{new Ui::VisualizationGraphWidget},
51 ui{new Ui::VisualizationGraphWidget},
48 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>()}
52 impl{spimpl::make_unique_impl<VisualizationGraphWidgetPrivate>(name)}
49 {
53 {
50 ui->setupUi(this);
54 ui->setupUi(this);
51
55
52 // The delegate must be initialized after the ui as it uses the plot
53 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*ui->widget);
54
55 ui->graphNameLabel->setText(name);
56
57 // 'Close' options : widget is deleted when closed
56 // 'Close' options : widget is deleted when closed
58 setAttribute(Qt::WA_DeleteOnClose);
57 setAttribute(Qt::WA_DeleteOnClose);
59 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close);
60 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
61
58
62 // Set qcpplot properties :
59 // Set qcpplot properties :
63 // - Drag (on x-axis) and zoom are enabled
60 // - Drag (on x-axis) and zoom are enabled
64 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
61 // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation
65 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
62 ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems);
66 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
63 ui->widget->axisRect()->setRangeDrag(Qt::Horizontal);
67
64
65 // The delegate must be initialized after the ui as it uses the plot
66 impl->m_RenderingDelegate = std::make_unique<VisualizationGraphRenderingDelegate>(*this);
67
68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
68 connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress);
69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
69 connect(ui->widget, &QCustomPlot::mouseRelease, this,
70 &VisualizationGraphWidget::onMouseRelease);
70 &VisualizationGraphWidget::onMouseRelease);
71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
71 connect(ui->widget, &QCustomPlot::mouseMove, this, &VisualizationGraphWidget::onMouseMove);
72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
72 connect(ui->widget, &QCustomPlot::mouseWheel, this, &VisualizationGraphWidget::onMouseWheel);
73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
73 connect(ui->widget->xAxis, static_cast<void (QCPAxis::*)(const QCPRange &, const QCPRange &)>(
74 &QCPAxis::rangeChanged),
74 &QCPAxis::rangeChanged),
75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
75 this, &VisualizationGraphWidget::onRangeChanged, Qt::DirectConnection);
76
76
77 // Activates menu when right clicking on the graph
77 // Activates menu when right clicking on the graph
78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
78 ui->widget->setContextMenuPolicy(Qt::CustomContextMenu);
79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
79 connect(ui->widget, &QCustomPlot::customContextMenuRequested, this,
80 &VisualizationGraphWidget::onGraphMenuRequested);
80 &VisualizationGraphWidget::onGraphMenuRequested);
81
81
82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
82 connect(this, &VisualizationGraphWidget::requestDataLoading, &sqpApp->variableController(),
83 &VariableController::onRequestDataLoading);
83 &VariableController::onRequestDataLoading);
84
84
85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
85 connect(&sqpApp->variableController(), &VariableController::updateVarDisplaying, this,
86 &VisualizationGraphWidget::onUpdateVarDisplaying);
86 &VisualizationGraphWidget::onUpdateVarDisplaying);
87 }
87 }
88
88
89
89
90 VisualizationGraphWidget::~VisualizationGraphWidget()
90 VisualizationGraphWidget::~VisualizationGraphWidget()
91 {
91 {
92 delete ui;
92 delete ui;
93 }
93 }
94
94
95 void VisualizationGraphWidget::enableAcquisition(bool enable)
95 void VisualizationGraphWidget::enableAcquisition(bool enable)
96 {
96 {
97 impl->m_DoAcquisition = enable;
97 impl->m_DoAcquisition = enable;
98 }
98 }
99
99
100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
100 void VisualizationGraphWidget::addVariable(std::shared_ptr<Variable> variable, SqpRange range)
101 {
101 {
102 // Uses delegate to create the qcpplot components according to the variable
102 // Uses delegate to create the qcpplot components according to the variable
103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
103 auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget);
104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
104 impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)});
105
105
106 // Set axes properties according to the units of the data series
107 /// @todo : for the moment, no control is performed on the axes: the units and the tickers
108 /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph
109 auto xAxisUnit = Unit{};
110 auto valuesUnit = Unit{};
111
112 if (auto dataSeries = variable->dataSeries()) {
113 dataSeries->lockRead();
114 xAxisUnit = dataSeries->xAxisUnit();
115 valuesUnit = dataSeries->valuesUnit();
116 dataSeries->unlock();
117 }
118 impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit);
119
106 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
120 connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated()));
107
121
108 auto varRange = variable->range();
122 auto varRange = variable->range();
109
123
110 this->enableAcquisition(false);
124 this->enableAcquisition(false);
111 this->setGraphRange(range);
125 this->setGraphRange(range);
112 this->enableAcquisition(true);
126 this->enableAcquisition(true);
113
127
114 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
128 emit requestDataLoading(QVector<std::shared_ptr<Variable> >() << variable, range, varRange,
115 false);
129 false);
116
130
117 emit variableAdded(variable);
131 emit variableAdded(variable);
118 }
132 }
119
133
120 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
134 void VisualizationGraphWidget::removeVariable(std::shared_ptr<Variable> variable) noexcept
121 {
135 {
122 // Each component associated to the variable :
136 // Each component associated to the variable :
123 // - is removed from qcpplot (which deletes it)
137 // - is removed from qcpplot (which deletes it)
124 // - is no longer referenced in the map
138 // - is no longer referenced in the map
125 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
139 auto variableIt = impl->m_VariableToPlotMultiMap.find(variable);
126 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
140 if (variableIt != impl->m_VariableToPlotMultiMap.cend()) {
127 auto &plottablesMap = variableIt->second;
141 auto &plottablesMap = variableIt->second;
128
142
129 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
143 for (auto plottableIt = plottablesMap.cbegin(), plottableEnd = plottablesMap.cend();
130 plottableIt != plottableEnd;) {
144 plottableIt != plottableEnd;) {
131 ui->widget->removePlottable(plottableIt->second);
145 ui->widget->removePlottable(plottableIt->second);
132 plottableIt = plottablesMap.erase(plottableIt);
146 plottableIt = plottablesMap.erase(plottableIt);
133 }
147 }
134
148
135 impl->m_VariableToPlotMultiMap.erase(variableIt);
149 impl->m_VariableToPlotMultiMap.erase(variableIt);
136 }
150 }
137
151
138 // Updates graph
152 // Updates graph
139 ui->widget->replot();
153 ui->widget->replot();
140 }
154 }
141
155
142 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
156 void VisualizationGraphWidget::setRange(std::shared_ptr<Variable> variable, const SqpRange &range)
143 {
157 {
144 // Note: in case of different axes that depends on variable, we could start with a code like
158 // Note: in case of different axes that depends on variable, we could start with a code like
145 // that:
159 // that:
146 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
160 // auto componentsIt = impl->m_VariableToPlotMultiMap.equal_range(variable);
147 // for (auto it = componentsIt.first; it != componentsIt.second;) {
161 // for (auto it = componentsIt.first; it != componentsIt.second;) {
148 // }
162 // }
149 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
163 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
150 ui->widget->replot();
164 ui->widget->replot();
151 }
165 }
152
166
153 void VisualizationGraphWidget::setYRange(const SqpRange &range)
167 void VisualizationGraphWidget::setYRange(const SqpRange &range)
154 {
168 {
155 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
169 ui->widget->yAxis->setRange(range.m_TStart, range.m_TEnd);
156 }
170 }
157
171
158 SqpRange VisualizationGraphWidget::graphRange() const noexcept
172 SqpRange VisualizationGraphWidget::graphRange() const noexcept
159 {
173 {
160 auto graphRange = ui->widget->xAxis->range();
174 auto graphRange = ui->widget->xAxis->range();
161 return SqpRange{graphRange.lower, graphRange.upper};
175 return SqpRange{graphRange.lower, graphRange.upper};
162 }
176 }
163
177
164 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
178 void VisualizationGraphWidget::setGraphRange(const SqpRange &range)
165 {
179 {
166 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
180 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange START");
167 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
181 ui->widget->xAxis->setRange(range.m_TStart, range.m_TEnd);
168 ui->widget->replot();
182 ui->widget->replot();
169 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
183 qCDebug(LOG_VisualizationGraphWidget()) << tr("VisualizationGraphWidget::setGraphRange END");
170 }
184 }
171
185
172 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
186 void VisualizationGraphWidget::accept(IVisualizationWidgetVisitor *visitor)
173 {
187 {
174 if (visitor) {
188 if (visitor) {
175 visitor->visit(this);
189 visitor->visit(this);
176 }
190 }
177 else {
191 else {
178 qCCritical(LOG_VisualizationGraphWidget())
192 qCCritical(LOG_VisualizationGraphWidget())
179 << tr("Can't visit widget : the visitor is null");
193 << tr("Can't visit widget : the visitor is null");
180 }
194 }
181 }
195 }
182
196
183 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
197 bool VisualizationGraphWidget::canDrop(const Variable &variable) const
184 {
198 {
185 /// @todo : for the moment, a graph can always accomodate a variable
199 /// @todo : for the moment, a graph can always accomodate a variable
186 Q_UNUSED(variable);
200 Q_UNUSED(variable);
187 return true;
201 return true;
188 }
202 }
189
203
190 bool VisualizationGraphWidget::contains(const Variable &variable) const
204 bool VisualizationGraphWidget::contains(const Variable &variable) const
191 {
205 {
192 // Finds the variable among the keys of the map
206 // Finds the variable among the keys of the map
193 auto variablePtr = &variable;
207 auto variablePtr = &variable;
194 auto findVariable
208 auto findVariable
195 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
209 = [variablePtr](const auto &entry) { return variablePtr == entry.first.get(); };
196
210
197 auto end = impl->m_VariableToPlotMultiMap.cend();
211 auto end = impl->m_VariableToPlotMultiMap.cend();
198 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
212 auto it = std::find_if(impl->m_VariableToPlotMultiMap.cbegin(), end, findVariable);
199 return it != end;
213 return it != end;
200 }
214 }
201
215
202 QString VisualizationGraphWidget::name() const
216 QString VisualizationGraphWidget::name() const
203 {
217 {
204 return ui->graphNameLabel->text();
218 return impl->m_Name;
219 }
220
221 void VisualizationGraphWidget::enterEvent(QEvent *event)
222 {
223 Q_UNUSED(event);
224 impl->m_RenderingDelegate->showGraphOverlay(true);
225 }
226
227 void VisualizationGraphWidget::leaveEvent(QEvent *event)
228 {
229 Q_UNUSED(event);
230 impl->m_RenderingDelegate->showGraphOverlay(false);
231 }
232
233 QCustomPlot &VisualizationGraphWidget::plot() noexcept
234 {
235 return *ui->widget;
205 }
236 }
206
237
207 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
238 void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept
208 {
239 {
209 QMenu graphMenu{};
240 QMenu graphMenu{};
210
241
211 // Iterates on variables (unique keys)
242 // Iterates on variables (unique keys)
212 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
243 for (auto it = impl->m_VariableToPlotMultiMap.cbegin(),
213 end = impl->m_VariableToPlotMultiMap.cend();
244 end = impl->m_VariableToPlotMultiMap.cend();
214 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
245 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
215 // 'Remove variable' action
246 // 'Remove variable' action
216 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
247 graphMenu.addAction(tr("Remove variable %1").arg(it->first->name()),
217 [ this, var = it->first ]() { removeVariable(var); });
248 [ this, var = it->first ]() { removeVariable(var); });
218 }
249 }
219
250
220 if (!graphMenu.isEmpty()) {
251 if (!graphMenu.isEmpty()) {
221 graphMenu.exec(QCursor::pos());
252 graphMenu.exec(QCursor::pos());
222 }
253 }
223 }
254 }
224
255
225 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
256 void VisualizationGraphWidget::onRangeChanged(const QCPRange &t1, const QCPRange &t2)
226 {
257 {
227 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
258 qCDebug(LOG_VisualizationGraphWidget()) << tr("TORM: VisualizationGraphWidget::onRangeChanged")
228 << QThread::currentThread()->objectName() << "DoAcqui"
259 << QThread::currentThread()->objectName() << "DoAcqui"
229 << impl->m_DoAcquisition;
260 << impl->m_DoAcquisition;
230
261
231 auto graphRange = SqpRange{t1.lower, t1.upper};
262 auto graphRange = SqpRange{t1.lower, t1.upper};
232 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
263 auto oldGraphRange = SqpRange{t2.lower, t2.upper};
233
264
234 if (impl->m_DoAcquisition) {
265 if (impl->m_DoAcquisition) {
235 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
266 QVector<std::shared_ptr<Variable> > variableUnderGraphVector;
236
267
237 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
268 for (auto it = impl->m_VariableToPlotMultiMap.begin(),
238 end = impl->m_VariableToPlotMultiMap.end();
269 end = impl->m_VariableToPlotMultiMap.end();
239 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
270 it != end; it = impl->m_VariableToPlotMultiMap.upper_bound(it->first)) {
240 variableUnderGraphVector.push_back(it->first);
271 variableUnderGraphVector.push_back(it->first);
241 }
272 }
242 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
273 emit requestDataLoading(std::move(variableUnderGraphVector), graphRange, oldGraphRange,
243 !impl->m_IsCalibration);
274 !impl->m_IsCalibration);
244
275
245 if (!impl->m_IsCalibration) {
276 if (!impl->m_IsCalibration) {
246 qCDebug(LOG_VisualizationGraphWidget())
277 qCDebug(LOG_VisualizationGraphWidget())
247 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
278 << tr("TORM: VisualizationGraphWidget::Synchronize notify !!")
248 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
279 << QThread::currentThread()->objectName() << graphRange << oldGraphRange;
249 emit synchronize(graphRange, oldGraphRange);
280 emit synchronize(graphRange, oldGraphRange);
250 }
281 }
251 }
282 }
252 }
283 }
253
284
254 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
285 void VisualizationGraphWidget::onMouseMove(QMouseEvent *event) noexcept
255 {
286 {
256 // Handles plot rendering when mouse is moving
287 // Handles plot rendering when mouse is moving
257 impl->m_RenderingDelegate->onMouseMove(event);
288 impl->m_RenderingDelegate->onMouseMove(event);
258 }
289 }
259
290
260 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
291 void VisualizationGraphWidget::onMouseWheel(QWheelEvent *event) noexcept
261 {
292 {
262 auto zoomOrientations = QFlags<Qt::Orientation>{};
293 auto zoomOrientations = QFlags<Qt::Orientation>{};
263
294
264 // Lambda that enables a zoom orientation if the key modifier related to this orientation
295 // Lambda that enables a zoom orientation if the key modifier related to this orientation
265 // has
296 // has
266 // been pressed
297 // been pressed
267 auto enableOrientation
298 auto enableOrientation
268 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
299 = [&zoomOrientations, event](const auto &orientation, const auto &modifier) {
269 auto orientationEnabled = event->modifiers().testFlag(modifier);
300 auto orientationEnabled = event->modifiers().testFlag(modifier);
270 zoomOrientations.setFlag(orientation, orientationEnabled);
301 zoomOrientations.setFlag(orientation, orientationEnabled);
271 };
302 };
272 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
303 enableOrientation(Qt::Vertical, VERTICAL_ZOOM_MODIFIER);
273 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
304 enableOrientation(Qt::Horizontal, HORIZONTAL_ZOOM_MODIFIER);
274
305
275 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
306 ui->widget->axisRect()->setRangeZoom(zoomOrientations);
276 }
307 }
277
308
278 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
309 void VisualizationGraphWidget::onMousePress(QMouseEvent *event) noexcept
279 {
310 {
280 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
311 impl->m_IsCalibration = event->modifiers().testFlag(Qt::ControlModifier);
281 }
312 }
282
313
283 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
314 void VisualizationGraphWidget::onMouseRelease(QMouseEvent *event) noexcept
284 {
315 {
285 impl->m_IsCalibration = false;
316 impl->m_IsCalibration = false;
286 }
317 }
287
318
288 void VisualizationGraphWidget::onDataCacheVariableUpdated()
319 void VisualizationGraphWidget::onDataCacheVariableUpdated()
289 {
320 {
290 auto graphRange = ui->widget->xAxis->range();
321 auto graphRange = ui->widget->xAxis->range();
291 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
322 auto dateTime = SqpRange{graphRange.lower, graphRange.upper};
292
323
293 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
324 for (auto &variableEntry : impl->m_VariableToPlotMultiMap) {
294 auto variable = variableEntry.first;
325 auto variable = variableEntry.first;
295 qCDebug(LOG_VisualizationGraphWidget())
326 qCDebug(LOG_VisualizationGraphWidget())
296 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
327 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated S" << variable->range();
297 qCDebug(LOG_VisualizationGraphWidget())
328 qCDebug(LOG_VisualizationGraphWidget())
298 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
329 << "TORM: VisualizationGraphWidget::onDataCacheVariableUpdated E" << dateTime;
299 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
330 if (dateTime.contains(variable->range()) || dateTime.intersect(variable->range())) {
300 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
331 VisualizationGraphHelper::updateData(variableEntry.second, variable->dataSeries(),
301 variable->range());
332 variable->range());
302 }
333 }
303 }
334 }
304 }
335 }
305
336
306 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
337 void VisualizationGraphWidget::onUpdateVarDisplaying(std::shared_ptr<Variable> variable,
307 const SqpRange &range)
338 const SqpRange &range)
308 {
339 {
309 auto it = impl->m_VariableToPlotMultiMap.find(variable);
340 auto it = impl->m_VariableToPlotMultiMap.find(variable);
310 if (it != impl->m_VariableToPlotMultiMap.end()) {
341 if (it != impl->m_VariableToPlotMultiMap.end()) {
311 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
342 VisualizationGraphHelper::updateData(it->second, variable->dataSeries(), range);
312 }
343 }
313 }
344 }
@@ -1,260 +1,268
1 #include "Visualization/VisualizationZoneWidget.h"
1 #include "Visualization/VisualizationZoneWidget.h"
2
2
3
4 #include "Visualization/IVisualizationWidgetVisitor.h"
3 #include "Visualization/IVisualizationWidgetVisitor.h"
4 #include "Visualization/QCustomPlotSynchronizer.h"
5 #include "Visualization/VisualizationGraphWidget.h"
5 #include "Visualization/VisualizationGraphWidget.h"
6 #include "ui_VisualizationZoneWidget.h"
6 #include "ui_VisualizationZoneWidget.h"
7
7
8 #include <Data/SqpRange.h>
8 #include <Data/SqpRange.h>
9 #include <Variable/Variable.h>
9 #include <Variable/Variable.h>
10 #include <Variable/VariableController.h>
10 #include <Variable/VariableController.h>
11
11
12 #include <QUuid>
12 #include <QUuid>
13 #include <SqpApplication.h>
13 #include <SqpApplication.h>
14 #include <cmath>
14 #include <cmath>
15
15
16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
16 Q_LOGGING_CATEGORY(LOG_VisualizationZoneWidget, "VisualizationZoneWidget")
17
17
18 namespace {
18 namespace {
19
19
20 /// Minimum height for graph added in zones (in pixels)
20 /// Minimum height for graph added in zones (in pixels)
21 const auto GRAPH_MINIMUM_HEIGHT = 300;
21 const auto GRAPH_MINIMUM_HEIGHT = 300;
22
22
23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
23 /// Generates a default name for a new graph, according to the number of graphs already displayed in
24 /// the zone
24 /// the zone
25 QString defaultGraphName(const QLayout &layout)
25 QString defaultGraphName(const QLayout &layout)
26 {
26 {
27 auto count = 0;
27 auto count = 0;
28 for (auto i = 0; i < layout.count(); ++i) {
28 for (auto i = 0; i < layout.count(); ++i) {
29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
29 if (dynamic_cast<VisualizationGraphWidget *>(layout.itemAt(i)->widget())) {
30 count++;
30 count++;
31 }
31 }
32 }
32 }
33
33
34 return QObject::tr("Graph %1").arg(count + 1);
34 return QObject::tr("Graph %1").arg(count + 1);
35 }
35 }
36
36
37 } // namespace
37 } // namespace
38
38
39 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
39 struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate {
40
40
41 explicit VisualizationZoneWidgetPrivate() : m_SynchronisationGroupId{QUuid::createUuid()} {}
41 explicit VisualizationZoneWidgetPrivate()
42 : m_SynchronisationGroupId{QUuid::createUuid()},
43 m_Synchronizer{std::make_unique<QCustomPlotSynchronizer>()}
44 {
45 }
42 QUuid m_SynchronisationGroupId;
46 QUuid m_SynchronisationGroupId;
47 std::unique_ptr<IGraphSynchronizer> m_Synchronizer;
43 };
48 };
44
49
45 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
50 VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent)
46 : QWidget{parent},
51 : QWidget{parent},
47 ui{new Ui::VisualizationZoneWidget},
52 ui{new Ui::VisualizationZoneWidget},
48 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
53 impl{spimpl::make_unique_impl<VisualizationZoneWidgetPrivate>()}
49 {
54 {
50 ui->setupUi(this);
55 ui->setupUi(this);
51
56
52 ui->zoneNameLabel->setText(name);
57 ui->zoneNameLabel->setText(name);
53
58
54 // 'Close' options : widget is deleted when closed
59 // 'Close' options : widget is deleted when closed
55 setAttribute(Qt::WA_DeleteOnClose);
60 setAttribute(Qt::WA_DeleteOnClose);
56 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
61 connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationZoneWidget::close);
57 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
62 ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
58
63
59 // Synchronisation id
64 // Synchronisation id
60 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
65 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronizationGroupId",
61 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
66 Qt::QueuedConnection, Q_ARG(QUuid, impl->m_SynchronisationGroupId));
62 }
67 }
63
68
64 VisualizationZoneWidget::~VisualizationZoneWidget()
69 VisualizationZoneWidget::~VisualizationZoneWidget()
65 {
70 {
66 delete ui;
71 delete ui;
67 }
72 }
68
73
69 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
74 void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget)
70 {
75 {
76 // Synchronize new graph with others in the zone
77 impl->m_Synchronizer->addGraph(*graphWidget);
78
71 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
79 ui->visualizationZoneFrame->layout()->addWidget(graphWidget);
72 }
80 }
73
81
74 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
82 VisualizationGraphWidget *VisualizationZoneWidget::createGraph(std::shared_ptr<Variable> variable)
75 {
83 {
76 auto graphWidget = new VisualizationGraphWidget{
84 auto graphWidget = new VisualizationGraphWidget{
77 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
85 defaultGraphName(*ui->visualizationZoneFrame->layout()), this};
78
86
79
87
80 // Set graph properties
88 // Set graph properties
81 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
89 graphWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
82 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
90 graphWidget->setMinimumHeight(GRAPH_MINIMUM_HEIGHT);
83
91
84
92
85 // Lambda to synchronize zone widget
93 // Lambda to synchronize zone widget
86 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
94 auto synchronizeZoneWidget = [this, graphWidget](const SqpRange &graphRange,
87 const SqpRange &oldGraphRange) {
95 const SqpRange &oldGraphRange) {
88
96
89 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
97 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
90 auto frameLayout = ui->visualizationZoneFrame->layout();
98 auto frameLayout = ui->visualizationZoneFrame->layout();
91 for (auto i = 0; i < frameLayout->count(); ++i) {
99 for (auto i = 0; i < frameLayout->count(); ++i) {
92 auto graphChild
100 auto graphChild
93 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
101 = dynamic_cast<VisualizationGraphWidget *>(frameLayout->itemAt(i)->widget());
94 if (graphChild && (graphChild != graphWidget)) {
102 if (graphChild && (graphChild != graphWidget)) {
95
103
96 auto graphChildRange = graphChild->graphRange();
104 auto graphChildRange = graphChild->graphRange();
97 switch (zoomType) {
105 switch (zoomType) {
98 case AcquisitionZoomType::ZoomIn: {
106 case AcquisitionZoomType::ZoomIn: {
99 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
107 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
100 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
108 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
101 graphChildRange.m_TStart += deltaLeft;
109 graphChildRange.m_TStart += deltaLeft;
102 graphChildRange.m_TEnd -= deltaRight;
110 graphChildRange.m_TEnd -= deltaRight;
103 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
111 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomIn");
104 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
112 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
105 << deltaLeft;
113 << deltaLeft;
106 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
114 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
107 << deltaRight;
115 << deltaRight;
108 qCDebug(LOG_VisualizationZoneWidget())
116 qCDebug(LOG_VisualizationZoneWidget())
109 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
117 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
110
118
111 break;
119 break;
112 }
120 }
113
121
114 case AcquisitionZoomType::ZoomOut: {
122 case AcquisitionZoomType::ZoomOut: {
115 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
123 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: ZoomOut");
116 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
124 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
117 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
125 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
118 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
126 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaLeft")
119 << deltaLeft;
127 << deltaLeft;
120 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
128 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: deltaRight")
121 << deltaRight;
129 << deltaRight;
122 qCDebug(LOG_VisualizationZoneWidget())
130 qCDebug(LOG_VisualizationZoneWidget())
123 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
131 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
124 graphChildRange.m_TStart -= deltaLeft;
132 graphChildRange.m_TStart -= deltaLeft;
125 graphChildRange.m_TEnd += deltaRight;
133 graphChildRange.m_TEnd += deltaRight;
126 break;
134 break;
127 }
135 }
128 case AcquisitionZoomType::PanRight: {
136 case AcquisitionZoomType::PanRight: {
129 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
137 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanRight");
130 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
138 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
131 graphChildRange.m_TStart += deltaRight;
139 graphChildRange.m_TStart += deltaRight;
132 graphChildRange.m_TEnd += deltaRight;
140 graphChildRange.m_TEnd += deltaRight;
133 qCDebug(LOG_VisualizationZoneWidget())
141 qCDebug(LOG_VisualizationZoneWidget())
134 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
142 << tr("TORM: dt") << graphRange.m_TEnd - graphRange.m_TStart;
135 break;
143 break;
136 }
144 }
137 case AcquisitionZoomType::PanLeft: {
145 case AcquisitionZoomType::PanLeft: {
138 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
146 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: PanLeft");
139 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
147 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
140 graphChildRange.m_TStart -= deltaLeft;
148 graphChildRange.m_TStart -= deltaLeft;
141 graphChildRange.m_TEnd -= deltaLeft;
149 graphChildRange.m_TEnd -= deltaLeft;
142 break;
150 break;
143 }
151 }
144 case AcquisitionZoomType::Unknown: {
152 case AcquisitionZoomType::Unknown: {
145 qCDebug(LOG_VisualizationZoneWidget())
153 qCDebug(LOG_VisualizationZoneWidget())
146 << tr("Impossible to synchronize: zoom type unknown");
154 << tr("Impossible to synchronize: zoom type unknown");
147 break;
155 break;
148 }
156 }
149 default:
157 default:
150 qCCritical(LOG_VisualizationZoneWidget())
158 qCCritical(LOG_VisualizationZoneWidget())
151 << tr("Impossible to synchronize: zoom type not take into account");
159 << tr("Impossible to synchronize: zoom type not take into account");
152 // No action
160 // No action
153 break;
161 break;
154 }
162 }
155 graphChild->enableAcquisition(false);
163 graphChild->enableAcquisition(false);
156 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
164 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range before: ")
157 << graphChild->graphRange();
165 << graphChild->graphRange();
158 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
166 qCDebug(LOG_VisualizationZoneWidget()) << tr("TORM: Range after : ")
159 << graphChildRange;
167 << graphChildRange;
160 qCDebug(LOG_VisualizationZoneWidget())
168 qCDebug(LOG_VisualizationZoneWidget())
161 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
169 << tr("TORM: child dt") << graphChildRange.m_TEnd - graphChildRange.m_TStart;
162 graphChild->setGraphRange(graphChildRange);
170 graphChild->setGraphRange(graphChildRange);
163 graphChild->enableAcquisition(true);
171 graphChild->enableAcquisition(true);
164 }
172 }
165 }
173 }
166 };
174 };
167
175
168 // connection for synchronization
176 // connection for synchronization
169 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
177 connect(graphWidget, &VisualizationGraphWidget::synchronize, synchronizeZoneWidget);
170 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
178 connect(graphWidget, &VisualizationGraphWidget::variableAdded, this,
171 &VisualizationZoneWidget::onVariableAdded);
179 &VisualizationZoneWidget::onVariableAdded);
172
180
173 auto range = SqpRange{};
181 auto range = SqpRange{};
174
182
175 // Apply visitor to graph children
183 // Apply visitor to graph children
176 auto layout = ui->visualizationZoneFrame->layout();
184 auto layout = ui->visualizationZoneFrame->layout();
177 if (layout->count() > 0) {
185 if (layout->count() > 0) {
178 // Case of a new graph in a existant zone
186 // Case of a new graph in a existant zone
179 if (auto visualizationGraphWidget
187 if (auto visualizationGraphWidget
180 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
188 = dynamic_cast<VisualizationGraphWidget *>(layout->itemAt(0)->widget())) {
181 range = visualizationGraphWidget->graphRange();
189 range = visualizationGraphWidget->graphRange();
182 }
190 }
183 }
191 }
184 else {
192 else {
185 // Case of a new graph as the first of the zone
193 // Case of a new graph as the first of the zone
186 range = variable->range();
194 range = variable->range();
187 }
195 }
188
196
189 this->addGraph(graphWidget);
197 this->addGraph(graphWidget);
190
198
191 graphWidget->addVariable(variable, range);
199 graphWidget->addVariable(variable, range);
192
200
193 // get y using variable range
201 // get y using variable range
194 if (auto dataSeries = variable->dataSeries()) {
202 if (auto dataSeries = variable->dataSeries()) {
195 dataSeries->lockRead();
203 dataSeries->lockRead();
196 auto valuesBounds
204 auto valuesBounds
197 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
205 = dataSeries->valuesBounds(variable->range().m_TStart, variable->range().m_TEnd);
198 auto end = dataSeries->cend();
206 auto end = dataSeries->cend();
199 if (valuesBounds.first != end && valuesBounds.second != end) {
207 if (valuesBounds.first != end && valuesBounds.second != end) {
200 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
208 auto rangeValue = [](const auto &value) { return std::isnan(value) ? 0. : value; };
201
209
202 auto minValue = rangeValue(valuesBounds.first->minValue());
210 auto minValue = rangeValue(valuesBounds.first->minValue());
203 auto maxValue = rangeValue(valuesBounds.second->maxValue());
211 auto maxValue = rangeValue(valuesBounds.second->maxValue());
204
212
205 graphWidget->setYRange(SqpRange{minValue, maxValue});
213 graphWidget->setYRange(SqpRange{minValue, maxValue});
206 }
214 }
207 dataSeries->unlock();
215 dataSeries->unlock();
208 }
216 }
209
217
210 return graphWidget;
218 return graphWidget;
211 }
219 }
212
220
213 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
221 void VisualizationZoneWidget::accept(IVisualizationWidgetVisitor *visitor)
214 {
222 {
215 if (visitor) {
223 if (visitor) {
216 visitor->visitEnter(this);
224 visitor->visitEnter(this);
217
225
218 // Apply visitor to graph children
226 // Apply visitor to graph children
219 auto layout = ui->visualizationZoneFrame->layout();
227 auto layout = ui->visualizationZoneFrame->layout();
220 for (auto i = 0; i < layout->count(); ++i) {
228 for (auto i = 0; i < layout->count(); ++i) {
221 if (auto item = layout->itemAt(i)) {
229 if (auto item = layout->itemAt(i)) {
222 // Widgets different from graphs are not visited (no action)
230 // Widgets different from graphs are not visited (no action)
223 if (auto visualizationGraphWidget
231 if (auto visualizationGraphWidget
224 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
232 = dynamic_cast<VisualizationGraphWidget *>(item->widget())) {
225 visualizationGraphWidget->accept(visitor);
233 visualizationGraphWidget->accept(visitor);
226 }
234 }
227 }
235 }
228 }
236 }
229
237
230 visitor->visitLeave(this);
238 visitor->visitLeave(this);
231 }
239 }
232 else {
240 else {
233 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
241 qCCritical(LOG_VisualizationZoneWidget()) << tr("Can't visit widget : the visitor is null");
234 }
242 }
235 }
243 }
236
244
237 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
245 bool VisualizationZoneWidget::canDrop(const Variable &variable) const
238 {
246 {
239 // A tab can always accomodate a variable
247 // A tab can always accomodate a variable
240 Q_UNUSED(variable);
248 Q_UNUSED(variable);
241 return true;
249 return true;
242 }
250 }
243
251
244 bool VisualizationZoneWidget::contains(const Variable &variable) const
252 bool VisualizationZoneWidget::contains(const Variable &variable) const
245 {
253 {
246 Q_UNUSED(variable);
254 Q_UNUSED(variable);
247 return false;
255 return false;
248 }
256 }
249
257
250 QString VisualizationZoneWidget::name() const
258 QString VisualizationZoneWidget::name() const
251 {
259 {
252 return ui->zoneNameLabel->text();
260 return ui->zoneNameLabel->text();
253 }
261 }
254
262
255 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
263 void VisualizationZoneWidget::onVariableAdded(std::shared_ptr<Variable> variable)
256 {
264 {
257 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
265 QMetaObject::invokeMethod(&sqpApp->variableController(), "onAddSynchronized",
258 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
266 Qt::QueuedConnection, Q_ARG(std::shared_ptr<Variable>, variable),
259 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
267 Q_ARG(QUuid, impl->m_SynchronisationGroupId));
260 }
268 }
@@ -1,83 +1,51
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>VisualizationGraphWidget</class>
3 <class>VisualizationGraphWidget</class>
4 <widget class="QWidget" name="VisualizationGraphWidget">
4 <widget class="QWidget" name="VisualizationGraphWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>400</width>
9 <width>400</width>
10 <height>300</height>
10 <height>300</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="windowTitle">
13 <property name="windowTitle">
14 <string>Form</string>
14 <string>Form</string>
15 </property>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <item>
17 <property name="leftMargin">
18 <widget class="QWidget" name="infobar" native="true">
18 <number>0</number>
19 <layout class="QHBoxLayout" name="horizontalLayout_2">
19 </property>
20 <property name="leftMargin">
20 <property name="topMargin">
21 <number>0</number>
21 <number>0</number>
22 </property>
22 </property>
23 <property name="topMargin">
23 <property name="rightMargin">
24 <number>0</number>
24 <number>0</number>
25 </property>
25 </property>
26 <property name="rightMargin">
26 <property name="bottomMargin">
27 <number>0</number>
27 <number>0</number>
28 </property>
28 </property>
29 <property name="bottomMargin">
30 <number>0</number>
31 </property>
32 <item>
33 <widget class="QLabel" name="graphNameLabel">
34 <property name="styleSheet">
35 <string notr="true">font: 75 9pt &quot;MS Shell Dlg 2&quot;;</string>
36 </property>
37 <property name="text">
38 <string>TextLabel</string>
39 </property>
40 <property name="textFormat">
41 <enum>Qt::AutoText</enum>
42 </property>
43 <property name="alignment">
44 <set>Qt::AlignCenter</set>
45 </property>
46 </widget>
47 </item>
48 <item>
49 <widget class="QToolButton" name="closeButton">
50 <property name="styleSheet">
51 <string notr="true">background-color: transparent;</string>
52 </property>
53 <property name="text">
54 <string>Close</string>
55 </property>
56 </widget>
57 </item>
58 </layout>
59 </widget>
60 </item>
61 <item>
29 <item>
62 <widget class="QCustomPlot" name="widget" native="true">
30 <widget class="QCustomPlot" name="widget" native="true">
63 <property name="sizePolicy">
31 <property name="sizePolicy">
64 <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
32 <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
65 <horstretch>0</horstretch>
33 <horstretch>0</horstretch>
66 <verstretch>0</verstretch>
34 <verstretch>0</verstretch>
67 </sizepolicy>
35 </sizepolicy>
68 </property>
36 </property>
69 </widget>
37 </widget>
70 </item>
38 </item>
71 </layout>
39 </layout>
72 </widget>
40 </widget>
73 <customwidgets>
41 <customwidgets>
74 <customwidget>
42 <customwidget>
75 <class>QCustomPlot</class>
43 <class>QCustomPlot</class>
76 <extends>QWidget</extends>
44 <extends>QWidget</extends>
77 <header>Visualization/qcustomplot.h</header>
45 <header>Visualization/qcustomplot.h</header>
78 <container>1</container>
46 <container>1</container>
79 </customwidget>
47 </customwidget>
80 </customwidgets>
48 </customwidgets>
81 <resources/>
49 <resources/>
82 <connections/>
50 <connections/>
83 </ui>
51 </ui>
@@ -1,57 +1,73
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>VisualizationTabWidget</class>
3 <class>VisualizationTabWidget</class>
4 <widget class="QWidget" name="VisualizationTabWidget">
4 <widget class="QWidget" name="VisualizationTabWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>400</width>
9 <width>400</width>
10 <height>300</height>
10 <height>300</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="windowTitle">
13 <property name="windowTitle">
14 <string>Form</string>
14 <string>Form</string>
15 </property>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <property name="leftMargin">
17 <property name="leftMargin">
18 <number>0</number>
18 <number>0</number>
19 </property>
19 </property>
20 <property name="topMargin">
20 <property name="topMargin">
21 <number>0</number>
21 <number>0</number>
22 </property>
22 </property>
23 <property name="rightMargin">
23 <property name="rightMargin">
24 <number>0</number>
24 <number>0</number>
25 </property>
25 </property>
26 <property name="bottomMargin">
26 <property name="bottomMargin">
27 <number>0</number>
27 <number>0</number>
28 </property>
28 </property>
29 <item>
29 <item>
30 <widget class="QScrollArea" name="scrollArea">
30 <widget class="QScrollArea" name="scrollArea">
31 <property name="frameShape">
31 <property name="frameShape">
32 <enum>QFrame::NoFrame</enum>
32 <enum>QFrame::NoFrame</enum>
33 </property>
33 </property>
34 <property name="frameShadow">
34 <property name="frameShadow">
35 <enum>QFrame::Sunken</enum>
35 <enum>QFrame::Sunken</enum>
36 </property>
36 </property>
37 <property name="widgetResizable">
37 <property name="widgetResizable">
38 <bool>true</bool>
38 <bool>true</bool>
39 </property>
39 </property>
40 <widget class="QWidget" name="scrollAreaWidgetContents">
40 <widget class="QWidget" name="scrollAreaWidgetContents">
41 <property name="geometry">
41 <property name="geometry">
42 <rect>
42 <rect>
43 <x>0</x>
43 <x>0</x>
44 <y>0</y>
44 <y>0</y>
45 <width>400</width>
45 <width>400</width>
46 <height>300</height>
46 <height>300</height>
47 </rect>
47 </rect>
48 </property>
48 </property>
49 <layout class="QVBoxLayout" name="verticalLayout_3"/>
49 <layout class="QVBoxLayout" name="verticalLayout_3">
50 <property name="spacing">
51 <number>3</number>
52 </property>
53 <property name="leftMargin">
54 <number>0</number>
55 </property>
56 <property name="topMargin">
57 <number>0</number>
58 </property>
59 <property name="rightMargin">
60 <number>0</number>
61 </property>
62 <property name="bottomMargin">
63 <number>0</number>
64 </property>
65 </layout>
50 </widget>
66 </widget>
51 </widget>
67 </widget>
52 </item>
68 </item>
53 </layout>
69 </layout>
54 </widget>
70 </widget>
55 <resources/>
71 <resources/>
56 <connections/>
72 <connections/>
57 </ui>
73 </ui>
@@ -1,28 +1,40
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>VisualizationWidget</class>
3 <class>VisualizationWidget</class>
4 <widget class="QWidget" name="VisualizationWidget">
4 <widget class="QWidget" name="VisualizationWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>400</width>
9 <width>400</width>
10 <height>300</height>
10 <height>300</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="windowTitle">
13 <property name="windowTitle">
14 <string>Form</string>
14 <string>Form</string>
15 </property>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout">
16 <layout class="QVBoxLayout" name="verticalLayout">
17 <property name="leftMargin">
18 <number>0</number>
19 </property>
20 <property name="topMargin">
21 <number>0</number>
22 </property>
23 <property name="rightMargin">
24 <number>0</number>
25 </property>
26 <property name="bottomMargin">
27 <number>0</number>
28 </property>
17 <item>
29 <item>
18 <widget class="QTabWidget" name="tabWidget">
30 <widget class="QTabWidget" name="tabWidget">
19 <property name="currentIndex">
31 <property name="currentIndex">
20 <number>-1</number>
32 <number>-1</number>
21 </property>
33 </property>
22 </widget>
34 </widget>
23 </item>
35 </item>
24 </layout>
36 </layout>
25 </widget>
37 </widget>
26 <resources/>
38 <resources/>
27 <connections/>
39 <connections/>
28 </ui>
40 </ui>
@@ -1,86 +1,117
1 <?xml version="1.0" encoding="UTF-8"?>
1 <?xml version="1.0" encoding="UTF-8"?>
2 <ui version="4.0">
2 <ui version="4.0">
3 <class>VisualizationZoneWidget</class>
3 <class>VisualizationZoneWidget</class>
4 <widget class="QWidget" name="VisualizationZoneWidget">
4 <widget class="QWidget" name="VisualizationZoneWidget">
5 <property name="geometry">
5 <property name="geometry">
6 <rect>
6 <rect>
7 <x>0</x>
7 <x>0</x>
8 <y>0</y>
8 <y>0</y>
9 <width>400</width>
9 <width>400</width>
10 <height>300</height>
10 <height>300</height>
11 </rect>
11 </rect>
12 </property>
12 </property>
13 <property name="windowTitle">
13 <property name="windowTitle">
14 <string>Form</string>
14 <string>Form</string>
15 </property>
15 </property>
16 <layout class="QVBoxLayout" name="verticalLayout_2">
16 <layout class="QVBoxLayout" name="verticalLayout_2">
17 <property name="spacing">
18 <number>0</number>
19 </property>
20 <property name="leftMargin">
21 <number>0</number>
22 </property>
23 <property name="topMargin">
24 <number>0</number>
25 </property>
26 <property name="rightMargin">
27 <number>0</number>
28 </property>
29 <property name="bottomMargin">
30 <number>0</number>
31 </property>
17 <item>
32 <item>
18 <widget class="QWidget" name="infobar" native="true">
33 <widget class="QWidget" name="infobar" native="true">
19 <property name="sizePolicy">
34 <property name="sizePolicy">
20 <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
35 <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
21 <horstretch>0</horstretch>
36 <horstretch>0</horstretch>
22 <verstretch>0</verstretch>
37 <verstretch>0</verstretch>
23 </sizepolicy>
38 </sizepolicy>
24 </property>
39 </property>
25 <layout class="QHBoxLayout" name="horizontalLayout">
40 <layout class="QHBoxLayout" name="horizontalLayout">
41 <property name="spacing">
42 <number>0</number>
43 </property>
26 <property name="leftMargin">
44 <property name="leftMargin">
27 <number>0</number>
45 <number>0</number>
28 </property>
46 </property>
29 <property name="topMargin">
47 <property name="topMargin">
30 <number>0</number>
48 <number>0</number>
31 </property>
49 </property>
32 <property name="rightMargin">
50 <property name="rightMargin">
33 <number>0</number>
51 <number>0</number>
34 </property>
52 </property>
35 <property name="bottomMargin">
53 <property name="bottomMargin">
36 <number>0</number>
54 <number>0</number>
37 </property>
55 </property>
38 <item>
56 <item>
39 <widget class="QLabel" name="zoneNameLabel">
57 <widget class="QLabel" name="zoneNameLabel">
40 <property name="styleSheet">
58 <property name="styleSheet">
41 <string notr="true">color: rgb(127, 127, 127);
59 <string notr="true">color: rgb(127, 127, 127);
42 </string>
60 </string>
43 </property>
61 </property>
44 <property name="text">
62 <property name="text">
45 <string>TextLabel</string>
63 <string>TextLabel</string>
46 </property>
64 </property>
47 </widget>
65 </widget>
48 </item>
66 </item>
49 <item>
67 <item>
50 <widget class="QToolButton" name="closeButton">
68 <widget class="QToolButton" name="closeButton">
51 <property name="styleSheet">
69 <property name="styleSheet">
52 <string notr="true">background-color: transparent;</string>
70 <string notr="true">background-color: transparent;</string>
53 </property>
71 </property>
54 <property name="text">
72 <property name="text">
55 <string>Close</string>
73 <string>Close</string>
56 </property>
74 </property>
57 </widget>
75 </widget>
58 </item>
76 </item>
59 </layout>
77 </layout>
60 </widget>
78 </widget>
61 </item>
79 </item>
62 <item>
80 <item>
63 <widget class="QFrame" name="visualizationZoneFrame">
81 <widget class="QFrame" name="visualizationZoneFrame">
64 <property name="sizePolicy">
82 <property name="sizePolicy">
65 <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
83 <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
66 <horstretch>0</horstretch>
84 <horstretch>0</horstretch>
67 <verstretch>0</verstretch>
85 <verstretch>0</verstretch>
68 </sizepolicy>
86 </sizepolicy>
69 </property>
87 </property>
70 <property name="frameShape">
88 <property name="frameShape">
71 <enum>QFrame::Box</enum>
89 <enum>QFrame::Box</enum>
72 </property>
90 </property>
73 <property name="frameShadow">
91 <property name="frameShadow">
74 <enum>QFrame::Raised</enum>
92 <enum>QFrame::Raised</enum>
75 </property>
93 </property>
76 <property name="lineWidth">
94 <property name="lineWidth">
77 <number>1</number>
95 <number>1</number>
78 </property>
96 </property>
79 <layout class="QVBoxLayout" name="verticalLayout"/>
97 <layout class="QVBoxLayout" name="verticalLayout">
98 <property name="leftMargin">
99 <number>0</number>
100 </property>
101 <property name="topMargin">
102 <number>0</number>
103 </property>
104 <property name="rightMargin">
105 <number>0</number>
106 </property>
107 <property name="bottomMargin">
108 <number>0</number>
109 </property>
110 </layout>
80 </widget>
111 </widget>
81 </item>
112 </item>
82 </layout>
113 </layout>
83 </widget>
114 </widget>
84 <resources/>
115 <resources/>
85 <connections/>
116 <connections/>
86 </ui>
117 </ui>
General Comments 0
You need to be logged in to leave comments. Login now