From 94000392d1e8fe4c5975e4cfde7281ecde8b4c92 2017-09-11 09:44:38 From: Alexandre Leroux Date: 2017-09-11 09:44:38 Subject: [PATCH] Adds button on plot overlay to show/hide x-axis properties --- diff --git a/gui/include/Visualization/VisualizationGraphRenderingDelegate.h b/gui/include/Visualization/VisualizationGraphRenderingDelegate.h index e3189f3..8be36b6 100644 --- a/gui/include/Visualization/VisualizationGraphRenderingDelegate.h +++ b/gui/include/Visualization/VisualizationGraphRenderingDelegate.h @@ -5,6 +5,7 @@ class QCustomPlot; class QMouseEvent; +class Unit; class VisualizationGraphWidget; class VisualizationGraphRenderingDelegate { @@ -16,6 +17,9 @@ public: 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; 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/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 @@ -24,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) { @@ -45,6 +76,11 @@ 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 @@ -60,6 +96,20 @@ void initClosePixmapStyle(QCPItemPixmap &pixmap) noexcept 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 @@ -80,7 +130,10 @@ struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegateP m_PointTracer{new QCPItemTracer{&m_Plot}}, m_TracerTimer{}, m_ClosePixmap{new QCPItemPixmap{&m_Plot}}, - m_TitleText{new QCPItemText{&m_Plot}} + m_TitleText{new QCPItemText{&m_Plot}}, + m_XAxisPixmap{new QCPItemPixmap{&m_Plot}}, + m_ShowXAxis{true}, + m_XAxisLabel{} { initPointTracerStyle(*m_PointTracer); @@ -103,6 +156,34 @@ struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegateP 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; @@ -110,6 +191,9 @@ struct VisualizationGraphRenderingDelegate::VisualizationGraphRenderingDelegateP 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( @@ -161,6 +245,28 @@ 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); diff --git a/gui/src/Visualization/VisualizationGraphWidget.cpp b/gui/src/Visualization/VisualizationGraphWidget.cpp index c5b9b95..b7ae3c0 100644 --- a/gui/src/Visualization/VisualizationGraphWidget.cpp +++ b/gui/src/Visualization/VisualizationGraphWidget.cpp @@ -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();