summaryrefslogtreecommitdiffhomepage
path: root/spline-widget
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2016-09-05 17:20:35 +0200
committerStanislaw Halik <sthalik@misaki.pl>2016-09-05 17:20:35 +0200
commit4f7bafa0124c3baa7b8da18806f50e6ff84fcf98 (patch)
tree3109791c384a9c883ba83fd06545cc6d70a13137 /spline-widget
parent06c591326a2c545484004b58a41c4b7b60c35525 (diff)
spline-widget: add tooltips, refactor
Tooltip shows current cursor/point position. Factor out common functions. Use QPoint/QPointF appropriately. Remove rounding that led to snapping to integral values. Allow for non-integral snapping amounts. Issue: #436
Diffstat (limited to 'spline-widget')
-rw-r--r--spline-widget/spline-widget.cpp302
-rw-r--r--spline-widget/spline-widget.hpp35
2 files changed, 228 insertions, 109 deletions
diff --git a/spline-widget/spline-widget.cpp b/spline-widget/spline-widget.cpp
index ff18a2f9..d4e01189 100644
--- a/spline-widget/spline-widget.cpp
+++ b/spline-widget/spline-widget.cpp
@@ -12,7 +12,13 @@
#include <QPen>
#include <QPixmap>
#include <QList>
-#include <QPointF>
+#include <QPoint>
+#include <QString>
+#include <QRect>
+#include <QApplication>
+#include <QStyle>
+#include <QMouseEvent>
+
#include <cmath>
#include <algorithm>
@@ -92,7 +98,7 @@ void spline_widget::drawBackground()
if (!isEnabled())
color__ = QColor(70, 90, 100, 96);
- QPen pen(color__, 1, Qt::SolidLine);
+ const QPen pen(color__, 1, Qt::SolidLine, Qt::FlatCap);
const int xstep = 10, ystep = 10;
const qreal maxx = _config->maxInput();
@@ -101,13 +107,13 @@ void spline_widget::drawBackground()
// horizontal grid
for (int i = 0; i <= maxy; i += xstep)
{
- const qreal y = pixel_bounds.height() - i * c.y() + pixel_bounds.y();
- drawLine(&painter,
- QPointF(pixel_bounds.x(), y),
- QPointF(pixel_bounds.x() + pixel_bounds.width(), y),
+ const int y = int(pixel_bounds.height() - i * c.y() + pixel_bounds.y());
+ drawLine(painter,
+ QPoint(pixel_bounds.x(), y),
+ QPoint(pixel_bounds.x() + pixel_bounds.width(), y),
pen);
painter.drawText(QRectF(10,
- y - metrics.height()/2,
+ y - metrics.height()/2.,
pixel_bounds.left(),
metrics.height()),
QString::number(i));
@@ -116,13 +122,13 @@ void spline_widget::drawBackground()
// vertical grid
for (int i = 0; i <= maxx; i += ystep)
{
- const qreal x = pixel_bounds.x() + i * c.x();
- drawLine(&painter,
- QPointF(x, pixel_bounds.y()),
- QPointF(x, pixel_bounds.y() + pixel_bounds.height()),
+ const int x = int(std::round(pixel_bounds.x() + i * c.x()));
+ drawLine(painter,
+ QPoint(x, pixel_bounds.y()),
+ QPoint(x, pixel_bounds.y() + pixel_bounds.height()),
pen);
const QString text = QString::number(i);
- painter.drawText(QRectF(x - metrics.width(text)/2,
+ painter.drawText(QRectF(x - metrics.width(text)/2.,
pixel_bounds.height() + 10 + metrics.height(),
metrics.width(text),
metrics.height()),
@@ -141,55 +147,56 @@ void spline_widget::drawFunction()
points_t points = _config->getPoints();
- const int alpha = !isEnabled() ? 64 : 120;
- if (!_preview_only)
- {
- for (int i = 0; i < points.size(); i++)
- {
- drawPoint(&painter,
- point_to_pixel(points[i]),
- QColor(200, 200, 210, alpha),
- isEnabled() ? QColor(50, 100, 120, 200) : QColor(200, 200, 200, 96));
- }
- }
-
- QColor color = spline_color;
-
- if (!isEnabled() && !_preview_only)
- {
- const int avg = int(float(color.red() + color.green() + color.blue())/3);
- color = QColor(int(float(color.red() + avg) * .5f),
- int(float(color.green() + avg) * .5f),
- int(float(color.blue() + avg) * .5f),
- 96);
- }
-
- QPen pen(color, 1.2, Qt::SolidLine);
+ const QColor color = progn
+ (
+ if (!isEnabled() && !_preview_only)
+ {
+ const int avg = int(float(color.red() + color.green() + color.blue())/3);
+ return QColor(int(float(color.red() + avg) * .5f),
+ int(float(color.green() + avg) * .5f),
+ int(float(color.blue() + avg) * .5f),
+ 96);
+ }
+ else
+ {
+ QColor color(spline_color);
+ color.setAlphaF(std::min(.9, color.alphaF()));
+ return color;
+ }
+ );
const qreal step_ = line_length_pixels / c.x();
- const qreal step = std::max(1e-2, step_);
+ const qreal step = std::max(5e-2, step_);
const qreal max = _config->maxInput();
- painter.save();
- painter.setPen(pen);
- painter.setBrush(Qt::NoBrush);
+ painter.setPen(QPen(color, 1.75, Qt::SolidLine, Qt::FlatCap));
- QPointF prev = point_to_pixel(QPointF(0, 0));
+ QPointF prev = point_to_pixel(QPoint(0, 0));
for (qreal i = 0; i < max; i += step)
{
const qreal val = qreal(_config->getValue(i));
- QPointF cur = point_to_pixel(QPointF(i, val));
+ const QPointF cur = point_to_pixel(QPointF(i, val));
painter.drawLine(prev, cur);
prev = cur;
}
{
const qreal val = qreal(_config->getValue(max));
- QPointF last = point_to_pixel(QPointF(max, val));
+ const QPointF last = point_to_pixel(QPointF(max, val));
painter.drawLine(prev, last);
}
- painter.restore();
+ const int alpha = !isEnabled() ? 64 : 120;
+ if (!_preview_only)
+ {
+ for (int i = 0; i < points.size(); i++)
+ {
+ drawPoint(painter,
+ point_to_pixel(points[i]),
+ QColor(200, 200, 210, alpha),
+ isEnabled() ? QColor(50, 100, 120, 200) : QColor(200, 200, 200, 96));
+ }
+ }
}
void spline_widget::paintEvent(QPaintEvent *e)
@@ -212,19 +219,21 @@ void spline_widget::paintEvent(QPaintEvent *e)
if (_config)
{
- QPen pen(Qt::white, 1, Qt::SolidLine);
+ const QPen pen(Qt::white, 1, Qt::SolidLine, Qt::FlatCap);
points_t points = _config->getPoints();
if (points.size() &&
moving_control_point_idx >= 0 &&
moving_control_point_idx < points.size())
{
if (points[0].x() > 1e-2)
- points.push_front(QPointF(0, 0));
- QPointF prev = point_to_pixel(points[0]);
+ points.push_front(QPoint(0, 0));
+ const QPointF prev_ = point_to_pixel(points[0]);
+ QPoint prev(int(std::round(prev_.x())), int(std::round(prev_.y())));
for (int i = 1; i < points.size(); i++)
{
- auto tmp = point_to_pixel(points[i]);
- drawLine(&p, prev, tmp, pen);
+ const QPointF tmp_ = point_to_pixel(points[i]);
+ const QPoint tmp(int(std::round(tmp_.x())), int(std::round(tmp_.y())));
+ drawLine(p, prev, tmp, pen);
prev = tmp;
}
}
@@ -235,39 +244,43 @@ void spline_widget::paintEvent(QPaintEvent *e)
QPointF last;
if (_config->getLastPoint(last) && isEnabled())
{
- QPointF pixel_pos = point_to_pixel(last);
- drawPoint(&p, pixel_pos, QColor(255, 0, 0, 120));
+ drawPoint(p, point_to_pixel(last), QColor(255, 0, 0, 120));
}
}
}
-void spline_widget::drawPoint(QPainter *painter, const QPointF &pos, QColor colBG, QColor border)
+void spline_widget::drawPoint(QPainter& painter, const QPointF& pos, const QColor& colBG, const QColor& border)
{
- painter->save();
- painter->setPen(border);
- painter->setBrush( colBG );
- painter->drawEllipse(QRectF(pos.x() - point_size,
+ painter.save();
+ painter.setPen(QPen(border, 1, Qt::SolidLine, Qt::PenCapStyle::FlatCap));
+ painter.setBrush(colBG);
+ painter.drawEllipse(QRectF(pos.x() - point_size,
pos.y() - point_size,
point_size*2, point_size*2));
- painter->restore();
+ painter.restore();
}
-void spline_widget::drawLine(QPainter *painter, const QPointF &start, const QPointF &end, QPen &pen)
+void spline_widget::drawLine(QPainter& painter, const QPoint& start, const QPoint& end, const QPen& pen)
{
- painter->save();
- painter->setPen(pen);
- painter->setBrush(Qt::NoBrush);
- painter->drawLine(start, end);
- painter->restore();
+ painter.save();
+ painter.setPen(pen);
+ painter.setBrush(Qt::NoBrush);
+ painter.drawLine(start, end);
+ painter.restore();
}
void spline_widget::mousePressEvent(QMouseEvent *e)
{
if (!_config || !isEnabled())
return;
+
+ if (!is_in_bounds(e->pos()))
+ return;
+
points_t points = _config->getPoints();
if (e->button() == Qt::LeftButton)
{
+ setFocus();
bool bTouchingPoint = false;
moving_control_point_idx = -1;
if (_config)
@@ -289,8 +302,8 @@ void spline_widget::mousePressEvent(QMouseEvent *e)
for (int i = 0; i < points.size(); i++)
{
const QPointF pt = point_to_pixel(points[i]);
- const qreal x = pt.x() - pos.x();
- if (point_closeness_limit * point_closeness_limit >= x * x)
+ const qreal x = std::fabs(pt.x() - pos.x());
+ if (point_closeness_limit >= x)
{
too_close = true;
break;
@@ -298,13 +311,18 @@ void spline_widget::mousePressEvent(QMouseEvent *e)
}
if (!too_close)
+ {
_config->addPoint(pixel_coord_to_point(e->pos()));
+ show_tooltip(e->pos());
+ setFocus();
+ }
}
}
}
if (e->button() == Qt::RightButton)
{
+ clearFocus();
if (_config)
{
int found_pt = -1;
@@ -333,9 +351,18 @@ void spline_widget::mouseMoveEvent(QMouseEvent *e)
if (!_config || !isEnabled())
return;
+ const bool has_focus = hasFocus();
+
+ if (!has_focus)
+ {
+ moving_control_point_idx = -1;
+ setCursor(Qt::ArrowCursor);
+ }
+
points_t points = _config->getPoints();
- if (moving_control_point_idx >= 0 &&
+ if (hasFocus() &&
+ moving_control_point_idx >= 0 &&
moving_control_point_idx < points.size())
{
const int idx = moving_control_point_idx;
@@ -344,7 +371,7 @@ void spline_widget::mouseMoveEvent(QMouseEvent *e)
bool overlap = false;
- QPointF pix = e->pos();
+ QPoint pix = e->pos();
QPointF new_pt = pixel_coord_to_point(pix);
for (int i = 0; i < 2; i++)
@@ -357,7 +384,7 @@ void spline_widget::mouseMoveEvent(QMouseEvent *e)
bad = pix.x() + point_closeness_limit > other_pix.x();
if (i == 0 && bad)
{
- pix.setX(other_pix.x() - point_closeness_limit);
+ pix.setX(int(std::round(other_pix.x() - point_closeness_limit)));
new_pt = pixel_coord_to_point(pix);
}
else
@@ -365,12 +392,12 @@ void spline_widget::mouseMoveEvent(QMouseEvent *e)
}
if (idx != 0)
{
- auto other = points[idx-1];
- auto other_pix = point_to_pixel(other);
+ const QPointF other = points[idx-1];
+ const QPointF other_pix = point_to_pixel(other);
bad = pix.x() - point_closeness_limit < other_pix.x();
if (i == 0 && bad)
{
- pix.setX(other_pix.x() + point_closeness_limit);
+ pix.setX(int(std::round(other_pix.x() + point_closeness_limit)));
new_pt = pixel_coord_to_point(pix);
}
else
@@ -385,29 +412,30 @@ void spline_widget::mouseMoveEvent(QMouseEvent *e)
points[idx] = new_pt;
_config->movePoint(int(idx), new_pt);
_draw_function = true;
+
+ show_tooltip(pix, new_pt);
update();
}
}
else
{
- bool is_on_point = false;
- for (int i = 0; i < points.size(); i++)
- {
- const QPoint pos = e->pos();
- if (point_within_pixel(points[i], pos))
- {
- is_on_point = true;
- break;
- }
- }
+ moving_control_point_idx = -1;
+
+ int i;
+ bool is_on_point = is_on_pt(e->pos(), &i);
if (is_on_point)
{
setCursor(Qt::CrossCursor);
+ show_tooltip(e->pos(), points[i]);
}
else
{
setCursor(Qt::ArrowCursor);
+ if (is_in_bounds(e->pos()))
+ show_tooltip(e->pos());
+ else
+ QToolTip::hideText();
}
}
}
@@ -417,13 +445,30 @@ void spline_widget::mouseReleaseEvent(QMouseEvent *e)
if (!_config || !isEnabled())
return;
+ clearFocus();
+
if (e->button() == Qt::LeftButton)
{
- mouseMoveEvent(e);
- setCursor(Qt::ArrowCursor);
+ //mouseMoveEvent(e);
+
+ {
+ int i;
+
+ if (is_on_pt(e->pos(), &i))
+ {
+ setCursor(Qt::CrossCursor);
+ }
+ else
+ setCursor(Qt::ArrowCursor);
+ }
moving_control_point_idx = -1;
_draw_function = true;
+ if (is_in_bounds(e->pos()))
+ show_tooltip(e->pos());
+ else
+ QToolTip::hideText();
+
update();
}
}
@@ -437,6 +482,41 @@ void spline_widget::reload_spline()
}
}
+void spline_widget::show_tooltip(const QPoint& pos, const QPointF& value_, const QString& prefix)
+{
+ const QPointF value = QPoint(0, 0) == value_ ? pixel_coord_to_point(pos) : value_;
+
+ double x = value.x(), y = value.y();
+ const int x_ = int(std::round(x)), y_ = int(std::round(y));
+
+ using std::fabs;
+
+ if (fabs(x_ - x) < 1e-3)
+ x = x_;
+ if (fabs(y_ - y) < 1e-3)
+ y = y_;
+
+ const bool is_fusion = QStringLiteral("fusion") == QApplication::style()->objectName();
+ const int add_x = (is_fusion ? 25 : 0), add_y = (is_fusion ? 15 : 0);
+
+ const QPoint pix(int(pos.x()) + add_x, int(pos.y()) + add_y);
+
+ QToolTip::showText(mapToGlobal(pix),
+ QStringLiteral("value: %1%2x%3").arg(prefix).arg(x).arg(y),
+ this,
+ rect(),
+ 0);
+}
+
+bool spline_widget::is_in_bounds(const QPoint& pos) const
+{
+ static constexpr int grace = 2;
+ return !(pos.x() + grace < pixel_bounds.left() ||
+ pos.x() - grace > pixel_bounds.right() ||
+ pos.y() + grace < pixel_bounds.top() ||
+ pos.y() - grace > pixel_bounds.bottom());
+}
+
void spline_widget::update_range()
{
if (!_config)
@@ -446,7 +526,7 @@ void spline_widget::update_range()
const int mwl = 40, mhl = 20;
const int mwr = 15, mhr = 35;
- pixel_bounds = QRectF(mwl, mhl, (w - mwl - mwr), (h - mhl - mhr));
+ pixel_bounds = QRect(mwl, mhl, (w - mwl - mwr), (h - mhl - mhr));
c = QPointF(pixel_bounds.width() / _config->maxInput(), pixel_bounds.height() / _config->maxOutput());
_draw_function = true;
@@ -456,28 +536,36 @@ void spline_widget::update_range()
update();
}
-bool spline_widget::point_within_pixel(const QPointF &pt, const QPointF &pixel)
+bool spline_widget::point_within_pixel(const QPointF& pt, const QPoint &pixel)
{
QPointF tmp = pixel - point_to_pixel(pt);
return sqrt(QPointF::dotProduct(tmp, tmp)) < point_size;
}
-QPointF spline_widget::pixel_coord_to_point(const QPointF& point)
+QPointF spline_widget::pixel_coord_to_point(const QPoint& point)
{
if (!_config)
- return QPointF(-1, -1);
+ return QPoint(-1, -1);
using std::round;
- qreal x = round((point.x() - pixel_bounds.x()) / c.x());
- qreal y = round((pixel_bounds.height() - point.y() + pixel_bounds.y()) / c.y());
+ qreal x = (point.x() - pixel_bounds.x()) / c.x();
+ qreal y = (pixel_bounds.height() - point.y() + pixel_bounds.y()) / c.y();
- const volatile int c = 8192;
+ static constexpr int c = 1000;
if (snap_x > 0)
- x = std::nearbyint(x * c - (int(x * c) % int(snap_x * c))) / double(c);
+ {
+ x -= std::fmod(x, snap_x);
+ const volatile int x_ = int(x * c);
+ x = x_ / double(c);
+ }
if (snap_y > 0)
- y = std::nearbyint(y * c - (int(y * c) % int(snap_y * c))) / double(c);
+ {
+ y -= std::fmod(y, snap_y);
+ const volatile int y_ = int(y * c);
+ y = y_ / double(c);
+ }
if (x < 0)
x = 0;
@@ -494,11 +582,37 @@ QPointF spline_widget::pixel_coord_to_point(const QPointF& point)
QPointF spline_widget::point_to_pixel(const QPointF& point)
{
- return QPointF(pixel_bounds.x() + point.x() * c.x(),
- pixel_bounds.y() + pixel_bounds.height() - point.y() * c.y());
+ return QPoint(int(std::round(pixel_bounds.x() + point.x() * c.x())),
+ int(std::round(pixel_bounds.y() + pixel_bounds.height() - point.y() * c.y())));
}
void spline_widget::resizeEvent(QResizeEvent *)
{
update_range();
}
+
+bool spline_widget::is_on_pt(const QPoint& pos, int* pt)
+{
+ if (!_config)
+ {
+ if (pt)
+ *pt = -1;
+ return false;
+ }
+
+ const points_t points = _config->getPoints();
+
+ for (int i = 0; i < points.size(); i++)
+ {
+ if (point_within_pixel(points[i], pos))
+ {
+ if (pt)
+ *pt = i;
+ return true;
+ }
+ }
+
+ if (pt)
+ *pt = -1;
+ return false;
+}
diff --git a/spline-widget/spline-widget.hpp b/spline-widget/spline-widget.hpp
index 94e6b32c..53560d6a 100644
--- a/spline-widget/spline-widget.hpp
+++ b/spline-widget/spline-widget.hpp
@@ -17,9 +17,13 @@ using namespace options;
#include "export.hpp"
#include <QWidget>
-#include <QtGui>
-#include <QMetaObject>
+#include <QRect>
+#include <QPoint>
#include <QPointF>
+#include <QToolTip>
+#include <QShowEvent>
+#include <QMetaObject>
+
#include <QDebug>
class OPENTRACK_SPLINE_EXPORT spline_widget final : public QWidget
@@ -62,30 +66,31 @@ protected slots:
void mouseReleaseEvent(QMouseEvent *e) override;
void reload_spline();
private:
+ void show_tooltip(const QPoint& pos, const QPointF& value = QPointF(0, 0), const QString& prefix = QStringLiteral(""));
+ bool is_in_bounds(const QPoint& pos) const;
+
void drawBackground();
void drawFunction();
- void drawPoint(QPainter *painter, const QPointF &pt, QColor colBG, QColor border = QColor(50, 100, 120, 200));
- void drawLine(QPainter *painter, const QPointF &start, const QPointF &end, QPen& pen);
- bool point_within_pixel(const QPointF& pt, const QPointF& pixel);
+ void drawPoint(QPainter& painter, const QPointF& pt, const QColor& colBG, const QColor& border = QColor(50, 100, 120, 200));
+ void drawLine(QPainter& painter, const QPoint& start, const QPoint& end, const QPen& pen);
+ bool point_within_pixel(const QPointF& pt, const QPoint& pixel);
protected:
void resizeEvent(QResizeEvent *) override;
private:
+ bool is_on_pt(const QPoint& pos, int* pt = nullptr);
void update_range();
-
- QPointF pixel_coord_to_point (const QPointF& point);
+ QPointF pixel_coord_to_point(const QPoint& point);
QPointF point_to_pixel(const QPointF& point);
- spline* _config;
-
- // bounds of the rectangle user can interact with
- QRectF pixel_bounds;
-
QPointF c;
-
- QColor spline_color;
+ spline* _config;
QPixmap _background;
QPixmap _function;
+ QColor spline_color;
+
+ // bounds of the rectangle user can interact with
+ QRect pixel_bounds;
QMetaObject::Connection connection;
@@ -95,5 +100,5 @@ private:
static constexpr int line_length_pixels = 3;
static constexpr int point_size = 4;
- static constexpr int point_closeness_limit = 5;
+ static constexpr int point_closeness_limit = 7;
};