diff options
Diffstat (limited to 'spline-widget/spline-widget.cpp')
-rw-r--r-- | spline-widget/spline-widget.cpp | 652 |
1 files changed, 0 insertions, 652 deletions
diff --git a/spline-widget/spline-widget.cpp b/spline-widget/spline-widget.cpp deleted file mode 100644 index c7dd5e5a..00000000 --- a/spline-widget/spline-widget.cpp +++ /dev/null @@ -1,652 +0,0 @@ -/* 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 "compat/util.hpp" -#include "spline-widget.hpp" -#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 <QDebug> - -#include <cmath> -#include <algorithm> - -spline_widget::spline_widget(QWidget *parent) : - QWidget(parent), - _config(nullptr), - snap_x(0), - snap_y(0), - _x_step(10), - _y_step(10), - moving_control_point_idx(-1), - _draw_function(true), - _preview_only(false) -{ - setMouseTracking(true); - setFocusPolicy(Qt::ClickFocus); - setCursor(Qt::ArrowCursor); -} - -spline_widget::~spline_widget() -{ - if (connection) - QObject::disconnect(connection); -} - -void spline_widget::setConfig(spline* spl) -{ - if (spl != _config) - { - if (connection) - { - QObject::disconnect(connection); - connection = QMetaObject::Connection(); - } - - if (spl) - { - mem<spline::settings> s = spl->get_settings(); - connection = connect(s.get(), &spline::settings::recomputed, - this, [this]() { reload_spline(); }, - Qt::QueuedConnection); - } - - _config = spl; - _background = QPixmap(); - update_range(); - } -} - -QColor spline_widget::colorBezier() const -{ - return spline_color; -} - -void spline_widget::setColorBezier(QColor color) -{ - spline_color = color; - update(); -} - -void spline_widget::force_redraw() -{ - _background = QPixmap(); - update(); -} - -void spline_widget::set_preview_only(bool val) -{ - _preview_only = val; -} - -bool spline_widget::is_preview_only() const -{ - return _preview_only; -} - -void spline_widget::drawBackground() -{ - _background = QPixmap(width(), height()); - - QPainter painter(&_background); - - painter.fillRect(rect(), palette().color(QPalette::Light)); - - QColor bg_color(112, 154, 209); - if (!isEnabled() && !_preview_only) - bg_color = QColor(176,176,180); - painter.fillRect(pixel_bounds, bg_color); - - QFont font; - font.setPointSize(8); - painter.setFont(font); - QFontMetrics metrics(font); - - QColor color__(176, 190, 209, 127); - - if (!isEnabled()) - color__ = QColor(70, 90, 100, 96); - - 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(); - - // horizontal grid - for (int i = 0; i <= maxy; i += ystep) - { - 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., - pixel_bounds.left(), - metrics.height()), - QString::number(i)); - } - - // vertical grid - for (int i = 0; i <= maxx; i += xstep) - { - const int x = iround(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., - pixel_bounds.height() + 10 + metrics.height(), - metrics.width(text), - metrics.height()), - text); - } -} - -void spline_widget::drawFunction() -{ - _function = _background; - QPainter painter(&_function); - painter.setRenderHint(QPainter::Antialiasing, true); - - 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++) - { - const QPointF tmp_ = point_to_pixel(points[i]); - const QPoint tmp(iround(tmp_.x()), iround(tmp_.y())); - drawLine(painter, prev, tmp, pen); - prev = tmp; - } - } - - const QColor color = progn - ( - if (!isEnabled() && !_preview_only) - { - QColor color(spline_color); - 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(color.alphaF() * .9); - return color; - } - ); - - painter.setPen(QPen(color, 1.75, Qt::SolidLine, Qt::FlatCap)); - -//#define DEBUG_SPLINE -#ifndef DEBUG_SPLINE - static constexpr double step_ = 3./3; - - const double maxx = _config->max_input(); - const double step = step_ / c.x(); - - QPainterPath path; - - path.moveTo(point_to_pixel(QPointF(0, 0))); - - 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 QPointF b(point_to_pixel_(QPointF(k + step*1, qreal(next_1)))), - c(point_to_pixel_(QPointF(k + step*2, qreal(next_2)))), - d(point_to_pixel_(QPointF(k + step*3, qreal(next_3)))); - - path.cubicTo(b, c, d); - } - - painter.drawPath(path); -#else - static 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) - { - const qreal val = qreal(_config->get_value_no_save(i)); - const QPointF cur = point_to_pixel(QPointF(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))); - } -#endif - - 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) -{ - if (!_config) - return; - - QPainter p(this); - - if (_background.isNull()) - { - _draw_function = true; - drawBackground(); - } - - if (_draw_function) - { - _draw_function = false; - drawFunction(); - } - - p.drawPixmap(e->rect(), _function); - - // 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()) - drawPoint(p, point_to_pixel(last), QColor(255, 0, 0, 120)); -} - -void spline_widget::drawPoint(QPainter& painter, const QPointF& pos, const QColor& colBG, const QColor& border) -{ - 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(); -} - -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(); -} - -void spline_widget::mousePressEvent(QMouseEvent *e) -{ - if (!_config || !isEnabled() || !is_in_bounds(e->pos())) - { - clearFocus(); - return; - } - - const int point_pixel_closeness_limit = get_closeness_limit(); - - points_t points = _config->get_points(); - if (e->button() == Qt::LeftButton) - { - bool bTouchingPoint = false; - moving_control_point_idx = -1; - for (int i = 0; i < points.size(); i++) - { - if (point_within_pixel(points[i], e->pos())) - { - bTouchingPoint = true; - moving_control_point_idx = int(i); - break; - } - } - if (!bTouchingPoint) - { - bool too_close = false; - const QPoint pos = e->pos(); - - for (int i = 0; i < points.size(); i++) - { - const QPointF pt = point_to_pixel(points[i]); - const qreal x = std::fabs(pt.x() - pos.x()); - if (point_pixel_closeness_limit >= x) - { - too_close = true; - break; - } - } - - if (!too_close) - { - _config->add_point(pixel_coord_to_point(e->pos())); - show_tooltip(e->pos()); - } - } - } - - if (e->button() == Qt::RightButton) - { - if (_config) - { - int found_pt = -1; - for (int i = 0; i < points.size(); i++) - { - if (point_within_pixel(points[i], e->pos())) - { - found_pt = i; - break; - } - } - - if (found_pt != -1) - { - _config->remove_point(found_pt); - } - moving_control_point_idx = -1; - } - } - _draw_function = true; - update(); -} - -void spline_widget::mouseMoveEvent(QMouseEvent *e) -{ - if (_preview_only && _config) - { - show_tooltip(e->pos()); - clearFocus(); - return; - } - - if (!_config || !isEnabled() || !isActiveWindow() || (moving_control_point_idx != -1 && !hasFocus())) - { - clearFocus(); - return; - } - - const int i = moving_control_point_idx; - const points_t points = _config->get_points(); - const int sz = points.size(); - - if (i >= 0 && i < sz) - { - const int point_pixel_closeness_limit = get_closeness_limit(); - bool overlap = false; - - const QPoint pix = progn( - // takes snap into account - const QPointF pix_ = point_to_pixel(pixel_coord_to_point(e->pos())); - return QPoint(int(pix_.x()), int(pix_.y())); - ); - - QPointF new_pt = pixel_coord_to_point(e->pos()); - - if (i + 1 < points.size()) - { - const QPointF other_pix = point_to_pixel(points[i+1]); - overlap |= other_pix.x() - pix.x() < point_pixel_closeness_limit; - } - if (i != 0) - { - const QPointF other_pix = point_to_pixel(points[i-1]); - overlap |= pix.x() - other_pix.x() < point_pixel_closeness_limit; - } - - if (overlap) - new_pt.setX(points[i].x()); - - _config->move_point(i, new_pt); - _draw_function = true; - - setCursor(Qt::ClosedHandCursor); - show_tooltip(pix, new_pt); - update(); - } - else if (sz) - { - 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(); - } - } -} - -void spline_widget::mouseReleaseEvent(QMouseEvent *e) -{ - if (!_config || !isEnabled() || !isActiveWindow() || !hasFocus()) - { - clearFocus(); - return; - } - - if (e->button() == Qt::LeftButton) - { - { - if (is_on_pt(e->pos(), nullptr)) - 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(); - } -} - -void spline_widget::reload_spline() -{ - // don't recompute here as the value's about to be recomputed in the callee - update_range(); -} - -int spline_widget::get_closeness_limit() -{ - return std::max(iround(snap_x * c.x()), 1); -} - -void spline_widget::show_tooltip(const QPoint& pos, const QPointF& value_) -{ - const QPointF value = QPoint(0, 0) == value_ ? pixel_coord_to_point(pos) : value_; - - double x = value.x(), y = value.y(); - - 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) - 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: %1x%2").arg(x).arg(y), - this, - rect(), - 0); -} - -bool spline_widget::is_in_bounds(const QPoint& pos) const -{ - static constexpr int grace = point_size * 3; - static constexpr int bottom_grace = int(point_size * 1.5); - return (pos.x() + grace > pixel_bounds.left() && - pos.x() - grace < pixel_bounds.right() && - pos.y() + grace > pixel_bounds.top() && - pos.y() - bottom_grace < pixel_bounds.bottom()); -} - -void spline_widget::update_range() -{ - 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(); - - update(); -} - -bool spline_widget::point_within_pixel(const QPointF& pt, const QPoint &pixel) -{ - const QPointF tmp = pixel - point_to_pixel(pt); - return QPointF::dotProduct(tmp, tmp) < point_size * point_size; -} - -void spline_widget::focusOutEvent(QFocusEvent* e) -{ - if (moving_control_point_idx != -1) - QToolTip::hideText(); - moving_control_point_idx = -1; - _draw_function = true; - lower(); - setCursor(Qt::ArrowCursor); - e->accept(); -} - -QPointF spline_widget::pixel_coord_to_point(const QPoint& point) -{ - qreal x = (point.x() - pixel_bounds.x()) / c.x(); - qreal y = (pixel_bounds.height() - point.y() + pixel_bounds.y()) / c.y(); - - static constexpr int c = 1000; - - if (snap_x > 0) - { - x += snap_x * .5; - x -= std::fmod(x, snap_x); - // truncate after few decimal places to reduce rounding errors. - // round upward to nearest. - 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); -} - -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()); -} - -QPoint spline_widget::point_to_pixel(const QPointF& point) -{ - QPointF pt(point_to_pixel_(point)); - - return QPoint(iround(pt.x()), iround(pt.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->get_points(); - - 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; -} |