From 1cb481e11c973b16d3949ad4055533e92e1f50bd 2017-09-11 09:47:18 From: Alexandre Leroux Date: 2017-09-11 09:47:18 Subject: [PATCH] Merge branch 'feature/GraphCleaning' into develop --- diff --git a/gui/include/Visualization/IGraphSynchronizer.h b/gui/include/Visualization/IGraphSynchronizer.h new file mode 100644 index 0000000..cd05317 --- /dev/null +++ b/gui/include/Visualization/IGraphSynchronizer.h @@ -0,0 +1,24 @@ +#ifndef SCIQLOP_IGRAPHSYNCHRONIZER_H +#define SCIQLOP_IGRAPHSYNCHRONIZER_H + +class VisualizationGraphWidget; + +/** + * @brief The IVisualizationSynchronizer interface represents a delegate used to manage the + * synchronization between graphs, applying them processes or properties to ensure their + * synchronization + */ +class IGraphSynchronizer { + +public: + virtual ~IGraphSynchronizer() = default; + + /** + * Adds a graph as a new synchronized element, and sets its properties so that its + * synchronization is maintained with all other graphs managed by the synchonizer + * @param graph the graph to add in the synchronization + */ + virtual void addGraph(VisualizationGraphWidget &graph) const = 0; +}; + +#endif // SCIQLOP_IGRAPHSYNCHRONIZER_H diff --git a/gui/include/Visualization/QCustomPlotSynchronizer.h b/gui/include/Visualization/QCustomPlotSynchronizer.h new file mode 100644 index 0000000..3d8a397 --- /dev/null +++ b/gui/include/Visualization/QCustomPlotSynchronizer.h @@ -0,0 +1,26 @@ +#ifndef SCIQLOP_QCUSTOMPLOTSYNCHRONIZER_H +#define SCIQLOP_QCUSTOMPLOTSYNCHRONIZER_H + +#include "Visualization/IGraphSynchronizer.h" + +#include + +/** + * @brief The QCustomPlotSynchronizer class is an implementation of IGraphSynchronizer that handles + * graphs using QCustomPlot elements + * @sa IGraphSynchronizer + * @sa QCustomPlot + */ +class QCustomPlotSynchronizer : public IGraphSynchronizer { +public: + explicit QCustomPlotSynchronizer(); + + /// @sa IGraphSynchronizer::addGraph() + virtual void addGraph(VisualizationGraphWidget &graph) const override; + +private: + class QCustomPlotSynchronizerPrivate; + spimpl::unique_impl_ptr impl; +}; + +#endif // SCIQLOP_QCUSTOMPLOTSYNCHRONIZER_H diff --git a/gui/include/Visualization/VisualizationGraphRenderingDelegate.h b/gui/include/Visualization/VisualizationGraphRenderingDelegate.h index 7bdd366..8be36b6 100644 --- a/gui/include/Visualization/VisualizationGraphRenderingDelegate.h +++ b/gui/include/Visualization/VisualizationGraphRenderingDelegate.h @@ -5,13 +5,24 @@ class QCustomPlot; class QMouseEvent; +class Unit; +class VisualizationGraphWidget; class VisualizationGraphRenderingDelegate { public: - explicit VisualizationGraphRenderingDelegate(QCustomPlot &plot); + /// Ctor + /// @param graphWidget the graph widget to which the delegate is associated + /// @remarks the graph widget must exist throughout the life cycle of the delegate + explicit VisualizationGraphRenderingDelegate(VisualizationGraphWidget &graphWidget); void onMouseMove(QMouseEvent *event) noexcept; + /// Sets properties of the plot's axes + void setAxesProperties(const Unit &xAxisUnit, const Unit &valuesUnit) noexcept; + + /// Shows or hides graph overlay (name, close button, etc.) + void showGraphOverlay(bool show) noexcept; + private: class VisualizationGraphRenderingDelegatePrivate; spimpl::unique_impl_ptr impl; diff --git a/gui/include/Visualization/VisualizationGraphWidget.h b/gui/include/Visualization/VisualizationGraphWidget.h index c40ee8b..3d2892f 100644 --- a/gui/include/Visualization/VisualizationGraphWidget.h +++ b/gui/include/Visualization/VisualizationGraphWidget.h @@ -13,6 +13,7 @@ Q_DECLARE_LOGGING_CATEGORY(LOG_VisualizationGraphWidget) class QCPRange; +class QCustomPlot; class SqpRange; class Variable; @@ -23,6 +24,9 @@ class VisualizationGraphWidget; class VisualizationGraphWidget : public QWidget, public IVisualizationWidget { Q_OBJECT + friend class QCustomPlotSynchronizer; + friend class VisualizationGraphRenderingDelegate; + public: explicit VisualizationGraphWidget(const QString &name = {}, QWidget *parent = 0); virtual ~VisualizationGraphWidget(); @@ -52,9 +56,13 @@ signals: void requestDataLoading(QVector > variable, const SqpRange &range, const SqpRange &oldRange, bool synchronise); - void variableAdded(std::shared_ptr var); +protected: + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; + + QCustomPlot &plot() noexcept; private: Ui::VisualizationGraphWidget *ui; diff --git a/gui/meson.build b/gui/meson.build index db498e7..a8ece56 100644 --- a/gui/meson.build +++ b/gui/meson.build @@ -53,6 +53,7 @@ gui_sources = [ 'src/Visualization/VisualizationWidget.cpp', 'src/Visualization/VisualizationZoneWidget.cpp', 'src/Visualization/qcustomplot.cpp', + 'src/Visualization/QCustomPlotSynchronizer.cpp', 'src/Visualization/operations/GenerateVariableMenuOperation.cpp', 'src/Visualization/operations/MenuBuilder.cpp', 'src/Visualization/operations/RemoveVariableOperation.cpp', diff --git a/gui/resources/icones/down.png b/gui/resources/icones/down.png new file mode 100644 index 0000000000000000000000000000000000000000..1e628f49dd7c8076d7c898a900f33f52cca2d006 GIT binary patch literal 1231 zc$|e)>r;|>82v$S`l>64S|KVJTbpGCa99 z>;V9doJe-8RV53AZLCwn+}mmu=x`Wk2W*81-gm~j+X*7~90tI_Wq}xQj?^CO4N z+L3A@&18?v{E~cf z1lbhZ@ob!=O#ASwRk*abA2SHk?v(g^VAEPk2L3pyhnTKmlDP4_v7Dn)+XK+f_~&~ zh{Zi+I~0{Zh#u4u4@7WRFTA+r^m^jspkf12tRZSDLW#|_&a5%8RXIORm#gzGB58+; zzw{7(w&(9N)G#XX+h^#)Uex%$Z6t&CxiBpSOzfG#6qWdplV<30RhfMLO=?2uME3Bm z*0;mQLj);c{;w%s(^?Jxn^f6$C^C?)t&=&h( z#ghTdjkEMf!h^vts2)Z55nLXOWXt?dc}qWpxlw{4;7=_ARoayobG<4|EpgzsQWe^` zA;(Ux-&uMNPhJFeuQR8}^~ac6nm0M5q`mp`G4EhoV4+se;0m2?4zrP9%VRUzwF&4~ zNgE~vcJ0dJ-2CpBXcrf#V6RzIX$$Z&z)3_32?u%lOG+9C)Kp`5@r{qy7jdYMrw3OsmmDjFOWR1};tt1OELsS|eMZu2VcjN%I@d zo0hA9Iu0VIUKL)gyFXe##;7@f1sO^5v&f|(Er zoFcILbu!5!$=v4ik5Q*|AnP_co@b^_|NjZN^ZB8}N}Ek-POu=!va z3D*OgUNOU-@3EpNccX?CSO8DAoIBh8!q4*G?_)e3Q%8H*XuT~IY&ijHUgtd zR(Z8f20wxt$0CY(|J)hp71C^RWfTe(5BT|`;_>BDtUPA@XfGvUdXD6B0(AWZ^&_3% zcjw_f?LholRU8s7!%DPYzaK)o>VT>a4h&!(vHBsiQgkw<4fqJ#XxfOl?{3Ap?h0M^ z&b+0$W670j9=rz8XPppEG*4A`j4m|}Ci%_1{Bk+0X9}niq16g}E(H3hk;$S+Z{WR* zwG|0Z!l+*nD*Tu$h+v4k;H?a!Ziiz%Lo;mg4nJ za0`PlBg3pY5=T@4oLB{=Bs@Kc@Gs?&OyT=6NSJN-S9F zFj0dwk8$G@rU;|Z=Zm!;Dfm{ga=hH}PIk+M8LY)i%w}aidVJk3{(Qcr?;2&>`pRXU zoeTtkjG6c4%PME(Zrio{GT&z3kUH(T`kChMoj?61EjzyLd@}cKy9VCPHueu^eY^iF zac^DC#+bTCKCu**gDe+5{)j3NWD#`mf1K^;`ksNS{iY2q$W0|nzr#aBb zbrSKDyAmvBt*h-k(9NKCeE;TA@4B%akioBgAxX_W7m^958PzP z>05tPpm8$e4ugGRQ(xtn%-g57jG4=T={b{tA?E2TY3N%h-P&u}ImR-EA zc>fW;)E7og^|ieVzB4R2w!a{uX06uMogOTcJ!3UXwQBd3zcg)7IV~qp9Pl_>Nl@Us zoMS$tO60eOj{P}>oax7}wFm8%t>PW2dRbYB$+;on)BeUl0atLR^$^!fjd4KHp$j293GF@aa z`1duY*FlG&XaC%8!48&&kLAy!Sk^Kh_;Gfph~sJogMB;2z2@?(PY&OvY{2J`QnRXG zZ(6r}bj;!GsX_j^?g=6XbWZO}?flrSbnBz(L5>qDO~)8x`s&xe{C%(CqdAAGfqCbG zKn98Z*4vbBSTgk7x0M!rBf@a(z5ji|9Nq_I)7}byJin}6vFCoo(kquAR{WYYlkcQW z)8C5~H8E44-hW?p_Zq`I?XTh8@3$K6TevDm^x)I*mq*v%j@xm0J;UL4=~uH}`G>oH zyxh0GowrTUq^d9JxjmD#Tf@gzlb!`1olScGN$*Hzk%+(1Cn#a-c=bo~0$ss`KYcl! z2Y!6CT-@KZzLVi``I}iBQMT5Ze^M{Fv9x^ry-|=cvcAB~^YiY_I=_$HVpN*Cicones/dataSourceProduct.png icones/dataSourceRoot.png icones/delete.png + icones/down.png icones/openInspector.png icones/next.png icones/plot.png icones/previous.png icones/unplot.png + icones/up.png diff --git a/gui/src/Visualization/QCustomPlotSynchronizer.cpp b/gui/src/Visualization/QCustomPlotSynchronizer.cpp new file mode 100644 index 0000000..34796d1 --- /dev/null +++ b/gui/src/Visualization/QCustomPlotSynchronizer.cpp @@ -0,0 +1,30 @@ +#include "Visualization/QCustomPlotSynchronizer.h" + +#include "Visualization/VisualizationGraphWidget.h" +#include "Visualization/qcustomplot.h" + +struct QCustomPlotSynchronizer::QCustomPlotSynchronizerPrivate { + explicit QCustomPlotSynchronizerPrivate() + : m_MarginGroup{std::make_unique(nullptr)} + { + } + + /// Sets the same margin sides for all added plot elements + std::unique_ptr m_MarginGroup; +}; + +QCustomPlotSynchronizer::QCustomPlotSynchronizer() + : impl{spimpl::make_unique_impl()} +{ +} + +void QCustomPlotSynchronizer::addGraph(VisualizationGraphWidget &graph) const +{ + // Adds all plot elements of the graph to the margin group: all these elements will then have + // the same margin sides + auto &plot = graph.plot(); + for (auto axisRect : plot.axisRects()) { + // Sames margin sides at left and right + axisRect->setMarginGroup(QCP::msLeft | QCP::msRight, impl->m_MarginGroup.get()); + } +} diff --git a/gui/src/Visualization/VisualizationGraphHelper.cpp b/gui/src/Visualization/VisualizationGraphHelper.cpp index bdd5a70..141b9b9 100644 --- a/gui/src/Visualization/VisualizationGraphHelper.cpp +++ b/gui/src/Visualization/VisualizationGraphHelper.cpp @@ -17,44 +17,6 @@ public: void appendGraphData(const QCPGraphData &data) { mData.append(data); } }; - -/// Format for datetimes on a axis -const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss"); - -/// Generates the appropriate ticker for an axis, depending on whether the axis displays time or -/// non-time data -QSharedPointer axisTicker(bool isTimeAxis) -{ - if (isTimeAxis) { - auto dateTicker = QSharedPointer::create(); - dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT); - dateTicker->setDateTimeSpec(Qt::UTC); - - return dateTicker; - } - else { - // default ticker - return QSharedPointer::create(); - } -} - -/// Sets axes properties according to the properties of a data series. Not thread safe -template -void setAxesProperties(const DataSeries &dataSeries, QCustomPlot &plot) noexcept -{ - /// @todo : for the moment, no control is performed on the axes: the units and the tickers - /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph - auto setAxisProperties = [](auto axis, const auto &unit) { - // label (unit name) - axis->setLabel(unit.m_Name); - - // ticker (depending on the type of unit) - axis->setTicker(axisTicker(unit.m_TimeUnit)); - }; - setAxisProperties(plot.xAxis, dataSeries.xAxisUnit()); - setAxisProperties(plot.yAxis, dataSeries.valuesUnit()); -} - /** * Struct used to create plottables, depending on the type of the data series from which to create * them @@ -99,11 +61,6 @@ struct PlottablesCreator +#include + +#include + namespace { +/// Name of the axes layer in QCustomPlot +const auto AXES_LAYER = QStringLiteral("axes"); + const auto DATETIME_FORMAT = QStringLiteral("yyyy/MM/dd hh:mm:ss:zzz"); +/// Format for datetimes on a axis +const auto DATETIME_TICKER_FORMAT = QStringLiteral("yyyy/MM/dd \nhh:mm:ss"); + +/// Icon used to show x-axis properties +const auto HIDE_AXIS_ICON_PATH = QStringLiteral(":/icones/down.png"); + +/// Name of the overlay layer in QCustomPlot +const auto OVERLAY_LAYER = QStringLiteral("overlay"); + +/// Pixmap used to show x-axis properties +const auto SHOW_AXIS_ICON_PATH = QStringLiteral(":/icones/up.png"); + const auto TOOLTIP_FORMAT = QStringLiteral("key: %1\nvalue: %2"); /// Offset used to shift the tooltip of the mouse @@ -18,6 +38,23 @@ const auto TOOLTIP_RECT = QRect{10, 10, 10, 10}; /// Timeout after which the tooltip is displayed const auto TOOLTIP_TIMEOUT = 500; +/// Generates the appropriate ticker for an axis, depending on whether the axis displays time or +/// non-time data +QSharedPointer axisTicker(bool isTimeAxis) +{ + if (isTimeAxis) { + auto dateTicker = QSharedPointer::create(); + dateTicker->setDateTimeFormat(DATETIME_TICKER_FORMAT); + dateTicker->setDateTimeSpec(Qt::UTC); + + return dateTicker; + } + else { + // default ticker + return QSharedPointer::create(); + } +} + /// Formats a data value according to the axis on which it is present QString formatValue(double value, const QCPAxis &axis) { @@ -39,25 +76,129 @@ void initPointTracerStyle(QCPItemTracer &tracer) noexcept tracer.setBrush(Qt::black); } +QPixmap pixmap(const QString &iconPath) noexcept +{ + return QIcon{iconPath}.pixmap(QSize{16, 16}); +} + +void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept +{ + // Icon + pixmap.setPixmap( + sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton).pixmap(QSize{16, 16})); + + // Position + pixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio); + pixmap.topLeft->setCoords(1, 0); + pixmap.setClipToAxisRect(false); + + // Can be selected + pixmap.setSelectable(true); +} + +void initXAxisPixmapStyle(QCPItemPixmap &itemPixmap) noexcept +{ + // Icon + itemPixmap.setPixmap(pixmap(HIDE_AXIS_ICON_PATH)); + + // Position + itemPixmap.topLeft->setType(QCPItemPosition::ptAxisRectRatio); + itemPixmap.topLeft->setCoords(0, 1); + itemPixmap.setClipToAxisRect(false); + + // Can be selected + itemPixmap.setSelectable(true); +} + +void initTitleTextStyle(QCPItemText &text) noexcept +{ + // Font and background styles + text.setColor(Qt::gray); + text.setBrush(Qt::white); + + // Position + text.setPositionAlignment(Qt::AlignTop | Qt::AlignLeft); + text.position->setType(QCPItemPosition::ptAxisRectRatio); + text.position->setCoords(0.5, 0); +} + } // namespace struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegatePrivate { - explicit VisualizationGraphRenderingDelegatePrivate(QCustomPlot &plot) - : m_Plot{plot}, m_PointTracer{new QCPItemTracer{&plot}}, m_TracerTimer{} + explicit VisualizationGraphRenderingDelegatePrivate(VisualizationGraphWidget &graphWidget) + : m_Plot{graphWidget.plot()}, + m_PointTracer{new QCPItemTracer{&m_Plot}}, + m_TracerTimer{}, + m_ClosePixmap{new QCPItemPixmap{&m_Plot}}, + m_TitleText{new QCPItemText{&m_Plot}}, + m_XAxisPixmap{new QCPItemPixmap{&m_Plot}}, + m_ShowXAxis{true}, + m_XAxisLabel{} { initPointTracerStyle(*m_PointTracer); m_TracerTimer.setInterval(TOOLTIP_TIMEOUT); m_TracerTimer.setSingleShot(true); + + // Inits "close button" in plot overlay + m_ClosePixmap->setLayer(OVERLAY_LAYER); + initClosePixmapStyle(*m_ClosePixmap); + + // Connects pixmap selection to graph widget closing + QObject::connect(m_ClosePixmap, &QCPItemPixmap::selectionChanged, + [&graphWidget](bool selected) { + if (selected) { + graphWidget.close(); + } + }); + + // Inits graph name in plot overlay + m_TitleText->setLayer(OVERLAY_LAYER); + m_TitleText->setText(graphWidget.name()); + initTitleTextStyle(*m_TitleText); + + // Inits "show x-axis button" in plot overlay + m_XAxisPixmap->setLayer(OVERLAY_LAYER); + initXAxisPixmapStyle(*m_XAxisPixmap); + + // Connects pixmap selection to graph x-axis showing/hiding + QObject::connect(m_XAxisPixmap, &QCPItemPixmap::selectionChanged, [this]() { + if (m_XAxisPixmap->selected()) { + // Changes the selection state and refreshes the x-axis + m_ShowXAxis = !m_ShowXAxis; + updateXAxisState(); + m_Plot.layer(AXES_LAYER)->replot(); + + // Deselects the x-axis pixmap and updates icon + m_XAxisPixmap->setSelected(false); + m_XAxisPixmap->setPixmap( + pixmap(m_ShowXAxis ? HIDE_AXIS_ICON_PATH : SHOW_AXIS_ICON_PATH)); + m_Plot.layer(OVERLAY_LAYER)->replot(); + } + }); + } + + /// Updates state of x-axis according to the current selection of x-axis pixmap + /// @remarks the method doesn't call plot refresh + void updateXAxisState() noexcept + { + m_Plot.xAxis->setTickLabels(m_ShowXAxis); + m_Plot.xAxis->setLabel(m_ShowXAxis ? m_XAxisLabel : QString{}); } QCustomPlot &m_Plot; QCPItemTracer *m_PointTracer; QTimer m_TracerTimer; + QCPItemPixmap *m_ClosePixmap; /// Graph's close button + QCPItemText *m_TitleText; /// Graph's title + QCPItemPixmap *m_XAxisPixmap; + bool m_ShowXAxis; /// X-axis properties are shown or hidden + QString m_XAxisLabel; }; -VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate(QCustomPlot &plot) - : impl{spimpl::make_unique_impl(plot)} +VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegate( + VisualizationGraphWidget &graphWidget) + : impl{spimpl::make_unique_impl(graphWidget)} { } @@ -103,3 +244,32 @@ void VisualizationGraphRenderingDelegate::onMouseMove(QMouseEvent *event) noexce } } } + +void VisualizationGraphRenderingDelegate::setAxesProperties(const Unit &xAxisUnit, + const Unit &valuesUnit) noexcept +{ + // Stores x-axis label to be able to retrieve it when x-axis pixmap is unselected + impl->m_XAxisLabel = xAxisUnit.m_Name; + + auto setAxisProperties = [](auto axis, const auto &unit) { + // label (unit name) + axis->setLabel(unit.m_Name); + + // ticker (depending on the type of unit) + axis->setTicker(axisTicker(unit.m_TimeUnit)); + }; + setAxisProperties(impl->m_Plot.xAxis, xAxisUnit); + setAxisProperties(impl->m_Plot.yAxis, valuesUnit); + + // Updates x-axis state + impl->updateXAxisState(); + + impl->m_Plot.layer(AXES_LAYER)->replot(); +} + +void VisualizationGraphRenderingDelegate::showGraphOverlay(bool show) noexcept +{ + auto overlay = impl->m_Plot.layer(OVERLAY_LAYER); + overlay->setVisible(show); + overlay->replot(); +} diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index a8d4d3a..b7ae3c0 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -28,11 +28,15 @@ const auto VERTICAL_ZOOM_MODIFIER = Qt::ControlModifier; struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { - explicit VisualizationGraphWidgetPrivate() - : m_DoAcquisition{true}, m_IsCalibration{false}, m_RenderingDelegate{nullptr} + explicit VisualizationGraphWidgetPrivate(const QString &name) + : m_Name{name}, + m_DoAcquisition{true}, + m_IsCalibration{false}, + m_RenderingDelegate{nullptr} { } + QString m_Name; // 1 variable -> n qcpplot std::map, PlottablesMap> m_VariableToPlotMultiMap; bool m_DoAcquisition; @@ -45,26 +49,22 @@ struct VisualizationGraphWidget::VisualizationGraphWidgetPrivate { VisualizationGraphWidget::VisualizationGraphWidget(const QString &name, QWidget *parent) : QWidget{parent}, ui{new Ui::VisualizationGraphWidget}, - impl{spimpl::make_unique_impl()} + impl{spimpl::make_unique_impl(name)} { ui->setupUi(this); - // The delegate must be initialized after the ui as it uses the plot - impl->m_RenderingDelegate = std::make_unique(*ui->widget); - - ui->graphNameLabel->setText(name); - // 'Close' options : widget is deleted when closed setAttribute(Qt::WA_DeleteOnClose); - connect(ui->closeButton, &QToolButton::clicked, this, &VisualizationGraphWidget::close); - ui->closeButton->setIcon(sqpApp->style()->standardIcon(QStyle::SP_TitleBarCloseButton)); // Set qcpplot properties : // - Drag (on x-axis) and zoom are enabled // - Mouse wheel on qcpplot is intercepted to determine the zoom orientation - ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); + ui->widget->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectItems); ui->widget->axisRect()->setRangeDrag(Qt::Horizontal); + // The delegate must be initialized after the ui as it uses the plot + impl->m_RenderingDelegate = std::make_unique(*this); + connect(ui->widget, &QCustomPlot::mousePress, this, &VisualizationGraphWidget::onMousePress); connect(ui->widget, &QCustomPlot::mouseRelease, this, &VisualizationGraphWidget::onMouseRelease); @@ -103,6 +103,20 @@ void VisualizationGraphWidget::addVariable(std::shared_ptr variable, S auto createdPlottables = VisualizationGraphHelper::create(variable, *ui->widget); impl->m_VariableToPlotMultiMap.insert({variable, std::move(createdPlottables)}); + // Set axes properties according to the units of the data series + /// @todo : for the moment, no control is performed on the axes: the units and the tickers + /// are fixed for the default x-axis and y-axis of the plot, and according to the new graph + auto xAxisUnit = Unit{}; + auto valuesUnit = Unit{}; + + if (auto dataSeries = variable->dataSeries()) { + dataSeries->lockRead(); + xAxisUnit = dataSeries->xAxisUnit(); + valuesUnit = dataSeries->valuesUnit(); + dataSeries->unlock(); + } + impl->m_RenderingDelegate->setAxesProperties(xAxisUnit, valuesUnit); + connect(variable.get(), SIGNAL(updated()), this, SLOT(onDataCacheVariableUpdated())); auto varRange = variable->range(); @@ -201,7 +215,24 @@ bool VisualizationGraphWidget::contains(const Variable &variable) const QString VisualizationGraphWidget::name() const { - return ui->graphNameLabel->text(); + return impl->m_Name; +} + +void VisualizationGraphWidget::enterEvent(QEvent *event) +{ + Q_UNUSED(event); + impl->m_RenderingDelegate->showGraphOverlay(true); +} + +void VisualizationGraphWidget::leaveEvent(QEvent *event) +{ + Q_UNUSED(event); + impl->m_RenderingDelegate->showGraphOverlay(false); +} + +QCustomPlot &VisualizationGraphWidget::plot() noexcept +{ + return *ui->widget; } void VisualizationGraphWidget::onGraphMenuRequested(const QPoint &pos) noexcept diff --git a/gui/src/Visualization/VisualizationZoneWidget.cpp b/gui/src/Visualization/VisualizationZoneWidget.cpp index 561d20d..cb254e2 100644 --- a/gui/src/Visualization/VisualizationZoneWidget.cpp +++ b/gui/src/Visualization/VisualizationZoneWidget.cpp @@ -1,7 +1,7 @@ #include "Visualization/VisualizationZoneWidget.h" - #include "Visualization/IVisualizationWidgetVisitor.h" +#include "Visualization/QCustomPlotSynchronizer.h" #include "Visualization/VisualizationGraphWidget.h" #include "ui_VisualizationZoneWidget.h" @@ -38,8 +38,13 @@ QString defaultGraphName(const QLayout &layout) struct VisualizationZoneWidget::VisualizationZoneWidgetPrivate { - explicit VisualizationZoneWidgetPrivate() : m_SynchronisationGroupId{QUuid::createUuid()} {} + explicit VisualizationZoneWidgetPrivate() + : m_SynchronisationGroupId{QUuid::createUuid()}, + m_Synchronizer{std::make_unique()} + { + } QUuid m_SynchronisationGroupId; + std::unique_ptr m_Synchronizer; }; VisualizationZoneWidget::VisualizationZoneWidget(const QString &name, QWidget *parent) @@ -68,6 +73,9 @@ VisualizationZoneWidget::~VisualizationZoneWidget() void VisualizationZoneWidget::addGraph(VisualizationGraphWidget *graphWidget) { + // Synchronize new graph with others in the zone + impl->m_Synchronizer->addGraph(*graphWidget); + ui->visualizationZoneFrame->layout()->addWidget(graphWidget); } diff --git a/gui/ui/Visualization/VisualizationGraphWidget.ui b/gui/ui/Visualization/VisualizationGraphWidget.ui index 69df1b0..453c9c4 100644 --- a/gui/ui/Visualization/VisualizationGraphWidget.ui +++ b/gui/ui/Visualization/VisualizationGraphWidget.ui @@ -14,50 +14,18 @@ Form - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - font: 75 9pt "MS Shell Dlg 2"; - - - TextLabel - - - Qt::AutoText - - - Qt::AlignCenter - - - - - - - background-color: transparent; - - - Close - - - - - - + + 0 + + + 0 + + + 0 + + + 0 + diff --git a/gui/ui/Visualization/VisualizationTabWidget.ui b/gui/ui/Visualization/VisualizationTabWidget.ui index 1e886a8..60b3e1c 100644 --- a/gui/ui/Visualization/VisualizationTabWidget.ui +++ b/gui/ui/Visualization/VisualizationTabWidget.ui @@ -46,7 +46,23 @@ 300 - + + + 3 + + + 0 + + + 0 + + + 0 + + + 0 + + diff --git a/gui/ui/Visualization/VisualizationWidget.ui b/gui/ui/Visualization/VisualizationWidget.ui index 1547c1e..dde8671 100644 --- a/gui/ui/Visualization/VisualizationWidget.ui +++ b/gui/ui/Visualization/VisualizationWidget.ui @@ -14,6 +14,18 @@ Form + + 0 + + + 0 + + + 0 + + + 0 + diff --git a/gui/ui/Visualization/VisualizationZoneWidget.ui b/gui/ui/Visualization/VisualizationZoneWidget.ui index fe266c5..79d6be0 100644 --- a/gui/ui/Visualization/VisualizationZoneWidget.ui +++ b/gui/ui/Visualization/VisualizationZoneWidget.ui @@ -14,6 +14,21 @@ Form + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + @@ -23,6 +38,9 @@ + + 0 + 0 @@ -76,7 +94,20 @@ 1 - + + + 0 + + + 0 + + + 0 + + + 0 + +