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 \