diff options
Diffstat (limited to 'spline/spline-widget.cpp')
-rw-r--r-- | spline/spline-widget.cpp | 493 |
1 files changed, 257 insertions, 236 deletions
diff --git a/spline/spline-widget.cpp b/spline/spline-widget.cpp index 638b67a7..46e2095c 100644 --- a/spline/spline-widget.cpp +++ b/spline/spline-widget.cpp @@ -1,62 +1,59 @@ -/* Copyright (c) 2012-2016 Stanislaw Halik <sthalik@misaki.pl> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - */ - #include "spline-widget.hpp" #include "compat/math.hpp" + +#include <algorithm> + #include <QPainter> #include <QPainterPath> -#include <QPaintEvent> -#include <QPen> #include <QPixmap> -#include <QList> -#include <QPoint> #include <QString> -#include <QRect> -#include <QApplication> -#include <QStyle> -#include <QMouseEvent> +#include <QToolTip> +#include <QtEvents> +#include <QPainterPath> #include <QDebug> -#include <cmath> -#include <algorithm> +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) +# define OTR_OBSOLETE_QT_WORKAROUND +#endif + +namespace spline_detail { spline_widget::spline_widget(QWidget *parent) : QWidget(parent) { setMouseTracking(true); - setFocusPolicy(Qt::ClickFocus); + //setFocusPolicy(Qt::ClickFocus); setCursor(Qt::ArrowCursor); } spline_widget::~spline_widget() { if (connection) + { QObject::disconnect(connection); + connection = {}; + } } -void spline_widget::setConfig(base_spline* spl) +void spline_widget::set_config(base_spline* spl) { if (connection) { QObject::disconnect(connection); - connection = QMetaObject::Connection(); + connection = {}; } - _config = spl; + config = spl; if (spl) { - update_range(); - - std::shared_ptr<base_spline::base_settings> s = spl->get_settings(); - connection = connect(s.get(), &spline::base_settings::recomputed, - this, [this]() { reload_spline(); }, + std::shared_ptr<base_settings> s = spl->get_settings(); + connection = connect(&*s, &base_settings::recomputed, + this, [this] { reload_spline(); }, Qt::QueuedConnection); } + + reload_spline(); } QColor spline_widget::colorBezier() const @@ -64,7 +61,7 @@ QColor spline_widget::colorBezier() const return spline_color; } -void spline_widget::setColorBezier(QColor color) +void spline_widget::setColorBezier(QColor const& color) { spline_color = color; repaint(); @@ -72,37 +69,38 @@ void spline_widget::setColorBezier(QColor color) void spline_widget::force_redraw() { - _background = QPixmap(); + background_img = {}; repaint(); } void spline_widget::set_preview_only(bool val) { - _preview_only = val; + preview_only = val; } bool spline_widget::is_preview_only() const { - return _preview_only; + return preview_only; } void spline_widget::drawBackground() { - QPainter painter(&_background); + QPainter painter(&background_img); painter.fillRect(rect(), widget_bg_color); { QColor bg_color(112, 154, 209); - if (!isEnabled() && !_preview_only) + if (!isEnabled() && !preview_only) bg_color = QColor(176,176,180); painter.fillRect(pixel_bounds, bg_color); } QFont font; font.setPointSize(8); + font.setStyleHint(QFont::Monospace, QFont::PreferAntialias); painter.setFont(font); - QFontMetrics metrics(font); + const QFontMetricsF metrics(font); QColor color__(176, 190, 209, 127); @@ -111,66 +109,80 @@ void spline_widget::drawBackground() const QPen pen(color__, 1, Qt::SolidLine, Qt::FlatCap); - const int ystep = _y_step, xstep = _x_step; - const qreal maxx = _config->max_input(); - const qreal maxy = _config->max_output(); + const int ystep = (int)std::ceil(y_step_), xstep = (int)std::ceil(x_step_); + const double maxx = config->max_input(); + const double maxy = config->max_output(); +#ifndef OTR_OBSOLETE_QT_WORKAROUND + double space_width = metrics.horizontalAdvance(' '); +#else + double space_width = metrics.boundingRect(' ').right(); +#endif + painter.setPen(palette().text().color()); - // horizontal grid + // vertical grid for (int i = 0; i <= maxy; i += ystep) { - const int y = int(pixel_bounds.height() - i * c.y() + pixel_bounds.y()); + const double y = pixel_bounds.height() - i * c.y() + pixel_bounds.y(); drawLine(painter, - QPoint(pixel_bounds.x(), y), - QPoint(pixel_bounds.x() + pixel_bounds.width(), y), + QPointF(pixel_bounds.x(), y), + QPointF(pixel_bounds.x() + pixel_bounds.width(), y), pen); - painter.drawText(QRectF(10, - y - metrics.height()/2., - pixel_bounds.left(), - metrics.height()), - QString::number(i)); + QString text = QString::number(i); + QRectF rect = metrics.boundingRect(text); +#ifndef OTR_OBSOLETE_QT_WORKAROUND + double advance = metrics.horizontalAdvance(text); +#else + double advance = rect.right(); +#endif + painter.drawText(QPointF(pixel_bounds.x() - advance - space_width, + y - rect.height()/2 - rect.top()), + text); } - // vertical grid + // horizontal grid for (int i = 0; i <= maxx; i += xstep) { - const int x = iround(pixel_bounds.x() + i * c.x()); + const double x = pixel_bounds.x() + i * c.x(); drawLine(painter, - QPoint(x, pixel_bounds.y()), - QPoint(x, pixel_bounds.y() + pixel_bounds.height()), + QPointF(x, pixel_bounds.y()), + QPointF(x, pixel_bounds.y() + pixel_bounds.height()), pen); + const QString text = QString::number(i); - painter.drawText(QRectF(x - metrics.width(text)/2., - pixel_bounds.height() + 10 + metrics.height(), - metrics.width(text), - metrics.height()), + QRectF rect = metrics.boundingRect(text); +#ifndef OTR_OBSOLETE_QT_WORKAROUND + double advance = metrics.horizontalAdvance(text); +#else + double advance = metrics.boundingRect(text).right(); +#endif + painter.drawText(QPointF(x - advance/2 - rect.left(), + pixel_bounds.bottom() + metrics.lineSpacing()), text); } } void spline_widget::drawFunction() { - QPainter painter(&_function); + QPainter painter(&spline_img); painter.setRenderHint(QPainter::Antialiasing, true); - const points_t points = _config->get_points(); + const points_t& points = config->get_points(); if (moving_control_point_idx >= 0 && moving_control_point_idx < points.size()) { const QPen pen(Qt::white, 1, Qt::SolidLine, Qt::FlatCap); - const QPointF prev_ = point_to_pixel(QPointF(0, 0)); - QPoint prev(iround(prev_.x()), iround(prev_.y())); - for (int i = 0; i < points.size(); i++) + QPointF prev = point_to_pixel({}); + for (const auto& point : points) { - const QPointF tmp_ = point_to_pixel(points[i]); - const QPoint tmp(iround(tmp_.x()), iround(tmp_.y())); + const QPointF tmp = point_to_pixel(point); drawLine(painter, prev, tmp, pen); prev = tmp; } } const QColor color_ = progn( - if (!isEnabled() && !_preview_only) + if (!isEnabled() && !preview_only) { QColor color(spline_color); const int avg = int(float(color.red() + color.green() + color.blue())/3); @@ -187,57 +199,58 @@ void spline_widget::drawFunction() } ); - painter.setPen(QPen(color_, 1.75, Qt::SolidLine, Qt::FlatCap)); + painter.setPen(QPen(color_, 2, Qt::SolidLine, Qt::FlatCap)); -//#define DEBUG_SPLINE -#ifndef DEBUG_SPLINE - constexpr double step_ = 5; - - const double maxx = _config->max_input(); - const double step = step_ / c.x(); + const double dpr = screen_dpi(); + const double line_length_pixels = std::fmax(1, dpr); + const double step = std::fmax(.1, line_length_pixels / c.x()); + const double maxx = config->max_input(); +#define USE_CUBIC_SPLINE +#if defined USE_CUBIC_SPLINE QPainterPath path; - path.moveTo(point_to_pixel(QPointF(0, 0))); + path.moveTo(point_to_pixel({})); - const double max_x_pixel = point_to_pixel_(QPointF(maxx, 0)).x(); + const double max_x_pixel = point_to_pixel({maxx, 0}).x(); - auto check = [=](const QPointF& val) { - return val.x() < max_x_pixel + auto clamp = [=](const QPointF& val) { + return val.x() <= max_x_pixel ? val - : QPointF(max_x_pixel, val.y()); + : QPointF{max_x_pixel, val.y()}; }; - for (double k = 0; k < maxx; k += step*3) - { - const float next_1(_config->get_value_no_save(k + step*1)); - const float next_2(_config->get_value_no_save(k + step*2)); - const float next_3(_config->get_value_no_save(k + step*3)); + const auto fn = [&] (double k) { + const auto next_1 = config->get_value_no_save(k + step*1); + const auto next_2 = config->get_value_no_save(k + step*2); + const auto next_3 = config->get_value_no_save(k + step*3); - QPointF b(check(point_to_pixel_(QPointF(k + step*1, qreal(next_1))))), - c(check(point_to_pixel_(QPointF(k + step*2, qreal(next_2))))), - d(check(point_to_pixel_(QPointF(k + step*3, qreal(next_3))))); + QPointF b(clamp(point_to_pixel({k + step*1, next_1}))), + c(clamp(point_to_pixel({k + step*2, next_2}))), + d(clamp(point_to_pixel({k + step*3, next_3}))); - path.cubicTo(b, c, d); - } + path.cubicTo(b, c, d); + }; + + for (double k = 0; k < maxx; k += step*3) // NOLINT + fn(k); + + fn(maxx); painter.drawPath(path); #else - constexpr int line_length_pixels = 3; - const qreal max = _config->maxInput(); - const qreal step = clamp(line_length_pixels / c.x(), 5e-2, max); - QPointF prev = point_to_pixel(QPoint(0, 0)); - for (qreal i = 0; i < max; i += step) + QPointF prev = point_to_pixel({}); + for (double i = 0; i < maxx; i += step) // NOLINT { - const qreal val = qreal(_config->get_value_no_save(i)); - const QPointF cur = point_to_pixel(QPointF(i, val)); + const auto val = config->get_value_no_save(i); + const QPointF cur = point_to_pixel({i, val}); painter.drawLine(prev, cur); prev = cur; } { - const qreal maxx = _config->maxInput(); - const qreal maxy = qreal(_config->get_value_no_save(maxx)); - painter.drawLine(QPointF(prev), point_to_pixel_(QPointF(maxx, maxy))); + const double maxx = config->max_input(); + const double maxy = config->get_value_no_save(maxx); + painter.drawLine(prev, point_to_pixel({ maxx, maxy })); } #endif @@ -250,51 +263,59 @@ void spline_widget::drawFunction() painter.fillRect(r2, widget_bg_color); const int alpha = !isEnabled() ? 64 : 120; - if (!_preview_only) + if (!preview_only) { - for (int i = 0; i < points.size(); i++) + for (auto const& point : points) { drawPoint(painter, - point_to_pixel(points[i]), + point_to_pixel(point), QColor(200, 200, 210, alpha), isEnabled() ? QColor(50, 100, 120, 200) : QColor(200, 200, 200, 96)); } } } +QSize spline_widget::minimumSizeHint() const +{ + const double dpi = screen_dpi(); + return { iround(800 * dpi), iround(250 * dpi) }; +} + void spline_widget::paintEvent(QPaintEvent *e) { - if (!_config) + if (!config) return; QPainter p(this); const double dpr = devicePixelRatioF(); - const int W = int(width() * dpr); - const int H = int(height() * dpr); + const int W = iround(width() * dpr); + const int H = iround(height() * dpr); - if (_background.size() != QSize(W, H)) + if (background_img.size() != QSize(W, H)) { - _background = QPixmap(W, H); - _background.setDevicePixelRatio(dpr); - _draw_function = true; + update_range(); + + background_img = { W, H }; + background_img.setDevicePixelRatio(dpr); drawBackground(); + draw_function = true; } - if (_draw_function) + if (draw_function) { - _draw_function = false; - _function = _background; + draw_function = false; + spline_img = background_img; drawFunction(); } - p.drawPixmap(e->rect(), _function); + p.drawPixmap(e->rect(), spline_img); // If the Tracker is active, the 'Last Point' it requested is recorded. // Show that point on the graph, with some lines to assist. // This new feature is very handy for tweaking the curves! QPointF last; - if (_config->get_last_value(last) && isEnabled()) + if (config->get_last_value(last) && isEnabled()) drawPoint(p, point_to_pixel(last), QColor(255, 0, 0, 120)); } @@ -303,13 +324,13 @@ void spline_widget::drawPoint(QPainter& painter, const QPointF& pos, const QColo 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.drawEllipse(QRectF{pos.x() - point_size_in_pixels, + pos.y() - point_size_in_pixels, + point_size_in_pixels*2, point_size_in_pixels*2}); painter.restore(); } -void spline_widget::drawLine(QPainter& painter, const QPoint& start, const QPoint& end, const QPen& pen) +void spline_widget::drawLine(QPainter& painter, const QPointF& start, const QPointF& end, const QPen& pen) { painter.save(); painter.setPen(pen); @@ -320,17 +341,14 @@ void spline_widget::drawLine(QPainter& painter, const QPoint& start, const QPoin void spline_widget::mousePressEvent(QMouseEvent *e) { - if (!_config || !isEnabled() || !is_in_bounds(e->pos()) || _preview_only) - { - clearFocus(); + if (!config || !isEnabled() || !is_in_bounds(e->localPos()) || preview_only) return; - } - const int point_pixel_closeness_limit = get_closeness_limit(); + const double min_dist = min_pt_distance(); moving_control_point_idx = -1; - points_t points = _config->get_points(); + const points_t& points = config->get_points(); if (e->button() == Qt::LeftButton) { @@ -338,7 +356,7 @@ void spline_widget::mousePressEvent(QMouseEvent *e) for (int i = 0; i < points.size(); i++) { - if (point_within_pixel(points[i], e->pos())) + if (point_within_pixel(points[i], e->localPos())) { is_touching_point = true; moving_control_point_idx = i; @@ -349,13 +367,12 @@ void spline_widget::mousePressEvent(QMouseEvent *e) if (!is_touching_point) { bool too_close = false; - const QPoint pos = e->pos(); + const QPointF pos = pixel_to_point(e->localPos()); - for (int i = 0; i < points.size(); i++) + for (QPointF const& point : points) { - const QPointF pt = point_to_pixel(points[i]); - const qreal x = std::fabs(pt.x() - pos.x()); - if (point_pixel_closeness_limit >= x) + const double x = std::fabs(point.x() - pos.x()); + if (min_dist > x) { too_close = true; break; @@ -364,93 +381,91 @@ void spline_widget::mousePressEvent(QMouseEvent *e) if (!too_close) { - _config->add_point(pixel_coord_to_point(e->pos())); + config->add_point(pixel_to_point(e->localPos())); show_tooltip(e->pos()); } } - _draw_function = true; + draw_function = true; } if (e->button() == Qt::RightButton) { - if (_config) + if (config) { - int found_pt = -1; for (int i = 0; i < points.size(); i++) { - if (point_within_pixel(points[i], e->pos())) + if (point_within_pixel(points[i], e->localPos())) { - found_pt = i; + config->remove_point(i); + draw_function = true; break; } } - - if (found_pt != -1) - { - _config->remove_point(found_pt); - _draw_function = true; - } } } - if (_draw_function) + if (draw_function) repaint(); } void spline_widget::mouseMoveEvent(QMouseEvent *e) { - if (_preview_only && _config) + if (preview_only && config) { show_tooltip(e->pos()); - clearFocus(); return; } - if (!_config || !isEnabled() || !isActiveWindow() || (moving_control_point_idx != -1 && !hasFocus())) + if (!config || !isEnabled() || !isActiveWindow()) { - clearFocus(); + QToolTip::hideText(); return; } const int i = moving_control_point_idx; - const points_t points = _config->get_points(); + const points_t& points = config->get_points(); const int sz = points.size(); if (i >= 0 && i < sz) { - const int point_closeness_limit = get_closeness_limit(); - bool overlap = false; + const double min_dist = min_pt_distance(); + QPointF new_pt = pixel_to_point(e->localPos()); + + const bool has_prev = i > 0, has_next = i + 1 < points.size(); - const QPointF pix_ = point_to_pixel(pixel_coord_to_point(e->pos())); - const QPoint pix(int(pix_.x()), int(pix_.y())); + auto check_next = [&] { + return points[i+1].x() - new_pt.x() >= min_dist; + }; - QPointF new_pt = pixel_coord_to_point(e->pos()); + auto check_prev = [&] { + return new_pt.x() - points[i-1].x() >= min_dist; + }; - if (i + 1 < points.size()) + if (has_prev && !check_prev()) { - overlap |= points[i+1].x() - new_pt.x() < point_closeness_limit; + new_pt.rx() = points[i-1].x() + min_dist + 1e-4; } - if (i > 0) + + if (has_next && !check_next()) { - overlap |= new_pt.x() - points[i-1].x() < point_closeness_limit; + new_pt.rx() = points[i+1].x() - min_dist - 1e-4; } - if (overlap) - new_pt = QPointF(points[i].x(), new_pt.y()); - - _config->move_point(i, new_pt); - - _draw_function = true; - repaint(); - setCursor(Qt::ClosedHandCursor); - show_tooltip(pix, new_pt); + show_tooltip(point_to_pixel(new_pt).toPoint(), new_pt); + + if ((!has_prev || check_prev()) && (!has_next || check_next())) + { + config->move_point(i, new_pt); + draw_function = true; + repaint(); + } } else if (sz) { int i; - bool is_on_point = is_on_pt(e->pos(), &i); + bool is_on_point = is_on_pt(e->localPos(), &i); if (is_on_point) { @@ -460,7 +475,7 @@ void spline_widget::mouseMoveEvent(QMouseEvent *e) else { setCursor(Qt::ArrowCursor); - if (is_in_bounds(e->pos())) + if (is_in_bounds(e->localPos())) show_tooltip(e->pos()); else QToolTip::hideText(); @@ -470,11 +485,8 @@ void spline_widget::mouseMoveEvent(QMouseEvent *e) void spline_widget::mouseReleaseEvent(QMouseEvent *e) { - if (!_config || !isEnabled() || !isActiveWindow() || !hasFocus() || _preview_only) - { - clearFocus(); + if (!config || !isEnabled() || !isActiveWindow() || preview_only) return; - } const bool redraw = moving_control_point_idx != -1; moving_control_point_idx = -1; @@ -482,13 +494,13 @@ void spline_widget::mouseReleaseEvent(QMouseEvent *e) if (e->button() == Qt::LeftButton) { { - if (is_on_pt(e->pos(), nullptr)) + if (is_on_pt(e->localPos(), nullptr)) setCursor(Qt::CrossCursor); else setCursor(Qt::ArrowCursor); } - if (is_in_bounds(e->pos())) + if (is_in_bounds(e->localPos())) show_tooltip(e->pos()); else QToolTip::hideText(); @@ -496,7 +508,7 @@ void spline_widget::mouseReleaseEvent(QMouseEvent *e) if (redraw) { - _draw_function = true; + draw_function = true; repaint(); } } @@ -504,49 +516,53 @@ void spline_widget::mouseReleaseEvent(QMouseEvent *e) void spline_widget::reload_spline() { // don't recompute here as the value's about to be recomputed in the callee - update_range(); + background_img = {}; update(); } -int spline_widget::get_closeness_limit() +double spline_widget::min_pt_distance() const { - return iround(std::fmax(snap_x, 1)); + double pt = 3*point_size_in_pixels / c.x(); + pt = snap(pt, snap_x); + return pt; } void spline_widget::show_tooltip(const QPoint& pos, const QPointF& value_) { - const QPointF value = QPoint(0, 0) == value_ ? pixel_coord_to_point(pos) : value_; + const QPointF value = value_.isNull() ? pixel_to_point(pos) : value_; double x = value.x(), y = value.y(); - if (_preview_only) - y = _config->get_value_no_save(x); + if (preview_only) + y = config->get_value_no_save(x); const int x_ = iround(x), y_ = iround(y); - using std::fabs; - - if (fabs(x_ - x) < 1e-3) + if (std::fabs(x_ - x) < 1e-3) x = x_; - if (fabs(y_ - y) < 1e-3) + if (std::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); + // the native OSX style doesn't look right otherwise +#if defined __APPLE__ + constexpr int off_x = 0, off_y = 0; +#else + constexpr int off_x = 25, off_y = 15; +#endif - const QPoint pix(pos.x() + add_x, pos.y() + add_y); + const QPoint pix(pos.x() + off_x, pos.y() + off_y); QToolTip::showText(mapToGlobal(pix), - QStringLiteral("value: %1x%2").arg(x, 0, 'f', 2).arg(y, 0, 'f', 2), + QString{"value: %1x%2"}.arg(x, 0, 'f', 2).arg(y, 0, 'f', 2), this, rect(), 0); } -bool spline_widget::is_in_bounds(const QPoint& pos) const +bool spline_widget::is_in_bounds(const QPointF& pos) const { - constexpr int grace = point_size * 3; - constexpr int bottom_grace = int(point_size * 1.5); + const int grace = (int)std::ceil(point_size_in_pixels * 3); + const int bottom_grace = (int)std::ceil(point_size_in_pixels * 1.5); return (pos.x() + grace > pixel_bounds.left() && pos.x() - grace < pixel_bounds.right() && pos.y() + grace > pixel_bounds.top() && @@ -555,27 +571,28 @@ bool spline_widget::is_in_bounds(const QPoint& pos) const void spline_widget::update_range() { - if (!_config) + if (!config) return; const int w = width(), h = height(); const int mwl = 40, mhl = 20; const int mwr = 15, mhr = 35; - pixel_bounds = QRect(mwl, mhl, (w - mwl - mwr), (h - mhl - mhr)); - c = QPointF(pixel_bounds.width() / _config->max_input(), pixel_bounds.height() / _config->max_output()); - _draw_function = true; - - _background = QPixmap(); - _function = QPixmap(); + pixel_bounds = { mwl, mhl, (w - mwl - mwr), (h - mhl - mhr) }; + c = { + pixel_bounds.width() / std::fmax(1, config->max_input()), + pixel_bounds.height() / std::fmax(1, config->max_output()) + }; - repaint(); + draw_function = true; + background_img = {}; + spline_img = {}; } -bool spline_widget::point_within_pixel(const QPointF& pt, const QPoint &pixel) +bool spline_widget::point_within_pixel(const QPointF& pt, const QPointF& pixel) { const QPointF tmp = pixel - point_to_pixel(pt); - return QPointF::dotProduct(tmp, tmp) < point_size * point_size; + return QPointF::dotProduct(tmp, tmp) < point_size_in_pixels * point_size_in_pixels; } void spline_widget::focusOutEvent(QFocusEvent* e) @@ -583,76 +600,66 @@ void spline_widget::focusOutEvent(QFocusEvent* e) if (moving_control_point_idx != -1) QToolTip::hideText(); moving_control_point_idx = -1; - _draw_function = true; + draw_function = true; lower(); setCursor(Qt::ArrowCursor); e->accept(); } -QPointF spline_widget::pixel_coord_to_point(const QPoint& point) +double spline_widget::snap(double x, double snap_value) { - qreal x = (point.x() - pixel_bounds.x()) / c.x(); - qreal y = (pixel_bounds.height() - point.y() + pixel_bounds.y()) / c.y(); - - constexpr int c = 1000; - - if (snap_x > 0) + if (snap_value > 0) { - x += snap_x * .5; - x -= std::fmod(x, snap_x); + constexpr int c = 1000; + x += snap_value * .5; + x -= std::fmod(x, snap_value); // truncate after few decimal places to reduce rounding errors. - // round upward to nearest. + // round upward. x = int(x * c + .5/c) / double(c); } - if (snap_y > 0) - { - y += snap_y * .5; - y -= std::fmod(y, snap_y); - // idem - y = int(y * c + .5/c) / double(c); - } - - if (x < 0) - x = 0; - if (x > _config->max_input()) - x = _config->max_input(); - - if (y < 0) - y = 0; - if (y > _config->max_output()) - y = _config->max_output(); - return QPointF(x, y); + return x; } -QPointF spline_widget::point_to_pixel_(const QPointF& point) +QPointF spline_widget::pixel_to_point(const QPointF& point) { - return QPointF(pixel_bounds.x() + point.x() * c.x(), - pixel_bounds.y() + pixel_bounds.height() - point.y() * c.y()); + double x = (point.x() - pixel_bounds.x()) / c.x(); + double y = (pixel_bounds.height() - point.y() + pixel_bounds.y()) / c.y(); + + if (snap_x > 0) + x = snap(x, snap_x); + if (snap_y > 0) + y = snap(y, snap_y); + + x = std::clamp(x, 0., config->max_input()); + y = std::clamp(y, 0., config->max_output()); + + return { x, y }; } -QPoint spline_widget::point_to_pixel(const QPointF& point) +QPointF spline_widget::point_to_pixel(const QPointF& point) { - QPointF pt(point_to_pixel_(point)); - - return QPoint(iround(pt.x()), iround(pt.y())); + return { + pixel_bounds.x() + point.x() * c.x(), + pixel_bounds.y() + pixel_bounds.height() - point.y() * c.y() + }; } void spline_widget::resizeEvent(QResizeEvent *) { - update_range(); + reload_spline(); } -bool spline_widget::is_on_pt(const QPoint& pos, int* pt) +bool spline_widget::is_on_pt(const QPointF& pos, int* pt) { - if (!_config) + if (!config) { if (pt) *pt = -1; return false; } - const points_t points = _config->get_points(); + const points_t& points = config->get_points(); for (int i = 0; i < points.size(); i++) { @@ -668,3 +675,17 @@ bool spline_widget::is_on_pt(const QPoint& pos, int* pt) *pt = -1; return false; } + +void spline_widget::changeEvent(QEvent* e) +{ + switch (e->type()) + { + case QEvent::EnabledChange: + background_img = {}; spline_img = {}; + update(); + break; + default: + break; + } +} +} // ns spline_detail |