#include <QMouseEvent>
#include <qwt_plot.h>
#include <qwt_plot_canvas.h>
#include <qwt_plot_curve.h>
#include <qwt_plot_legenditem.h>
#include "CanvasPicker.h"
CanvasPicker
::CanvasPicker(QwtPlot* plot
) : m_lastSelectedCurve(nullptr)
{
QwtPlotCanvas* canvas
= qobject_cast<QwtPlotCanvas
*>
(plot
->canvas
());
canvas->installEventFilter(this);
// We want the focus, but no focus rect. The
// selected point will be highlighted instead.
canvas->setFocusPolicy(Qt::StrongFocus);
#ifndef QT_NO_CURSOR
canvas->setCursor(Qt::PointingHandCursor);
#endif
canvas->setFocus();
}
{
return qobject_cast<QwtPlot*>(parent());
}
const QwtPlot* CanvasPicker
::plot() const {
return qobject_cast<const
QwtPlot*>
(parent
());
}
{
if (plot() == nullptr || object != plot()->canvas())
{
return false;
}
switch (event->type())
{
case QEvent::MouseButtonPress: {
const QMouseEvent* const mouseEvent
= static_cast<QMouseEvent
*>
(event
);
if (mouseEvent->button() & Qt::LeftButton)
{
m_mousePressPosition = mouseEvent->pos();
}
break;
}
case QEvent::MouseButtonRelease: {
const QMouseEvent* const mouseEvent
= static_cast<QMouseEvent
*>
(event
);
const QPoint mouseReleasePosition
= mouseEvent
->pos
();
if (mouseEvent->button() & Qt::LeftButton)
{
if (m_mousePressPosition == mouseReleasePosition)
{
select(mouseEvent->pos());
//return true; // blocks painting ??!!??
}
}
break;
}
default:
break;
}
return QObject::eventFilter(object, event
);
}
void CanvasPicker::select(const QPoint& pos)
{
// 1. check if the legend has been clicked on
QwtPlotItemList curveList
= plot
()->itemList
(QwtPlotItem::Rtti_PlotCurve);
if (curveList.isEmpty())
{
return;
}
// we only have one legend item
QwtPlotItemList legendList
= plot
()->itemList
(QwtPlotItem::Rtti_PlotLegend);
QwtPlotLegendItem* legendItem = (legendList.size() > 0) ? \
static_cast<QwtPlotLegendItem*>(legendList[0]) : nullptr;
QVector<QList<QRect>> curveLegendGeometries;
if (legendItem &&
legendItem->geometry(plot()->canvas()->rect()).contains(pos))
{
for (auto curveItem : curveList)
{
//QwtPlotCurve* curve = static_cast<QwtPlotCurve*>(curveItem);
curveLegendGeometries.push_back(legendItem->legendGeometries(curveItem));
}
}
if (!curveLegendGeometries.isEmpty())
{
auto it = std::find_if(curveLegendGeometries.begin(), curveLegendGeometries.end(),
[&pos](const QList<QRect>& listRect) -> bool
{
for (const auto& rect : listRect)
{
if (rect.contains(pos))
{
return true;
}
}
return false;
});
if (it != curveLegendGeometries.end())
{
// or a simple substraction...
auto curveIndex = std::distance(curveLegendGeometries.begin(), it);
if (curveIndex < curveList.size())
{
QwtPlotCurve* legendCurve
= static_cast<QwtPlotCurve
*>
(curveList
[int(curveIndex
)]);
if (m_lastSelectedCurve == legendCurve)
{
deselectLastSelectedCurve();
}
else
{
highlightSelectedCurve(legendCurve);
}
//highlightSelectedLegend(legendItem, legendCurve);
// Immediate paint doesn't work !
//QwtPlotCanvas* plotCanvas = qobject_cast<QwtPlotCanvas*>(plot()->canvas());
//plotCanvas->setPaintAttribute(QwtPlotCanvas::ImmediatePaint, true);
plot()->replot();
//plotCanvas->setPaintAttribute(QwtPlotCanvas::ImmediatePaint, false);
}
return;
}
else
{
if (deselectLastSelectedCurve())
{
plot()->replot();
}
}
}
// 2. check if a curve has been selected
double minDistance = 10e10;
{
double tmp;
for (const auto curve : curveList)
{
c->closestPoint(pos, &tmp);
if (tmp < minDistance)
{
closestCurve = c;
minDistance = tmp;
}
}
}
if (closestCurve && minDistance < 10) // 10 pixels tolerance
{
if (m_lastSelectedCurve == closestCurve)
{
deselectLastSelectedCurve();
}
else
{
highlightSelectedCurve(closestCurve);
}
//QwtPlotCanvas* plotCanvas = qobject_cast<QwtPlotCanvas*>(plot()->canvas());
//plotCanvas->setPaintAttribute(QwtPlotCanvas::ImmediatePaint, true);
plot()->replot();
//plotCanvas->setPaintAttribute(QwtPlotCanvas::ImmediatePaint, false);
}
else
{
if (deselectLastSelectedCurve())
{
plot()->replot();
}
}
}
bool CanvasPicker
::isCurveStillAlive(QwtPlotCurve* curve
) const {
if (!curve)
{
return false;
}
const QwtPlotItemList& curveList = plot()->itemList();
return (std::find(curveList.begin(), curveList.end(), static_cast<QwtPlotItem*>(curve))
!= curveList.end());
}
void CanvasPicker
::highlightSelectedCurve(QwtPlotCurve* curve
) {
// Deselect last selected curve !
deselectLastSelectedCurve();
QPen originalPen
= curve
->pen
();
originalPen.setWidth(originalPen.width() + 1);
curve->setPen(originalPen);
m_lastSelectedCurve = curve;
}
bool CanvasPicker::deselectLastSelectedCurve()
{
if (m_lastSelectedCurve != nullptr && isCurveStillAlive(m_lastSelectedCurve))
{
QPen originalPen
= m_lastSelectedCurve
->pen
();
originalPen.setWidth(originalPen.width() - 1);
m_lastSelectedCurve->setPen(originalPen);
m_lastSelectedCurve = nullptr;
return true;
}
return false;
}
#if 0
// The API is not very friendly, let's just only highlight the curve, it's sufficient for now :(
void CanvasPicker
::highlightSelectedLegend(QwtPlotLegendItem
* legend,
QwtPlotCurve* curve
) {
// legendData: The default implementation returns one entry with the title()
// of the item and the legendIcon().
QList<QwtLegendData> originalLegData = curve->legendData();
if (originalLegData.size() > 0)
{
originalLegData[0].value(QwtLegendData::TitleRole);
//............
}
legend->updateLegend(curve, originalLegData);
}
#endif
Bookmarks