Changeset - 02b5bd46073f
[Not reviewed]
default
0 2 0
Hasan Yavuz ÖZDERYA - 9 years ago 2017-02-24 15:47:13
hy@ozderya.net
draw triangles on scale
2 files changed with 39 insertions and 19 deletions:
0 comments (0 inline, 0 general)
src/scalepicker.cpp
Show inline comments
 
/*
 
  Copyright © 2015 Hasan Yavuz Özderya
 
  Copyright © 2017 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 <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <QEvent>
 
#include <QMouseEvent>
 
#include <QPainter>
 
#include <qwt_scale_widget.h>
 
#include <qwt_scale_map.h>
 
#include <qwt_scale_div.h>
 
#include <math.h>
 

	
 
#include "scalepicker.h"
 

	
 
// minimum size for pick (in pixels)
 
#define MIN_PICK_SIZE (2)
 

	
 
#define SNAP_DISTANCE (5)
 

	
 
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;
 
@@ -146,117 +146,136 @@ bool ScalePicker::eventFilter(QObject* o
 
            pressed = false;
 
            if (started)
 
            {
 
                // finalize
 
                started = 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 (_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
 
    // rotate & adjust coordinate system for vertical drawing
 
    if (_scaleWidget->alignment() == QwtScaleDraw::LeftScale ||
 
        _scaleWidget->alignment() == QwtScaleDraw::RightScale) // vertical
 
    {
 
        int width = painter->device()->width();
 
        if (started) painter->drawLine(0, firstPosPx, width, firstPosPx);
 
        if (started || _scaleWidget->underMouse())
 
        painter->rotate(90);
 
        painter->translate(0, -width);
 
    }
 

	
 
    // draw the indicators
 
    if (started) drawTriangle(painter, firstPosPx);
 
    if (started || _scaleWidget->underMouse())
 
    {
 
        drawTriangle(painter, currentPosPx);
 
    }
 

	
 
    painter->restore();
 
}
 

	
 
void ScalePicker::drawTriangle(QPainter* painter, int position)
 
{
 
    const double tan60 = 1.732;
 
    const double trsize = 10;
 
    const int TRIANGLE_NUM_POINTS = 3;
 
    const int MARGIN = 2;
 
    const QPointF points[TRIANGLE_NUM_POINTS] =
 
        {
 
            painter->drawLine(0, currentPosPx, width, currentPosPx);
 
        }
 
    }
 
            {0, 0},
 
            {-trsize/tan60 , trsize},
 
            {trsize/tan60 , trsize}
 
        };
 

	
 
    painter->save();
 
    painter->setPen(Qt::NoPen);
 
    painter->setBrush(_scaleWidget->palette().windowText());
 
    painter->setRenderHint(QPainter::Antialiasing);
 

	
 
    painter->translate(position, MARGIN);
 
    painter->drawPolygon(points, TRIANGLE_NUM_POINTS);
 

	
 
    painter->restore();
 
}
 

	
 
void ScalePicker::setPen(QPen pen)
 
{
 
    _pen = pen;
 
}
 

	
 
// convert the position of the click to the plot coordinates
 
double ScalePicker::position(double posPx)
 
{
 
    return _scaleWidget->scaleDraw()->scaleMap().invTransform(posPx);
 
}
 

	
 
int 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());
 
    }
src/scalepicker.h
Show inline comments
 
/*
 
  Copyright © 2015 Hasan Yavuz Özderya
 
  Copyright © 2017 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 <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef SCALEPICKER_H
 
#define SCALEPICKER_H
 

	
 
#include <QObject>
 
#include <QMouseEvent>
 
#include <QPen>
 
#include <QWidget>
 
#include <QList>
 
#include <qwt_scale_widget.h>
 
#include <qwt_widget_overlay.h>
 

	
 
class ScalePicker : public QObject
 
{
 
    Q_OBJECT
 

	
 
public:
 
    ScalePicker(QwtScaleWidget* scaleWidget, QWidget* canvas);
 
    virtual bool eventFilter(QObject*, QEvent*);
 

	
 
    void drawPlotOverlay(QPainter*); // called from ScalePickerOverlay
 
    void drawScaleOverlay(QPainter*); // called from ScaleOverlay
 
    void setPen(QPen pen);
 

	
 
signals:
 
    void pickStarted(double pos);
 
    void picking(double firstPos, double lastPos);
 
    void picked(double firstPos, double lastPos);
 

	
 
private:
 
    QwtScaleWidget* _scaleWidget;
 
    QWidget* _canvas;
 
    QwtWidgetOverlay* pickerOverlay; // will be PlotOverlay
 
    QwtWidgetOverlay* scaleOverlay;  // will be ScaleOverlay
 
    QPen _pen;
 

	
 
    bool pressed;
 
    bool started;
 
    double firstPos; // converted to plot coordinates
 
    double firstPosPx; // pixel coordinates
 
    double currentPosPx; // current position in pixel coordinates
 
    QList<int> snapPoints;
 

	
 
    double position(double); // returns the axis mouse position relative to plot coordinates
 
    int positionPx(QMouseEvent*); // returns the axis mouse position in pixels
 
    double posCanvasPx(double pos); // returns the given position in canvas coordinates
 
    void drawTriangle(QPainter* painter, int position);
 

	
 
private slots:
 
    void updateSnapPoints();
 
};
 

	
 
#endif // SCALEPICKER_H
0 comments (0 inline, 0 general)