/*
Copyright © 2015 Hasan Yavuz Özderya
This file is part of serialplot.
serialplot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
serialplot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with serialplot. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include "scalepicker.h"
// minimum size for pick (in pixels)
#define MIN_PICK_SIZE (2)
class PlotOverlay : public QwtWidgetOverlay
{
public:
PlotOverlay(QWidget* widget, ScalePicker* picker);
protected:
virtual void drawOverlay(QPainter*) const;
private:
ScalePicker* _picker;
};
PlotOverlay::PlotOverlay(QWidget* widget, ScalePicker* picker) :
QwtWidgetOverlay(widget)
{
_picker = picker;
}
void PlotOverlay::drawOverlay(QPainter* painter) const
{
_picker->drawPlotOverlay(painter);
}
class ScaleOverlay : public QwtWidgetOverlay
{
public:
ScaleOverlay(QWidget* widget, ScalePicker* picker);
protected:
virtual void drawOverlay(QPainter*) const;
private:
ScalePicker* _picker;
};
ScaleOverlay::ScaleOverlay(QWidget* widget, ScalePicker* picker) :
QwtWidgetOverlay(widget)
{
_picker = picker;
}
void ScaleOverlay::drawOverlay(QPainter* painter) const
{
_picker->drawScaleOverlay(painter);
}
ScalePicker::ScalePicker(QwtScaleWidget* scaleWidget, QWidget* canvas) :
QObject(scaleWidget)
{
_scaleWidget = scaleWidget;
_canvas = canvas;
scaleWidget->installEventFilter(this);
scaleWidget->setMouseTracking(true);
pickerOverlay = new PlotOverlay(canvas, this);
scaleOverlay = new ScaleOverlay(scaleWidget, this);
started = false;
pressed = false;
}
bool ScalePicker::eventFilter(QObject* object, QEvent* event)
{
if (event->type() == QEvent::MouseButtonPress ||
event->type() == QEvent::MouseButtonRelease ||
event->type() == QEvent::MouseMove)
{
QMouseEvent* mouseEvent = (QMouseEvent*) event;
double pos = this->position(mouseEvent);
double posPx = this->positionPx(mouseEvent);
currentPosPx = posPx;
if (event->type() == QEvent::MouseButtonPress &&
mouseEvent->button() == Qt::LeftButton)
{
pressed = true; // not yet started
firstPos = pos;
firstPosPx = posPx;
}
else if (event->type() == QEvent::MouseMove)
{
// make sure pick size is big enough, so that just
// clicking won't trigger pick
if (!started && pressed && (fabs(posPx-firstPosPx) > MIN_PICK_SIZE))
{
started = true;
emit pickStarted(pos);
}
else if (started)
{
pickerOverlay->updateOverlay();
emit picking(firstPos, pos);
}
scaleOverlay->updateOverlay();
}
else // event->type() == QEvent::MouseButtonRelease
{
if (started)
{
// finalize
started = false;
pressed = false;
emit picked(firstPos, pos);
}
}
return true;
}
else if (event->type() == QEvent::Leave)
{
scaleOverlay->updateOverlay();
return true;
}
else
{
return QObject::eventFilter(object, event);
}
}
void ScalePicker::drawPlotOverlay(QPainter* painter)
{
if (started)
{
painter->save();
painter->setPen(_pen);
QRect rect;
if (_scaleWidget->alignment() == QwtScaleDraw::BottomScale ||
_scaleWidget->alignment() == QwtScaleDraw::TopScale)
{
int height = painter->device()->height();
rect = QRect(posCanvasPx(firstPosPx), 0, currentPosPx-firstPosPx, height);
}
else // vertical
{
int width = painter->device()->width();
rect = QRect(0, posCanvasPx(firstPosPx), width, currentPosPx-firstPosPx);
}
painter->drawRect(rect);
painter->restore();
}
}
void ScalePicker::drawScaleOverlay(QPainter* painter)
{
painter->save();
painter->setPen(_pen);
if (1)
{
if (_scaleWidget->alignment() == QwtScaleDraw::BottomScale ||
_scaleWidget->alignment() == QwtScaleDraw::TopScale)
{
int height = painter->device()->height();
if (started) painter->drawLine(firstPosPx, 0, firstPosPx, height);
if (started || _scaleWidget->underMouse())
{
painter->drawLine(currentPosPx, 0, currentPosPx, height);
}
}
else // vertical
{
int width = painter->device()->width();
if (started) painter->drawLine(0, firstPosPx, width, firstPosPx);
if (started || _scaleWidget->underMouse())
{
painter->drawLine(0, currentPosPx, width, currentPosPx);
}
}
}
painter->restore();
}
void ScalePicker::setPen(QPen pen)
{
_pen = pen;
}
double ScalePicker::position(QMouseEvent* mouseEvent)
{
double pos;
pos = positionPx(mouseEvent);
// convert the position of the click to the plot coordinates
pos = _scaleWidget->scaleDraw()->scaleMap().invTransform(pos);
return pos;
}
double ScalePicker::positionPx(QMouseEvent* mouseEvent)
{
double pos;
if (_scaleWidget->alignment() == QwtScaleDraw::BottomScale ||
_scaleWidget->alignment() == QwtScaleDraw::TopScale)
{
pos = mouseEvent->pos().x();
}
else // left or right scale
{
pos = mouseEvent->pos().y();
}
return pos;
}
/*
* Scale widget and canvas widget is not always aligned. Especially
* when zooming scaleWidget moves around. This causes irregularities
* when drawing the tracker lines. This function maps scale widgets
* pixel coordinate to canvas' coordinate.
*/
double ScalePicker::posCanvasPx(double pos)
{
// assumption: scale.width < canvas.width && scale.x > canvas.x
if (_scaleWidget->alignment() == QwtScaleDraw::BottomScale ||
_scaleWidget->alignment() == QwtScaleDraw::TopScale)
{
return pos + (_scaleWidget->x() - _canvas->x());
}
else // left or right scale
{
return pos + (_scaleWidget->y() - _canvas->y());
}
return pos;
}