Allow multiple markers on a CachePlotView
ADD
resources/icons/crosshair_blue.svg
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 512 512"
+ style="enable-background:new 0 0 512 512;"
+ xml:space="preserve"
+ width="512"
+ height="512"
+ sodipodi:docname="crosshair_blue.svg"
+ inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
+ id="metadata877"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
+ id="defs875" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview873"
+ showgrid="false"
+ inkscape:zoom="1.671875"
+ inkscape:cx="143.85047"
+ inkscape:cy="184.2243"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1" />
+<path
+ d="M276,512h-40V317h40V512z M276,0h-40v195h40V0z M512,236H316v40h196V236z M195,236H0v40h195V236z M256,276 c11.046,0,20-8.954,20-20c0-11.046-8.954-20-20-20c-11.046,0-20,8.954-20,20C236,267.046,244.954,276,256,276z"
+ id="path870"
+ style="fill:#003b7e;fill-opacity:1" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</svg>
\ No newline at end of file

ADD
resources/icons/crosshair_gold.svg
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 512 512"
+ style="enable-background:new 0 0 512 512;"
+ xml:space="preserve"
+ width="512"
+ height="512"
+ sodipodi:docname="crosshair_gold.svg"
+ inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
+ id="metadata877"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs875" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1848"
+ inkscape:window-height="1016"
+ id="namedview873"
+ showgrid="false"
+ inkscape:zoom="1.671875"
+ inkscape:cx="256"
+ inkscape:cy="279.92523"
+ inkscape:window-x="72"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1" />
+<path
+ d="M276,512h-40V317h40V512z M276,0h-40v195h40V0z M512,236H316v40h196V236z M195,236H0v40h195V236z M256,276 c11.046,0,20-8.954,20-20c0-11.046-8.954-20-20-20c-11.046,0-20,8.954-20,20C236,267.046,244.954,276,256,276z"
+ id="path870"
+ style="fill:#c4820e;fill-opacity:1" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</svg>
\ No newline at end of file

MODIFY
resources/icons/icons.qrc
resources/icons/icons.qrc
<file>moon.svg</file>
<file>led.svg</file>
<file>tile.svg</file>
+ <file>crosshair_blue.svg</file>
+ <file>crosshair_gold.svg</file>
</qresource>
</RCC>

MODIFY
src/cachesim/cacheplotview.cpp
src/cachesim/cacheplotview.cpp
@@ -29,26 +29,59 @@ void constrainInPlotRange(QPointF& pos, QChart* chart) {
namespace Ripes {
+MarkerObjects::MarkerObjects(QObject* parent, QChart* chart, const QLineSeries* _series) : QObject(parent) {
+ marker = new ChartLineMarker(chart, _series);
+ coordX = new QGraphicsSimpleTextItem(chart);
+ coordY = new QGraphicsSimpleTextItem(chart);
+ label = new QGraphicsSimpleTextItem(chart);
+ label->setText(_series->name() + ":");
+ series = _series;
+ coordX->setText("Cycle: ");
+ coordY->setText("Value: ");
+
+ connect(marker, &ChartLineMarker::snappedMarkerChanged,
+ [=] { this->updateCoordinateValues(marker->getMarkerValuePos()); });
+}
+
+void MarkerObjects::clear() {
+ delete marker;
+ delete coordX;
+ delete coordY;
+ delete label;
+}
+
+void MarkerObjects::updateCoordinateValues(const QPointF& pos) {
+ coordX->setText(QString("Cycle: %1").arg(pos.x()));
+ coordY->setText(QString("Value: %1").arg(pos.y()));
+}
+
CachePlotView::CachePlotView(QWidget* parent) : QGraphicsView(new QGraphicsScene, parent) {
setMouseTracking(true);
}
void CachePlotView::enterEvent(QEvent* event) {
- if (m_marker && m_crosshairEnabled) {
- m_marker->show();
+ for (const auto& marker : m_markers) {
+ marker->marker->show();
}
+
QGraphicsView::enterEvent(event);
}
void CachePlotView::leaveEvent(QEvent* event) {
- if (m_marker) {
- m_marker->hide();
+ for (const auto& marker : m_markers) {
+ marker->marker->hide();
}
QGraphicsView::leaveEvent(event);
}
QPixmap CachePlotView::getPlotPixmap() {
- std::vector<QGraphicsItem*> itemsToHide = {m_coordX, m_coordY, m_marker};
+ QVector<QGraphicsItem*> itemsToHide;
+ for (const auto& marker : m_markers) {
+ itemsToHide << marker->marker;
+ itemsToHide << marker->coordX;
+ itemsToHide << marker->coordY;
+ itemsToHide << marker->label;
+ }
for (const auto& i : itemsToHide) {
if (i)
@@ -65,16 +98,30 @@ QPixmap CachePlotView::getPlotPixmap() {
return p;
};
+void CachePlotView::hideSeriesMarker(const QLineSeries* series) {
+ auto marker =
+ std::find_if(m_markers.begin(), m_markers.end(), [=](const auto& mob) { return mob->series == series; });
+ Q_ASSERT(marker != m_markers.end());
+ marker->get()->clear();
+ m_markers.erase(marker);
+ resizeObjects(scene()->sceneRect().size());
+}
+
+void CachePlotView::showSeriesMarker(const QLineSeries* series) {
+ m_markers.emplace_back(std::make_unique<MarkerObjects>(this, m_chart, series));
+ resizeObjects(scene()->sceneRect().size());
+}
+
void CachePlotView::setPlot(QChart* chart) {
if (m_chart) {
// Propagate the previous chart size to the new plot
- chart->resize(m_chart->size());
+ resizeObjects(scene()->sceneRect().size());
}
// Clear any previous plot or plot markers
scene()->clear();
m_tooltip = nullptr;
- m_marker = nullptr;
+ m_markers.clear();
m_chart = chart;
scene()->addItem(chart);
@@ -85,40 +132,34 @@ void CachePlotView::setPlot(QChart* chart) {
}
}
- if (m_chart->series().size() > 0) {
- if (auto* lineSeries = dynamic_cast<QLineSeries*>(m_chart->series()[0])) {
- m_marker = new ChartLineMarker(m_chart, lineSeries);
- connect(m_marker, &ChartLineMarker::snappedMarkerChanged,
- [=] { this->updateCoordinateValues(m_marker->getMarkerValuePos()); });
-
- m_marker->setVisible(hasFocus());
- }
- }
-
- m_coordX = new QGraphicsSimpleTextItem();
- scene()->addItem(m_coordX);
- m_coordY = new QGraphicsSimpleTextItem();
- scene()->addItem(m_coordY);
- m_coordX->setText("Cycle: ");
- m_coordY->setText("Value: ");
- m_coordX->setPos(m_chart->size().width() / 2 - 50, m_chart->size().height());
- m_coordY->setPos(m_chart->size().width() / 2 + 50, m_chart->size().height());
-
resizeObjects(m_chart->size());
}
void CachePlotView::resizeObjects(const QSizeF& size) {
+ int ySpaceForMarkers = 0;
+ if (m_markers.size() > 0) {
+ ySpaceForMarkers = m_markers.size() * m_markers.at(0)->coordX->boundingRect().height();
+ }
+
scene()->setSceneRect(QRectF(QPoint(0, 0), size));
- m_chart->resize(size);
- m_coordX->setPos(m_chart->size().width() / 2 - 50, m_chart->size().height() - 20);
- m_coordY->setPos(m_chart->size().width() / 2 + 50, m_chart->size().height() - 20);
+ m_chart->resize(size - QSizeF(0, ySpaceForMarkers));
for (auto* item : scene()->items()) {
if (auto* callout = dynamic_cast<Callout*>(item)) {
callout->updateGeometry();
}
- if (m_crosshairEnabled && m_marker) {
- m_marker->updateLines();
}
+
+ for (unsigned i = 0; i < m_markers.size(); i++) {
+ auto& marker = m_markers.at(i);
+ int yOffset = 0;
+ if (i > 0) {
+ yOffset = m_markers.at(i - 1)->coordX->boundingRect().height() * i;
+ }
+ const int y = yOffset + m_chart->size().height() - 20;
+ marker->label->setPos(m_chart->size().width() / 4 - marker->label->boundingRect().width(), y);
+ marker->coordX->setPos(m_chart->size().width() / 3, y);
+ marker->coordY->setPos(m_chart->size().width() / 2, y);
+ marker->marker->updateLines();
}
}
@@ -129,21 +170,14 @@ void CachePlotView::resizeEvent(QResizeEvent* event) {
QGraphicsView::resizeEvent(event);
}
-void CachePlotView::updateCoordinateValues(const QPointF& pos) {
- m_coordX->setText(QString("Cycle: %1").arg(pos.x()));
- m_coordY->setText(QString("Value: %1").arg(pos.y()));
-}
-
void CachePlotView::mouseMoveEvent(QMouseEvent* event) {
m_hoverPos = event->pos();
constrainInPlotRange(m_hoverPos, m_chart);
- if (m_crosshairEnabled && m_marker) {
- m_marker->move(m_hoverPos);
- } else {
- // Only update coordinate values if the marker is not currently snapping. If it is snapping, the marker itself
- // will emit signals with the snapped marker position.
- updateCoordinateValues(m_chart->mapToValue(m_hoverPos));
+ if (m_markers.size() > 0) {
+ for (const auto& marker : m_markers) {
+ marker->marker->move(m_hoverPos);
+ }
}
QGraphicsView::mouseMoveEvent(event);
}
@@ -161,10 +195,6 @@ void CachePlotView::deleteCallout(Callout* callout) {
delete callout;
}
-void CachePlotView::enableCrosshair(bool enabled) {
- m_crosshairEnabled = enabled;
-}
-
void CachePlotView::tooltip(QPointF point, bool state) {
m_tooltipLock.lock();
if (m_tooltip == nullptr)

MODIFY
src/cachesim/cacheplotview.h
src/cachesim/cacheplotview.h
@@ -12,6 +12,7 @@ QT_END_NAMESPACE
QT_CHARTS_BEGIN_NAMESPACE
class QChart;
+class QLineSeries;
QT_CHARTS_END_NAMESPACE
class Callout;
@@ -21,6 +22,20 @@ QT_CHARTS_USE_NAMESPACE
namespace Ripes {
class ChartLineMarker;
+class MarkerObjects : public QObject {
+ Q_OBJECT
+
+public:
+ QGraphicsSimpleTextItem* coordX;
+ QGraphicsSimpleTextItem* coordY;
+ QGraphicsSimpleTextItem* label;
+ ChartLineMarker* marker;
+ const QLineSeries* series;
+ MarkerObjects(QObject* parent, QChart* chart, const QLineSeries* series);
+ void updateCoordinateValues(const QPointF& pos);
+ void clear();
+};
+
class CachePlotView : public QGraphicsView {
Q_OBJECT
@@ -45,19 +60,18 @@ public slots:
void keepCallout();
void deleteCallout(Callout* callout);
void tooltip(QPointF point, bool state);
- void enableCrosshair(bool enabled);
+ void showSeriesMarker(const QLineSeries* series);
+ void hideSeriesMarker(const QLineSeries* series);
private:
- void updateCoordinateValues(const QPointF& pos);
void resizeObjects(const QSizeF& size);
QPointF m_hoverPos;
- QGraphicsSimpleTextItem* m_coordX;
- QGraphicsSimpleTextItem* m_coordY;
+ std::vector<std::unique_ptr<MarkerObjects>> m_markers;
+
QChart* m_chart = nullptr;
Callout* m_tooltip = nullptr;
- ChartLineMarker* m_marker = nullptr;
QMutex m_tooltipLock;
bool m_crosshairEnabled = true;

MODIFY
src/cachesim/cacheplotwidget.cpp
src/cachesim/cacheplotwidget.cpp
#include <algorithm>
+#include "defines.h"
#include "enumcombobox.h"
#include "processorhandler.h"
@@ -32,10 +33,6 @@ CachePlotWidget::CachePlotWidget(QWidget* parent) : QWidget(parent), m_ui(new Ui
m_ui->setupUi(this);
setWindowTitle("Cache Access Statistics");
- m_toolbar = new QToolBar(this);
- // m_ui->toolbarLayout->addWidget(m_toolbar);
- setupToolbar();
-
setupEnumCombobox(m_ui->num, s_cacheVariableStrings);
setupEnumCombobox(m_ui->den, s_cacheVariableStrings);
@@ -58,6 +55,7 @@ CachePlotWidget::CachePlotWidget(QWidget* parent) : QWidget(parent), m_ui(new Ui
m_ui->sizeBreakdownButton->setIcon(sizeBreakdownIcon);
connect(m_ui->sizeBreakdownButton, &QPushButton::clicked, this, &CachePlotWidget::showSizeBreakdown);
connect(m_ui->windowed, &QCheckBox::toggled, m_ui->windowCycles, &QWidget::setEnabled);
+ connect(m_ui->windowed, &QCheckBox::toggled, m_ui->mavgCursor, &QWidget::setEnabled);
}
void CachePlotWidget::showSizeBreakdown() {
@@ -87,14 +85,20 @@ void CachePlotWidget::setCache(std::shared_ptr<CacheSim> cache) {
m_plot = new QChart();
m_series = new QLineSeries(m_plot);
+ auto defaultPen = m_series->pen(); // Inherit default pen state
+ defaultPen.setColor(QColor(FoundersRock));
m_series->setName("Total");
+ m_series->setPen(defaultPen);
m_plot->addSeries(m_series);
- m_windowSeries = new QLineSeries(m_plot);
- m_windowSeries->setName("Moving avg.");
- m_plot->addSeries(m_windowSeries);
+ m_mavgSeries = new QLineSeries(m_plot);
+ m_mavgSeries->setName("Moving avg.");
+ defaultPen.setColor(QColor(Medalist));
+ m_mavgSeries->setPen(defaultPen);
+ m_plot->addSeries(m_mavgSeries);
m_plot->createDefaultAxes();
m_plot->legend()->hide();
m_ui->plotView->setPlot(m_plot);
+ setupPlotActions();
variablesChanged();
rangeChanged();
@@ -106,27 +110,41 @@ CachePlotWidget::~CachePlotWidget() {
delete m_plot;
}
-void CachePlotWidget::setupToolbar() {
- const QIcon crosshairIcon = QIcon(":/icons/crosshair.svg");
- m_crosshairAction = new QAction("Enable plot crosshair", this);
- m_crosshairAction->setIcon(crosshairIcon);
- m_crosshairAction->setCheckable(true);
- m_crosshairAction->setChecked(true);
- m_toolbar->addAction(m_crosshairAction);
- connect(m_crosshairAction, &QAction::triggered, m_ui->plotView, &CachePlotView::enableCrosshair);
+void CachePlotWidget::setupPlotActions() {
+ auto showMarkerFunctor = [=](const QLineSeries* series) {
+ return [=](bool visible) {
+ if (visible) {
+ m_ui->plotView->showSeriesMarker(series);
+ } else {
+ m_ui->plotView->hideSeriesMarker(series);
+ }
+ };
+ };
+
+ m_totalMarkerAction = new QAction("Enable total crosshair", this);
+ m_totalMarkerAction->setIcon(QIcon(":/icons/crosshair_blue.svg"));
+ m_totalMarkerAction->setCheckable(true);
+ m_ui->ratioCursor->setDefaultAction(m_totalMarkerAction);
+ connect(m_totalMarkerAction, &QAction::toggled, showMarkerFunctor(m_series));
+ m_totalMarkerAction->setChecked(true);
- m_toolbar->addSeparator();
+ m_mavgMarkerAction = new QAction("Enable moving average crosshair", this);
+ m_mavgMarkerAction->setIcon(QIcon(":/icons/crosshair_gold.svg"));
+ m_mavgMarkerAction->setCheckable(true);
+ m_ui->mavgCursor->setDefaultAction(m_mavgMarkerAction);
+ connect(m_mavgMarkerAction, &QAction::toggled, showMarkerFunctor(m_mavgSeries));
+ m_mavgMarkerAction->setChecked(true);
const QIcon copyIcon = QIcon(":/icons/documents.svg");
m_copyDataAction = new QAction("Copy data to clipboard", this);
m_copyDataAction->setIcon(copyIcon);
- m_toolbar->addAction(m_copyDataAction);
+ m_ui->copyData->setDefaultAction(m_copyDataAction);
connect(m_copyDataAction, &QAction::triggered, this, &CachePlotWidget::copyPlotDataToClipboard);
const QIcon saveIcon = QIcon(":/icons/saveas.svg");
m_savePlotAction = new QAction("Save plot to file", this);
m_savePlotAction->setIcon(saveIcon);
- m_toolbar->addAction(m_savePlotAction);
+ m_ui->savePlot->setDefaultAction(m_savePlotAction);
connect(m_savePlotAction, &QAction::triggered, this, &CachePlotWidget::savePlot);
}
@@ -308,10 +326,10 @@ void CachePlotWidget::updateRatioPlot() {
m_maxY = wRatio > m_maxY ? wRatio : m_maxY;
m_minY = wRatio < m_minY ? wRatio : m_minY;
- m_windowData.push(wRatio);
+ m_mavgData.push(wRatio);
// Plot moving average
- const double wAvg = std::accumulate(m_windowData.begin(), m_windowData.end(), 0.0) / m_windowData.size();
+ const double wAvg = std::accumulate(m_mavgData.begin(), m_mavgData.end(), 0.0) / m_mavgData.size();
newWindowPoints << QPointF(p1.x(), wAvg);
m_lastData.first = p1;
m_lastData.second = p2;
@@ -325,8 +343,8 @@ void CachePlotWidget::updateRatioPlot() {
plotMover(m_series, false);
m_series->append(newPoints);
if (m_ui->windowed->isChecked()) {
- plotMover(m_windowSeries, false);
- m_windowSeries->append(newWindowPoints);
+ plotMover(m_mavgSeries, false);
+ m_mavgSeries->append(newWindowPoints);
}
// Determine whether to resample; *2 the allowed points to account for the addition of step points.
@@ -337,7 +355,7 @@ void CachePlotWidget::updateRatioPlot() {
plotMover(m_series, true);
if (m_ui->windowed->isChecked()) {
- plotMover(m_windowSeries, true);
+ plotMover(m_mavgSeries, true);
}
m_plot->createDefaultAxes();
@@ -373,16 +391,18 @@ void CachePlotWidget::resetRatioPlot() {
m_maxY = -DBL_MAX;
m_minY = DBL_MAX;
m_series->clear();
- m_windowSeries->clear();
+ m_mavgSeries->clear();
m_lastCyclePlotted = 0;
m_xStep = 1;
+ m_mavgMarkerAction->setChecked(m_ui->windowed->isChecked() && m_mavgMarkerAction->isChecked());
+
if (m_ui->windowed->isChecked()) {
- m_windowData = FixedQueue<double>(m_ui->windowCycles->value());
- m_windowSeries->setVisible(true);
+ m_mavgData = FixedQueue<double>(m_ui->windowCycles->value());
+ m_mavgSeries->setVisible(true);
m_plot->legend()->setVisible(true);
} else {
- m_windowSeries->setVisible(false);
+ m_mavgSeries->setVisible(false);
m_plot->legend()->setVisible(false);
}

MODIFY
src/cachesim/cacheplotwidget.h
src/cachesim/cacheplotwidget.h
@@ -63,7 +63,7 @@ private:
* specified cycle
*/
std::map<Variable, QList<QPoint>> gatherData(unsigned fromCycle = 0) const;
- void setupToolbar();
+ void setupPlotActions();
void showSizeBreakdown();
void copyPlotDataToClipboard() const;
void savePlot();
@@ -84,9 +84,9 @@ private:
double m_xStep = 1.0;
static constexpr int s_resamplingRatio = 2;
- QLineSeries* m_windowSeries = nullptr;
+ QLineSeries* m_mavgSeries = nullptr;
// N last computations of the change in ratio value
- FixedQueue<double> m_windowData;
+ FixedQueue<double> m_mavgData;
// Last cycle numerator and denominator values
std::pair<QPoint, QPoint> m_lastData;
@@ -96,10 +96,10 @@ private:
CachePlotWidget::Variable m_numerator;
CachePlotWidget::Variable m_denominator;
- QToolBar* m_toolbar = nullptr;
QAction* m_copyDataAction = nullptr;
QAction* m_savePlotAction = nullptr;
- QAction* m_crosshairAction = nullptr;
+ QAction* m_totalMarkerAction = nullptr;
+ QAction* m_mavgMarkerAction = nullptr;
};
const static std::map<CachePlotWidget::Variable, QString> s_cacheVariableStrings{

MODIFY
src/cachesim/cacheplotwidget.ui
src/cachesim/cacheplotwidget.ui
<rect>
<x>0</x>
<y>0</y>
- <width>733</width>
+ <width>741</width>
<height>330</height>
</rect>
</property>
<number>0</number>
</property>
<item row="0" column="0">
- <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1">
+ <layout class="QVBoxLayout" name="verticalLayout_2" stretch="0,1,0">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<item>
<widget class="CachePlotView" name="plotView"/>
</item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QToolButton" name="ratioCursor">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="mavgCursor">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="copyData">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="savePlot">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
</layout>
</item>
</layout>

MODIFY
src/cachesim/chartlinemarker.cpp
src/cachesim/chartlinemarker.cpp
namespace Ripes {
-ChartLineMarker::ChartLineMarker(QChart* parent, QLineSeries* series)
+ChartLineMarker::ChartLineMarker(QChart* parent, const QLineSeries* series)
: QGraphicsObject(parent), m_chart(parent), m_series(series) {
m_hzLine = new QGraphicsLineItem(this);
m_vtLine = new QGraphicsLineItem(this);
+ m_hzLine->setPen(QPen(series->color()));
+ m_vtLine->setPen(QPen(series->color()));
setFlag(ItemHasNoContents, true);
}

MODIFY
src/cachesim/chartlinemarker.h
src/cachesim/chartlinemarker.h
@@ -12,7 +12,7 @@ namespace Ripes {
class ChartLineMarker : public QGraphicsObject {
Q_OBJECT
public:
- ChartLineMarker(QChart* parent, QLineSeries* series);
+ ChartLineMarker(QChart* parent, const QLineSeries* series);
QRectF boundingRect() const override;
void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) override {}
@@ -37,7 +37,7 @@ private:
QPointF m_center;
QChart* m_chart = nullptr;
- QLineSeries* m_series = nullptr;
+ QLineSeries const* m_series = nullptr;
QGraphicsLineItem* m_hzLine = nullptr;
QGraphicsLineItem* m_vtLine = nullptr;
};

Allow multiple markers on a CachePlotView