/*
Copyright © 2018 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 "zoomer.h"
#include
#include
#include
#include
static const int VALUE_POINT_DIAM = 4;
static const int VALUE_TEXT_MARGIN = VALUE_POINT_DIAM + 2;
Zoomer::Zoomer(QWidget* widget, const Stream* stream, bool doReplot) :
ScrollZoomer(widget)
{
is_panning = false;
_stream = stream;
setTrackerMode(AlwaysOn);
// set corner widget between the scrollbars with default background color
auto cornerWidget = new QWidget();
auto bgColor = cornerWidget->palette().color(QPalette::Window).name();
auto styleSheet = QString("background-color:%1;").arg(bgColor);
cornerWidget->setStyleSheet(styleSheet);
ScrollZoomer::setCornerWidget(cornerWidget);
}
void Zoomer::zoom(int up)
{
ScrollZoomer::zoom(up);
if(zoomRectIndex() == 0)
{
emit unzoomed();
}
}
void Zoomer::zoom( const QRectF & rect)
{
// set the zoom base when user zooms in to first level
if (zoomRectIndex() == 0)
{
this->setZoomBase(false);
}
ScrollZoomer::zoom(rect);
}
QwtText Zoomer::trackerTextF(const QPointF& pos) const
{
QwtText b = ScrollZoomer::trackerTextF(pos);
const QPolygon pa = selection();
if (!isActive() || pa.count() < 2)
{
return b;
}
const QRectF rect = invTransform(QRect(pa.first(), pa.last()).normalized());
QString sizeText = QString(" [%1, %2]").\
arg(rect.width(), 0, 'g', 4).\
arg(rect.height(), 0, 'g', 4);
b.setText(b.text() + sizeText);
return b;
}
void Zoomer::drawRubberBand(QPainter* painter) const
{
const double FILL_ALPHA = 0.2;
QColor color = painter->pen().color();
color.setAlphaF(FILL_ALPHA);
painter->setBrush(color);
ScrollZoomer::drawRubberBand(painter);
}
QRegion Zoomer::rubberBandMask() const
{
const QPolygon pa = selection();
if (pa.count() < 2)
{
return QRegion();
}
const QRect r = QRect(pa.first(), pa.last()).normalized().adjusted(0, 0, 1, 1);
return QRegion(r);
}
void Zoomer::drawTracker(QPainter* painter) const
{
if (isActive())
{
QwtPlotZoomer::drawTracker(painter);
}
else if (_stream != nullptr && _stream->numChannels())
{
drawValues(painter);
}
}
void Zoomer::drawValues(QPainter* painter) const
{
painter->save();
double x = invTransform(trackerPosition()).x();
auto values = findValues(x);
// draw vertical line
auto linePen = QPen(Qt::DotLine);
linePen.setColor(Qt::white);
painter->setPen(linePen);
const QRect pRect = pickArea().boundingRect().toRect();
int px = trackerPosition().x();
painter->drawLine(px, pRect.top(), px, pRect.bottom());
// draw sample values
for (int ci = 0; ci < values.size(); ci++)
{
double val = values[ci];
if (!std::isnan(val))
{
auto p = transform(QPointF(x, val));
painter->setBrush(_stream->channel(ci)->color());
painter->setPen(Qt::NoPen);
painter->drawEllipse(p, VALUE_POINT_DIAM, VALUE_POINT_DIAM);
painter->setPen(Qt::white);
// We give a very small (1x1) rectangle but disable clipping
painter->drawText(QRectF(p.x() + VALUE_TEXT_MARGIN, p.y(), 1, 1),
Qt::AlignVCenter | Qt::TextDontClip,
QString("%1").arg(val));
}
}
painter->restore();
}
QVector Zoomer::findValues(double x) const
{
// TODO: process only channel(s) of this plot
unsigned nc = _stream->numChannels();
QVector r(nc);
for (unsigned ci = 0; ci < nc; ci++)
{
auto chan = _stream->channel(ci);
double val = chan->findValue(x);
r[ci] = val;
}
return r;
}
QRect Zoomer::trackerRect(const QFont& font) const
{
if (isActive())
{
return QwtPlotZoomer::trackerRect(font);
}
else
{
return valueTrackerRect(font);
}
}
QRect Zoomer::valueTrackerRect(const QFont& font) const
{
// TODO: consider using actual tracker values for width calculation
const int textWidth = qCeil(QwtText("-8.8888888").textSize(font).width());
const int width = textWidth + VALUE_POINT_DIAM + VALUE_TEXT_MARGIN;
const int x = trackerPosition().x() - VALUE_POINT_DIAM;
const auto pickRect = pickArea().boundingRect();
return QRect(x, pickRect.y(), width, pickRect.height());
}
void Zoomer::widgetMousePressEvent(QMouseEvent* mouseEvent)
{
if (mouseEvent->modifiers() & Qt::ControlModifier)
{
is_panning = true;
parentWidget()->setCursor(Qt::ClosedHandCursor);
pan_point = invTransform(mouseEvent->pos());
}
else
{
ScrollZoomer::widgetMousePressEvent(mouseEvent);
}
}
void Zoomer::widgetMouseMoveEvent(QMouseEvent* mouseEvent)
{
if (is_panning)
{
auto cur_point = invTransform(mouseEvent->pos());
auto delta = cur_point - pan_point;
moveBy(-delta.x(), -delta.y());
pan_point = invTransform(mouseEvent->pos());
}
else
{
ScrollZoomer::widgetMouseMoveEvent(mouseEvent);
}
}
void Zoomer::widgetMouseReleaseEvent(QMouseEvent* mouseEvent)
{
if (is_panning)
{
is_panning = false;
parentWidget()->setCursor(Qt::CrossCursor);
}
else
{
ScrollZoomer::widgetMouseReleaseEvent(mouseEvent);
}
}