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

Auto status change to "Under Review"

Approved

Status change > Approved

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