# HG changeset patch # User Hasan Yavuz ÖZDERYA # Date 2015-09-13 09:23:25 # Node ID 94f7460166ef48e7a5cdb3fb105925ea34f3a6c8 # Parent 01cfae83a7f8f6e63026139d7ea36fd600149a09 # Parent 23c08728ad2d969947c7efbd3a16b16a2883f095 Merge with scalezoomer diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,6 +62,8 @@ add_executable(${PROGRAM_NAME} WIN32 zoomer.cpp hidabletabwidget.cpp framebuffer.cpp + scalepicker.cpp + scalezoomer.cpp ${UI_FILES} misc/windows_icon.rc ) diff --git a/plot.cpp b/plot.cpp --- a/plot.cpp +++ b/plot.cpp @@ -17,11 +17,12 @@ along with serialplot. If not, see . */ +#include #include "plot.h" - Plot::Plot(QWidget* parent) : QwtPlot(parent), - zoomer(this->canvas(), false) + zoomer(this->canvas(), false), + sZoomer(this, &zoomer) { isAutoScaled = false; @@ -30,6 +31,9 @@ Plot::Plot(QWidget* parent) : zoomer.setZoomBase(); grid.attach(this); + rectItem.setRect(QRectF(0,0,100,1)); + // rectItem.attach(this); + darkBackground(false); } @@ -94,6 +98,7 @@ void Plot::darkBackground(bool enabled) grid.setPen(Qt::darkGray); zoomer.setRubberBandPen(QPen(Qt::white)); zoomer.setTrackerPen(QPen(Qt::white)); + sZoomer.setPickerPen(QPen(Qt::white)); } else { @@ -101,6 +106,7 @@ void Plot::darkBackground(bool enabled) grid.setPen(Qt::lightGray); zoomer.setRubberBandPen(QPen(Qt::black)); zoomer.setTrackerPen(QPen(Qt::black)); + sZoomer.setPickerPen(QPen(Qt::black)); } replot(); } diff --git a/plot.h b/plot.h --- a/plot.h +++ b/plot.h @@ -22,7 +22,9 @@ #include #include +#include #include "zoomer.h" +#include "scalezoomer.h" class Plot : public QwtPlot { @@ -36,7 +38,9 @@ private: bool isAutoScaled; double yMin, yMax; Zoomer zoomer; + ScaleZoomer sZoomer; QwtPlotGrid grid; + QwtPlotShapeItem rectItem; void resetAxes(); diff --git a/scalepicker.cpp b/scalepicker.cpp new file mode 100644 --- /dev/null +++ b/scalepicker.cpp @@ -0,0 +1,250 @@ +/* + 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; +} diff --git a/scalepicker.h b/scalepicker.h new file mode 100644 --- /dev/null +++ b/scalepicker.h @@ -0,0 +1,65 @@ +/* + 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 . +*/ + +#ifndef SCALEPICKER_H +#define SCALEPICKER_H + +#include +#include +#include +#include +#include +#include + +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 + + double position(QMouseEvent*); // returns the axis mouse position relative to plot coordinates + double positionPx(QMouseEvent*); // returns the axis mouse position in pixels + double posCanvasPx(double pos); // returns the given position in canvas coordinates +}; + +#endif // SCALEPICKER_H diff --git a/scalezoomer.cpp b/scalezoomer.cpp new file mode 100644 --- /dev/null +++ b/scalezoomer.cpp @@ -0,0 +1,77 @@ +/* + 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 "scalezoomer.h" + +ScaleZoomer::ScaleZoomer(QwtPlot* plot, QwtPlotZoomer* zoomer) : + QObject(plot), + bottomPicker(plot->axisWidget(QwtPlot::xBottom), plot->canvas()), + leftPicker(plot->axisWidget(QwtPlot::yLeft), plot->canvas()) +{ + _plot = plot; + _zoomer = zoomer; + connect(&bottomPicker, &ScalePicker::picked, this, &ScaleZoomer::bottomPicked); + connect(&leftPicker, &ScalePicker::picked, this, &ScaleZoomer::leftPicked); +} + +void ScaleZoomer::setPickerPen(QPen pen) +{ + bottomPicker.setPen(pen); + leftPicker.setPen(pen); +} + +void ScaleZoomer::bottomPicked(double firstPos, double lastPos) +{ + QRectF zRect; + if (lastPos > firstPos) + { + zRect.setLeft(firstPos); + zRect.setRight(lastPos); + } + else + { + zRect.setLeft(lastPos); + zRect.setRight(firstPos); + } + + zRect.setBottom(_plot->axisScaleDiv(QwtPlot::yLeft).lowerBound()); + zRect.setTop(_plot->axisScaleDiv(QwtPlot::yLeft).upperBound()); + _zoomer->zoom(zRect); +} + +void ScaleZoomer::leftPicked(double firstPos, double lastPos) +{ + QRectF zRect; + if (lastPos > firstPos) + { + zRect.setBottom(firstPos); + zRect.setTop(lastPos); + } + else + { + zRect.setBottom(lastPos); + zRect.setTop(firstPos); + } + + zRect.setLeft(_plot->axisScaleDiv(QwtPlot::xBottom).lowerBound()); + zRect.setRight(_plot->axisScaleDiv(QwtPlot::xBottom).upperBound()); + _zoomer->zoom(zRect); +} diff --git a/scalezoomer.h b/scalezoomer.h new file mode 100644 --- /dev/null +++ b/scalezoomer.h @@ -0,0 +1,49 @@ +/* + 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 . +*/ + +#ifndef SCALEZOOMER_H +#define SCALEZOOMER_H + +#include +#include +#include +#include + +#include "scalepicker.h" + +class ScaleZoomer : public QObject +{ + Q_OBJECT + +public: + ScaleZoomer(QwtPlot*, QwtPlotZoomer*); + void setPickerPen(QPen pen); + +private: + QwtPlot* _plot; + QwtPlotZoomer* _zoomer; + ScalePicker bottomPicker; + ScalePicker leftPicker; + +private slots: + void bottomPicked(double firstPos, double lastPos); + void leftPicked(double firstPos, double lastPos); +}; + +#endif /* SCALEZOOMER_H */ diff --git a/serialplot.pro b/serialplot.pro --- a/serialplot.pro +++ b/serialplot.pro @@ -39,7 +39,9 @@ SOURCES += main.cpp\ plot.cpp \ zoomer.cpp \ hidabletabwidget.cpp \ - framebuffer.cpp + framebuffer.cpp \ + scalepicker.cpp \ + scalezoomer.cpp HEADERS += mainwindow.h \ utils.h \ @@ -48,7 +50,9 @@ HEADERS += mainwindow.h \ plot.h \ zoomer.h \ hidabletabwidget.h \ - framebuffer.h + framebuffer.h \ + scalepicker.h \ + scalezoomer.h FORMS += mainwindow.ui \ about_dialog.ui \