diff options
| author | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
| commit | e1bf674c16e3c8472b29574159c789cd3f0c64e0 (patch) | |
| tree | 9f0cfce09c71a2c27ff19589fcad6cd83504477c /tools/CurveEditor/source/Internal/Window | |
| parent | first commit (diff) | |
| download | blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.tar.xz blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.zip | |
Updating to [email protected] and [email protected] with a new directory structure.
NvBlast folder is gone, files have been moved to top level directory. README is changed to reflect this.
Diffstat (limited to 'tools/CurveEditor/source/Internal/Window')
| -rw-r--r-- | tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp | 181 | ||||
| -rw-r--r-- | tools/CurveEditor/source/Internal/Window/AlphaDialog.h | 47 | ||||
| -rw-r--r-- | tools/CurveEditor/source/Internal/Window/ColorWidget.cpp | 1724 | ||||
| -rw-r--r-- | tools/CurveEditor/source/Internal/Window/ColorWidget.h | 126 | ||||
| -rw-r--r-- | tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp | 1530 | ||||
| -rw-r--r-- | tools/CurveEditor/source/Internal/Window/CurveWidget.cpp | 1229 | ||||
| -rw-r--r-- | tools/CurveEditor/source/Internal/Window/CurveWidget.h | 158 |
7 files changed, 4995 insertions, 0 deletions
diff --git a/tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp b/tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp new file mode 100644 index 0000000..a51a802 --- /dev/null +++ b/tools/CurveEditor/source/Internal/Window/AlphaDialog.cpp @@ -0,0 +1,181 @@ +#include "AlphaDialog.h" +#include "ui_AlphaDialog.h" +#include <QtGui/QPaintEvent> +#include <QtGui/QPainter> +#include <QtGui/QPainterPath> + +namespace nvidia { +namespace CurveEditor { + +const int MARGIN_X = 8; +const int MARGIN_Y = 8; + +const int ALPHA_W = 255; +const int ALPHA_H = 30; + +const int CURSOR_W = 12; +const int CURSOR_H = 12; + +static QImage s_triangleUp; + +void InitTriangleResources(int w, int h) +{ + s_triangleUp = QImage(w, h, QImage::Format_ARGB32); + s_triangleUp.fill(QColor(0, 0, 0, 0)); + + // a painter cannot switch device? + QPainterPath path; + QPainter painter(&s_triangleUp); + painter.setRenderHint(QPainter::Antialiasing,true); + path = QPainterPath(); // trick to clear up a path + path.moveTo(w>>1, 0); + path.lineTo(0, h); + path.lineTo(w, h); + path.lineTo(w>>1, 0); + painter.setPen(Qt::NoPen); + painter.fillPath(path, QBrush(QColor(50, 50, 50))); +} + +////////////////////////////////////////////////////////////////////////////// +bool isClickedInCursor(const QPoint& cursorPos, const QPoint& p) +{ + QVector<QPoint> points; + points.push_back(cursorPos); + points.push_back(QPoint(cursorPos.x() - (CURSOR_W>>1), cursorPos.y() + CURSOR_H)); + points.push_back(QPoint(cursorPos.x() + (CURSOR_W>>1), cursorPos.y() + CURSOR_H)); + points.push_back(cursorPos); + + QPolygon polygon(points); + return polygon.containsPoint(p, Qt::OddEvenFill); +} + +////////////////////////////////////////////////////////////////////////////// + int AlphaDialog::getAlpha(int alpha, QWidget *parent) + { + AlphaDialog dlg(parent, alpha); + dlg.exec(); + return dlg._alpha; + } + +////////////////////////////////////////////////////////////////////////////// +AlphaDialog::AlphaDialog(QWidget *parent, int alpha) : + QDialog(parent), + ui(new Ui::AlphaDialog), + _drag(false), + _alpha(alpha), + _xOffset(0) +{ + ui->setupUi(this); + setWindowFlags(windowFlags()&~Qt::WindowContextHelpButtonHint); + setFixedWidth(271); + setFixedHeight(120); + + ui->spinBoxAlpha->setValue(_alpha); + + InitTriangleResources(12, 12); +} + +////////////////////////////////////////////////////////////////////////////// +AlphaDialog::~AlphaDialog() +{ + delete ui; +} + +////////////////////////////////////////////////////////////////////////////// +void AlphaDialog::paintEvent(QPaintEvent * e) +{ + QDialog::paintEvent(e); + + QPainter painter; + painter.begin(this); + drawAlphaRectangle(painter); + drawCursor(painter, _alpha + MARGIN_X); + painter.end(); +} + +////////////////////////////////////////////////////////////////////////////// +void AlphaDialog::mousePressEvent( QMouseEvent* e ) +{ + if(e->button() & Qt::LeftButton) + { + QPoint mousePos = e->pos(); + + if (isClickedInCursor(QPoint(_alpha + MARGIN_X, MARGIN_Y + ALPHA_H), mousePos)) + { + _xOffset = _alpha + MARGIN_X - mousePos.x(); + _drag = true; + } + } +} + +////////////////////////////////////////////////////////////////////////////// +void AlphaDialog::mouseReleaseEvent( QMouseEvent* e ) +{ + _drag = false; + _xOffset = -1; + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void AlphaDialog::mouseMoveEvent( QMouseEvent* e ) +{ + Qt::MouseButtons buttons = e->buttons(); + + if(buttons & Qt::LeftButton) + { + if (_drag) + { + QPoint mousePos = e->pos(); + + _alpha = mousePos.x() + _xOffset - MARGIN_X; + if (_alpha < 0) + { + _alpha = 0; + } + else if(_alpha > ALPHA_W) + { + _alpha = ALPHA_W; + } + ui->spinBoxAlpha->setValue(_alpha); + update(); + } + } +} + +void AlphaDialog::drawAlphaRectangle(QPainter& painter) +{ + QPointF topLeftPnt(MARGIN_X, MARGIN_Y); + QPointF topRightPnt(MARGIN_X + ALPHA_W, MARGIN_Y); + QPointF bottomRightPnt(MARGIN_X + ALPHA_W, MARGIN_Y + ALPHA_H); + QPointF bottomLeftPnt(MARGIN_X, MARGIN_Y + ALPHA_H); + QPainterPath path; + path.moveTo(topLeftPnt); + path.lineTo(topRightPnt); + path.lineTo(bottomRightPnt); + path.lineTo(bottomLeftPnt); + + QColor colorLeft(0, 0, 0, 255); + QColor colorRight(255, 255, 255, 255); + colorLeft.setAlpha(255); + colorRight.setAlpha(255); + QLinearGradient indicatorGradient(topLeftPnt,topRightPnt); + indicatorGradient.setColorAt(0.0, colorLeft); + indicatorGradient.setColorAt(1.0, colorRight); + + painter.fillPath(path, indicatorGradient); +} + +void AlphaDialog::drawCursor(QPainter& painter, int xPos) +{ + QRect rect(xPos - (CURSOR_W>>1), MARGIN_Y + ALPHA_H, CURSOR_W, CURSOR_H); + painter.drawImage(rect, s_triangleUp); + +} + +void AlphaDialog::on_spinBoxAlpha_valueChanged(int arg1) +{ + _alpha = arg1; +} + +} // namespace CurveEditor +} // namespace nvidia
\ No newline at end of file diff --git a/tools/CurveEditor/source/Internal/Window/AlphaDialog.h b/tools/CurveEditor/source/Internal/Window/AlphaDialog.h new file mode 100644 index 0000000..985d0b4 --- /dev/null +++ b/tools/CurveEditor/source/Internal/Window/AlphaDialog.h @@ -0,0 +1,47 @@ +#ifndef ALPHADIALOG_H +#define ALPHADIALOG_H + +#include <QtWidgets/QDialog> + +namespace Ui { + class AlphaDialog; +} + +namespace nvidia { +namespace CurveEditor { + +class AlphaDialog : public QDialog +{ + Q_OBJECT + +public: + static int getAlpha(int alpha = 255, QWidget *parent = 0); + + explicit AlphaDialog(QWidget *parent = 0, int alpha = 255); + ~AlphaDialog(); + +protected: + // QWidget events + virtual void paintEvent(QPaintEvent * e); + + virtual void mousePressEvent(QMouseEvent* e); + virtual void mouseReleaseEvent(QMouseEvent* e); + virtual void mouseMoveEvent(QMouseEvent* e); +private slots: + void on_spinBoxAlpha_valueChanged(int arg1); + +private: + void drawAlphaRectangle(QPainter& painter); + void drawCursor(QPainter& painter, int xPos); + +private: + Ui::AlphaDialog *ui; + bool _drag; + int _alpha; + int _xOffset; +}; + +} // namespace CurveEditor +} // namespace nvidia + +#endif // ALPHADIALOG_H diff --git a/tools/CurveEditor/source/Internal/Window/ColorWidget.cpp b/tools/CurveEditor/source/Internal/Window/ColorWidget.cpp new file mode 100644 index 0000000..a84ee70 --- /dev/null +++ b/tools/CurveEditor/source/Internal/Window/ColorWidget.cpp @@ -0,0 +1,1724 @@ +#include "ColorWidget.h" +#include <QtGui/QPaintEvent> +#include <QtGui/QPainter> +#include <QtGui/QPainterPath> +#include <QtGui/QImage> +#include <assert.h> +#include <QtCore/QDebug> +#include <QtCore/QTime> +#include <QtWidgets/QToolTip> +#include "CurveEditorMainWindow.h" + +namespace nvidia { +namespace CurveEditor { + +const int MARGIN_X = 8; +const int MARGIN_Y = 4; +const int CONTROL_POINT_CURSOR_W = 12; +const int CONTROL_POINT_CURSOR_H = 12; +const int WEIGHT_CURSOR_W = 6; +const int WEIGHT_CURSOR_H = 6; +const int SPACING_V = 0; + +static QImage S_CtrlPntWithTexCursorNormalImg; +static QImage S_CtrlPntWithTexCursorPickedImg; +static QImage S_WeightCursorNormalImg; +static QImage S_WeightCursorPickedImg; + +#define ROUND(v) (int(v + 0.5)) + +class TimeConsumeTracker +{ +public: + TimeConsumeTracker(QString text) + : _text(text) + { + _time.start(); + } + + ~TimeConsumeTracker() + { + qDebug()<<_text<<" consume: "<<_time.elapsed(); + } + + QTime _time; + QString _text; +}; + +////////////////////////////////////////////////////////////////////////////// +void InitCursorResources() +{ + int w = CONTROL_POINT_CURSOR_W; + int h = CONTROL_POINT_CURSOR_H; + S_CtrlPntWithTexCursorNormalImg = QImage(w, h, QImage::Format_ARGB32); + S_CtrlPntWithTexCursorPickedImg = QImage(w, h, QImage::Format_ARGB32); + S_CtrlPntWithTexCursorNormalImg.fill(QColor(0, 0, 0, 0)); + S_CtrlPntWithTexCursorPickedImg.fill(QColor(0, 0, 0, 0)); + + /////////////////////////////////////////////////////////////////////////// + QPainter painter(&S_CtrlPntWithTexCursorNormalImg); + painter.setRenderHint(QPainter::Antialiasing, true); + QPainterPath path; // trick to clear up a path + path.moveTo(w >> 1, 0); + path.lineTo(w >> 2, h >> 2); + path.lineTo(w >> 1, h >> 1); + path.lineTo((w >> 1) + (w >> 2), h >> 2); + path.lineTo(w >> 1, 0); + painter.setPen(Qt::NoPen); + painter.fillPath(path, QBrush(QColor(255, 255, 255))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w >> 2, h >> 2); + path.lineTo(0, h >> 1); + path.lineTo(w >> 2, (h >> 1) + (h >> 2)); + path.lineTo(w >> 1, h >> 1); + path.lineTo(w >> 2, h >> 2); + painter.setPen(Qt::NoPen); + painter.fillPath(path, (QColor(0, 0, 0))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w >> 1, h >> 1); + path.lineTo(w >> 2, (h >> 1) + (h >> 2)); + path.lineTo(w >> 1, h); + path.lineTo((w >> 1) + (w >> 2), (h >> 1) + (h >> 2)); + path.lineTo(w >> 1, h >> 1); + painter.setPen(Qt::NoPen); + painter.fillPath(path, QBrush(QColor(255, 255, 255))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo((w >> 1) + (w >> 2), h >> 2); + path.lineTo(w >> 1, h >> 1); + path.lineTo((w >> 1) + (w >> 2), (h >> 1) + (h >> 2)); + path.lineTo(w, h >> 1); + path.lineTo((w >> 1) + (w >> 2), h >> 2); + painter.setPen(Qt::NoPen); + painter.fillPath(path, (QColor(0, 0, 0))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w >> 1, 0); + path.lineTo(0, h >> 1); + path.lineTo(w >> 1, h); + path.lineTo(w, h >> 1); + path.lineTo(w >> 1, 0); + painter.setPen(QPen(Qt::white, 1, Qt::SolidLine)); + painter.drawPath(path); + + /////////////////////////////////////////////////////////////////////////// + // a painter cannot switch device? + QPainter painter2(&S_CtrlPntWithTexCursorPickedImg); + painter2.setRenderHint(QPainter::Antialiasing,true); + path = QPainterPath(); // trick to clear up a path + path.moveTo(w>>1, 0); + path.lineTo(w>>2, h>>2); + path.lineTo(w>>1, h>>1); + path.lineTo((w>>1)+(w>>2), h>>2); + path.lineTo(w>>1, 0); + painter2.setPen(Qt::NoPen); + painter2.fillPath(path, QBrush(QColor(255, 255, 255))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w>>2, h>>2); + path.lineTo(0, h>>1); + path.lineTo(w>>2, (h>>1)+(h>>2)); + path.lineTo(w>>1, h>>1); + path.lineTo(w>>2, h>>2); + painter2.setPen(Qt::NoPen); + painter2.fillPath(path, (QColor(0, 0, 0))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w>>1, h>>1); + path.lineTo(w>>2, (h>>1)+(h>>2)); + path.lineTo(w>>1, h); + path.lineTo((w>>1)+(w>>2), (h>>1)+(h>>2)); + path.lineTo(w>>1, h>>1); + painter2.setPen(Qt::NoPen); + painter2.fillPath(path, QBrush(QColor(255, 255, 255))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo((w>>1)+(w>>2), h>>2); + path.lineTo(w>>1, h>>1); + path.lineTo((w>>1)+(w>>2), (h>>1)+(h>>2)); + path.lineTo(w, h>>1); + path.lineTo((w>>1)+(w>>2), h>>2); + painter2.setPen(Qt::NoPen); + painter2.fillPath(path, (QColor(0, 0, 0))); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w>>1, 0); + path.lineTo(0, h>>1); + path.lineTo(w>>1, h); + path.lineTo(w, h>>1); + path.lineTo(w>>1, 0); + painter2.setPen(QPen(Qt::green,1, Qt::SolidLine)); + painter2.drawPath(path); + + /////////////////////////////////////////////////////////////////////////// + w = WEIGHT_CURSOR_W; + h = WEIGHT_CURSOR_H; + S_WeightCursorNormalImg = QImage(w, h, QImage::Format_ARGB32); + S_WeightCursorPickedImg = QImage(w, h, QImage::Format_ARGB32); + S_WeightCursorNormalImg.fill(QColor(0, 0, 0, 0)); + S_WeightCursorPickedImg.fill(QColor(0, 0, 0, 0)); + /////////////////////////////////////////////////////////////////////////// + QPainter painter3(&S_WeightCursorNormalImg); + painter3.setRenderHints(QPainter::Antialiasing,true); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w>>1, 0); + path.lineTo(0, h>>1); + path.lineTo(w>>1, h); + path.lineTo(w, h>>1); + path.lineTo(w>>1, 0); + painter3.setPen(QPen(Qt::black, 1, Qt::SolidLine)); + painter3.drawPath(path); + painter3.fillPath(path, QBrush(QColor(255, 255, 255))); + + /////////////////////////////////////////////////////////////////////////// + QPainter painter4(&S_WeightCursorPickedImg); + painter4.setRenderHints(QPainter::Antialiasing,true); + + path = QPainterPath(); // trick to clear up a path + path.moveTo(w>>1, 0); + path.lineTo(0, h>>1); + path.lineTo(w>>1, h); + path.lineTo(w, h>>1); + path.lineTo(w>>1, 0); + painter4.setPen(QPen(Qt::black, 1, Qt::SolidLine)); + painter4.drawPath(path); + painter4.fillPath(path, QBrush(QColor(0, 0, 0))); +} + +////////////////////////////////////////////////////////////////////////////// +float NDCToScreenCoord(QWidget* pWidget, float xValueOfUnitInterval) +{ + int w = pWidget->width(); + return MARGIN_X + (w - MARGIN_X * 2.0) * xValueOfUnitInterval; +} + +////////////////////////////////////////////////////////////////////////////// +float _screenToNDC(QWidget* pWidget, int xPos) +{ + int w = pWidget->width(); + return ((float)(xPos - MARGIN_X)) / (w - MARGIN_X * 2.0f); +} + +////////////////////////////////////////////////////////////////////////////// +bool isClickedInCtrlPntCursor(const QPointF& cursorPos, const QPointF& p) +{ + QVector<QPointF> points; + points.push_back(cursorPos); + points.push_back(QPointF(cursorPos.x() - CONTROL_POINT_CURSOR_W/2, cursorPos.y() + CONTROL_POINT_CURSOR_H/2)); + points.push_back(QPointF(cursorPos.x(), cursorPos.y() + CONTROL_POINT_CURSOR_H)); + points.push_back(QPointF(cursorPos.x() + CONTROL_POINT_CURSOR_W/2, cursorPos.y() + CONTROL_POINT_CURSOR_H/2)); + points.push_back(cursorPos); + QPolygonF polygon(points); + return polygon.containsPoint(p, Qt::OddEvenFill); +} + +////////////////////////////////////////////////////////////////////////////// +bool isClickedInWeightCursor(const QPointF& cursorPos, const QPointF& p) +{ + QVector<QPointF> points; + points.push_back(cursorPos); + points.push_back(QPointF(cursorPos.x() - WEIGHT_CURSOR_W/2, cursorPos.y() + WEIGHT_CURSOR_H/2)); + points.push_back(QPointF(cursorPos.x(), cursorPos.y() + WEIGHT_CURSOR_H)); + points.push_back(QPointF(cursorPos.x() + WEIGHT_CURSOR_W/2, cursorPos.y() + WEIGHT_CURSOR_H/2)); + points.push_back(cursorPos); + QPolygonF polygon(points); + return polygon.containsPoint(p, Qt::OddEvenFill); +} + +////////////////////////////////////////////////////////////////////////////// +QImage genControlPointCursorImg(const QColor& color, bool picked = false) +{ + int w = CONTROL_POINT_CURSOR_W; + int h = CONTROL_POINT_CURSOR_H; + QImage image = QImage(w, h, QImage::Format_ARGB32); + image.fill(QColor(0, 0, 0, 0)); + + QPainter painter(&image); + painter.setRenderHints(QPainter::Antialiasing,true); + + QPainterPath path; + path.moveTo(w>>1, 0); + path.lineTo(0, h>>1); + path.lineTo(w>>1, h); + path.lineTo(w, h>>1); + path.lineTo(w>>1, 0); + if (picked) + { + painter.setPen(QPen(Qt::green, 1, Qt::SolidLine)); + painter.drawPath(path); + } + + painter.fillPath(path, QBrush(color)); + + return image; +} + +////////////////////////////////////////////////////////////////////////////// +ColorWidget::ColorWidget(QWidget *parent) : + QFrame(parent), + _isLink(false), + _colorAttribute(nullptr), + _colorCurve(nullptr), + _alphaCurve(nullptr), + _canAddRemoveControlPoint(false), + _canAddCtrlPntByClick(false), + _canRemoveCtrlPntByClick(false), + _curveFitWindowScale(1), + _curveFitWindowOffset(0), + _pickedColorCtrlPnt(-1), + _pickedAlphaCtrlPnt(-1), + _pickedColorWeight(-1), + _pickedAlphaWeight(-1), + _dragColorCtrlPnt(false), + _dragAlphaCtrlPnt(false), + _dragColorWeight(false), + _dragAlphaWeight(false), + _colorCtrlPntToRemove(-1), + _alphaCtrlPntToRemove(-1), + _contextMenu(nullptr), + _removeCtrlPntAction(nullptr) +{ + setFocusPolicy(Qt::ClickFocus ); + + InitCursorResources(); + + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onShowContextMenu(const QPoint&))); + + _contextMenu = new QMenu(this);; + _removeCtrlPntAction = new QAction(this); + _removeCtrlPntAction->setText(tr("Remove Control Point")); + _contextMenu->addAction(_removeCtrlPntAction); + + connect(_removeCtrlPntAction, SIGNAL(triggered()), this, SLOT(onRemoveControlPoint()) ); +} + +////////////////////////////////////////////////////////////////////////////// +QColor ColorWidget::getColor() +{ + QColor color; + if (_pickedColorCtrlPnt != -1) + { + color = _colorCurve->getControlPoint(_pickedColorCtrlPnt).color; + } + return color; +} + +////////////////////////////////////////////////////////////////////////////// +int ColorWidget::getAlpha() +{ + if (_pickedAlphaCtrlPnt != -1) + { + if (_isLink) + { + return _colorCurve->getControlPoint(_pickedAlphaCtrlPnt).color.alpha(); + } + else + { + return _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt).color.alpha(); + } + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setColor(const QColor& color) +{ + if (_pickedColorCtrlPnt != -1) + { + ColorControlPoint pickedColorPnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + + pickedColorPnt.color.setRed(color.red()); + pickedColorPnt.color.setGreen(color.green()); + pickedColorPnt.color.setBlue(color.blue()); + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pickedColorPnt); + + emit ColorAttributeChanged(_colorAttribute); + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setAlpha(int alpha) +{ + if (_pickedColorCtrlPnt != -1) + { + ColorControlPoint pickedColorPnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pickedColorPnt.color.setAlpha(alpha); + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pickedColorPnt); + + emit ColorAttributeChanged(_colorAttribute); + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +float ColorWidget::getColorFallOff() +{ + if (_colorCurve && -1 != _pickedColorCtrlPnt) + { + const ColorControlPoint& pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + return pnt.fallOff; + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setColorFallOff(float fallOff) +{ + if (_colorCurve && -1 != _pickedColorCtrlPnt) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.fallOff = fallOff; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +float ColorWidget::getAlphaFallOff() +{ + if (_isLink) + { + if (_colorCurve && -1 != _pickedColorCtrlPnt) + { + const ColorControlPoint& pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + return pnt.fallOff; + } + } + else + { + if (_alphaCurve && -1 != _pickedAlphaCtrlPnt) + { + const ColorControlPoint& pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + return pnt.fallOff; + } + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setAlphaFallOff(float fallOff) +{ + if (_isLink) + { + if (_colorCurve && -1 != _pickedColorCtrlPnt) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.fallOff = fallOff; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + update(); + } + } + else + { + if (_alphaCurve && -1 != _pickedAlphaCtrlPnt) + { + ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + pnt.fallOff = fallOff; + _alphaCurve->setControlPoint(_pickedAlphaCtrlPnt, pnt); + + emit ColorAttributeChanged(_colorAttribute); + update(); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setColorAttribute(ColorAttribute* colorAttribute) +{ + _colorAttribute = colorAttribute; + if (colorAttribute != nullptr) + { + _colorCurve = &(colorAttribute->colorCurve); + _alphaCurve = &(colorAttribute->alphaCurve); + } + else + { + _colorCurve = nullptr; + _alphaCurve = nullptr; + } + + if (_alphaCurve !=nullptr && _alphaCurve->getControlPointCount() < 2) + { + _isLink = true; + } + else + { + _isLink = false; + } + + _pickedColorCtrlPnt = -1; + _pickedAlphaCtrlPnt = -1; + _pickedColorWeight = -1; + _pickedAlphaWeight = -1; + _dragColorCtrlPnt = false; + _dragAlphaCtrlPnt = false; + _dragColorWeight = false; + _dragAlphaWeight = false; + + _updateCurveFitWindowPara(); + if (_colorCurve) + _colorCurve->_needSample = true; + if (_alphaCurve) + _alphaCurve->_needSample = true; + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::reset() +{ + if (_colorAttribute) + { + _colorAttribute->colorCurve.reset(); + _colorAttribute->alphaCurve.reset(); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::addControlPointsBeforeSelected() +{ + if (-1 != _pickedColorCtrlPnt) + { + if (_pickedColorCtrlPnt == 0) + return; + + _colorCurve->insertControlPointAt(_pickedColorCtrlPnt); + ++_pickedColorCtrlPnt; + } + else if (-1 != _pickedAlphaCtrlPnt) + { + if (_pickedAlphaCtrlPnt == 0) + return; + + _alphaCurve->insertControlPointAt(_pickedAlphaCtrlPnt); + ++_pickedAlphaCtrlPnt; + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::addControlPointsAfterSelected() +{ + if (-1 != _pickedColorCtrlPnt ) + { + _colorCurve->insertControlPointAt(_pickedColorCtrlPnt + 1); + } + else if (-1 != _pickedAlphaCtrlPnt) + { + _alphaCurve->insertControlPointAt(_pickedAlphaCtrlPnt + 1); + } + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::removeSelectedControlPoint() +{ + if (-1 != _pickedColorCtrlPnt) + { + _colorCurve->removeControlPoint(_pickedColorCtrlPnt); + _pickedColorCtrlPnt = -1; + } + else if (-1 != _pickedAlphaCtrlPnt) + { + _alphaCurve->removeControlPoint(_pickedAlphaCtrlPnt); + _pickedAlphaCtrlPnt = -1; + } + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setTangentType(InterpolateMode mode) +{ + if (-1 != _pickedColorCtrlPnt) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.mode = mode; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + } + else if (-1 != _pickedAlphaCtrlPnt) + { + ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.mode = mode; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setSmoothTangent() +{ + if (-1 != _pickedColorCtrlPnt && _pickedColorCtrlPnt < (_colorCurve->getControlPointCount() - 1) ) + { + ColorControlPoint ctrlctrlPntFront = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 1.0; + ctrlctrlPntFront.splineData.outTan = 0; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront); + + ColorControlPoint ctrlPntBehiand = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 1.0; + ctrlPntBehiand.splineData.inTan = 0.0; + _colorCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand); + + emit ColorAttributeChanged(_colorAttribute); + } + else if (-1 != _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (_alphaCurve->getControlPointCount() - 1) ) + { + ColorControlPoint ctrlctrlPntFront = _alphaCurve->getControlPoint(_pickedColorCtrlPnt); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 1.0; + ctrlctrlPntFront.splineData.outTan = 0; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront); + + ColorControlPoint ctrlPntBehiand = _alphaCurve->getControlPoint(_pickedColorCtrlPnt + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 1.0; + ctrlPntBehiand.splineData.inTan = 0.0; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setEaseInTangent() +{ + if (-1 != _pickedColorCtrlPnt && _pickedColorCtrlPnt < (_colorCurve->getControlPointCount() - 1) ) + { + ColorControlPoint ctrlctrlPntFront = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 0.0; + ctrlctrlPntFront.splineData.outTan = 0; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront); + + ColorControlPoint ctrlPntBehiand = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 1.0; + ctrlPntBehiand.splineData.inTan = 0; + _colorCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand); + + emit ColorAttributeChanged(_colorAttribute); + } + else if (-1 != _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (_alphaCurve->getControlPointCount() - 1) ) + { + ColorControlPoint ctrlctrlPntFront = _alphaCurve->getControlPoint(_pickedColorCtrlPnt); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 0.0; + ctrlctrlPntFront.splineData.outTan = 0; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront); + + ColorControlPoint ctrlPntBehiand = _alphaCurve->getControlPoint(_pickedColorCtrlPnt + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 1.0; + ctrlPntBehiand.splineData.inTan = 0; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setEaseOutTangent() +{ + if (-1 != _pickedColorCtrlPnt && _pickedColorCtrlPnt < (_colorCurve->getControlPointCount() - 1) ) + { + ColorControlPoint ctrlctrlPntFront = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 1.0; + ctrlctrlPntFront.splineData.outTan = 0; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront); + + ColorControlPoint ctrlPntBehiand = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 0.0; + ctrlPntBehiand.splineData.inTan = 0; + _colorCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand); + + emit ColorAttributeChanged(_colorAttribute); + } + else if (-1 != _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (_alphaCurve->getControlPointCount() - 1) ) + { + ColorControlPoint ctrlctrlPntFront = _alphaCurve->getControlPoint(_pickedColorCtrlPnt); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 1.0; + ctrlctrlPntFront.splineData.outTan = 0; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt, ctrlctrlPntFront); + + ColorControlPoint ctrlPntBehiand = _alphaCurve->getControlPoint(_pickedColorCtrlPnt + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 0.0; + ctrlPntBehiand.splineData.inTan = 0; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt + 1, ctrlPntBehiand); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +QString ColorWidget::getColorTex() +{ + if (-1 != _pickedColorCtrlPnt) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + return pnt.texturePath.c_str(); + } + return ""; +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setColorTex(const QString& strPath) +{ + if (-1 != _pickedColorCtrlPnt) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.texturePath = strPath.toStdString(); + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::reloadColorTex() +{ + if (-1 != _pickedColorCtrlPnt) + { + emit ReloadColorAttributeTexture(_colorAttribute, true, _pickedColorCtrlPnt); + } +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::clearColorTex() +{ + if (-1 != _pickedColorCtrlPnt) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.texturePath = ""; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +QString ColorWidget::getAlphaTex() +{ + if (-1 != _pickedColorCtrlPnt && _isLink) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + return pnt.texturePath.c_str(); + } + else if (-1 != _pickedAlphaCtrlPnt) + { + ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + return pnt.texturePath.c_str(); + } + + return ""; +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setAlphaTex(const QString& strPath) +{ + if (-1 != _pickedColorCtrlPnt && _isLink) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.texturePath = strPath.toStdString(); + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + } + else if (-1 != _pickedAlphaCtrlPnt) + { + ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + pnt.texturePath = strPath.toStdString(); + _alphaCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::reloadAlphaTex() +{ + if (-1 != _pickedColorCtrlPnt && _isLink) + { + emit ReloadColorAttributeTexture(_colorAttribute, false, _pickedColorCtrlPnt); + } + else if (-1 != _pickedAlphaCtrlPnt) + { + emit ReloadColorAttributeTexture(_colorAttribute, false, _pickedAlphaCtrlPnt); + } +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::clearAlphaTex() +{ + if (-1 != _pickedColorCtrlPnt && _isLink) + { + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.texturePath = ""; + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + } + else if (-1 != _pickedAlphaCtrlPnt) + { + ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + pnt.texturePath = ""; + _alphaCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + emit ColorAttributeChanged(_colorAttribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::setUseAlphaFromColor(bool val) +{ + if (_colorAttribute && _colorAttribute->useAlphaFromColor != val) + { + _colorAttribute->useAlphaFromColor = val; + emit ColorAttributeChanged(_colorAttribute); + } + +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::onShowContextMenu(const QPoint& pos) +{ + _colorCtrlPntToRemove = _checkColorCtrlPntCursorSelected(pos); + _alphaCtrlPntToRemove = _checkAlphaCtrlPntCursorSelected(pos); + + if ( !_canAddRemoveControlPoint + || (-1 == _colorCtrlPntToRemove && -1 == _alphaCtrlPntToRemove) + || 2 == _colorCurve->_controlPoints.size() && -1 != _colorCtrlPntToRemove + || 2 == _alphaCurve->_controlPoints.size() && -1 != _alphaCtrlPntToRemove) + { + _removeCtrlPntAction->setEnabled(false); + } + else + { + _removeCtrlPntAction->setEnabled(true); + } + _contextMenu->exec(QCursor::pos()); +} + +void ColorWidget::onRemoveControlPoint() +{ + if (-1 != _colorCtrlPntToRemove) + { + _colorCurve->removeControlPoint(_colorCtrlPntToRemove); + + if (_colorCtrlPntToRemove == _pickedColorCtrlPnt) + { + if (_isLink) + { + _colorCtrlPntToRemove = -1; + _pickedColorCtrlPnt = -1; + _pickedAlphaCtrlPnt = -1; + } + else + { + _colorCtrlPntToRemove = -1; + _pickedColorCtrlPnt = -1; + } + } + + _colorCurve->_needSample = true; + emit ColorAttributeChanged(_colorAttribute); + update(); + } + else if (-1 != _alphaCtrlPntToRemove && _isLink) + { + _colorCurve->removeControlPoint(_alphaCtrlPntToRemove); + + if (_alphaCtrlPntToRemove == _pickedAlphaCtrlPnt) + { + _alphaCtrlPntToRemove = -1; + _pickedColorCtrlPnt = -1; + _pickedAlphaCtrlPnt = -1; + } + + _colorCurve->_needSample = true; + emit ColorAttributeChanged(_colorAttribute); + update(); + } + else if (-1 != _alphaCtrlPntToRemove && !_isLink) + { + _alphaCurve->removeControlPoint(_alphaCtrlPntToRemove); + + if (_alphaCtrlPntToRemove == _pickedAlphaCtrlPnt) + { + _colorCtrlPntToRemove = -1; + _pickedColorCtrlPnt = -1; + } + + _alphaCurve->_needSample = true; + emit ColorAttributeChanged(_colorAttribute); + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +bool ColorWidget::event(QEvent *event) +{ + if (event->type() == QEvent::ToolTip) { + QHelpEvent* helpEvent = static_cast<QHelpEvent*>(event); + QPoint mousePos = helpEvent->pos(); + + QPointF mousePosF(mousePos.x(), mousePos.y()); + int pickedColorCtrlPnt = _checkColorCtrlPntCursorSelected(mousePosF); + int pickedAlphaCtrlPnt = _checkAlphaCtrlPntCursorSelected(mousePosF); + + if (-1 != pickedColorCtrlPnt) + { + const std::string& tex = _colorCurve->getControlPoint(pickedColorCtrlPnt).texturePath; + if (!tex.empty()) + QToolTip::showText(helpEvent->globalPos(), tex.c_str()); + + } + else if (-1 != pickedAlphaCtrlPnt) + { + if (_isLink) + { + const std::string& tex = _colorCurve->getControlPoint(pickedAlphaCtrlPnt).texturePath; + if (!tex.empty()) + QToolTip::showText(helpEvent->globalPos(), tex.c_str()); + } + else + { + const std::string& tex = _alphaCurve->getControlPoint(pickedAlphaCtrlPnt).texturePath; + if (!tex.empty()) + QToolTip::showText(helpEvent->globalPos(), tex.c_str()); + } + } + else + { + QToolTip::hideText(); + event->ignore(); + } + + return true; + } + return QWidget::event(event); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::paintEvent(QPaintEvent * e) +{ + //TimeConsumeTracker t("update"); + QFrame::paintEvent(e); + + QPainter painter; + painter.begin(this); + painter.setRenderHints(QPainter::Antialiasing, true); + + if (_colorCurve) + { + _drawRampArea(painter); + _drawCtrlPntCursors(painter); + _drawWeightCursors(painter); + } + painter.end(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::resizeEvent(QResizeEvent* e) +{ + if (_colorCurve) + _updateCurveFitWindowPara(); + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::mousePressEvent( QMouseEvent* e ) +{ + if(_colorCurve && e->button() & Qt::LeftButton) + { + QPoint mousePos = e->pos(); + QPointF mousePosF(mousePos.x(), mousePos.y()); + int pickedColorCtrlPnt = _checkColorCtrlPntCursorSelected(mousePosF); + int pickedAlphaCtrlPnt = _checkAlphaCtrlPntCursorSelected(mousePosF); + + if (-1 != pickedColorCtrlPnt || -1 != pickedAlphaCtrlPnt) + { + if (_canAddRemoveControlPoint && _canRemoveCtrlPntByClick) + { + if (-1 != pickedColorCtrlPnt) + { + _colorCurve->removeControlPoint(pickedColorCtrlPnt); + _pickedColorCtrlPnt = -1; + } + + if (-1 != pickedAlphaCtrlPnt) + { + if (_isLink) + { + _colorCurve->removeControlPoint(pickedAlphaCtrlPnt); + _pickedColorCtrlPnt = -1; + pickedAlphaCtrlPnt = -1; + } + else + { + _alphaCurve->removeControlPoint(pickedAlphaCtrlPnt); + pickedAlphaCtrlPnt = -1; + } + } + return; + } + + _pickedColorCtrlPnt = pickedColorCtrlPnt; + _pickedAlphaCtrlPnt = pickedAlphaCtrlPnt; + + if (-1 < _pickedColorCtrlPnt) + _dragColorCtrlPnt = true; + + if (-1 < _pickedAlphaCtrlPnt) + _dragAlphaCtrlPnt = true; + + if (_isLink) + { + if (-1 != pickedColorCtrlPnt) + { + _pickedAlphaCtrlPnt = _pickedColorCtrlPnt; + _dragAlphaCtrlPnt = _dragColorCtrlPnt; + } + + if (-1 != pickedAlphaCtrlPnt) + { + _pickedColorCtrlPnt = _pickedAlphaCtrlPnt; + _dragColorCtrlPnt = _dragAlphaCtrlPnt; + } + PickedControlPointChanged(true); + } + else + { + if (-1 != pickedColorCtrlPnt) + { + PickedControlPointChanged(true); + } + + if (-1 != pickedAlphaCtrlPnt) + { + PickedControlPointChanged(false); + } + } + + + } + else + { + int pickedColorWeight = _checkColorWeightCursorSelected(mousePosF); + int pickedAlphaWeight = _checkAlphaWeightCursorSelected(mousePosF); + + if (-1 != pickedColorWeight || -1 != pickedAlphaWeight) + { + _pickedColorWeight = pickedColorWeight; + _pickedAlphaWeight = pickedAlphaWeight; + + if (-1 < _pickedColorWeight) + _dragColorWeight = true; + + if (-1 < _pickedAlphaCtrlPnt) + _dragAlphaWeight = true; + + if (_isLink) + { + if (-1 != _pickedColorWeight) + { + _pickedAlphaWeight = _pickedColorWeight; + _dragAlphaWeight = _dragColorWeight; + } + + if (-1 != _pickedAlphaWeight) + { + _pickedColorWeight = _pickedAlphaWeight; + _dragColorWeight = _dragAlphaWeight; + } + } + } + else + { + if (_canAddRemoveControlPoint && _canAddCtrlPntByClick) + { + int yMiddle = height() / 2; + if (mousePos.y() <= yMiddle) + { + _addColorControlPoint(mousePos.x()); + PickedControlPointChanged(true); + } + else if (mousePos.y() > yMiddle) + { + if (_isLink) + { + _addColorControlPoint(mousePos.x()); + PickedControlPointChanged(true); + } + else + { + _addAlphaControlPoint(mousePos.x()); + PickedControlPointChanged(false); + } + } + } + } + } + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::mouseReleaseEvent( QMouseEvent* /*e*/ ) +{ + _dragColorCtrlPnt = false; + _dragAlphaCtrlPnt = false; + _dragColorWeight = false; + _dragAlphaWeight = false; + _pickedColorWeight = -1; + _pickedAlphaWeight = -1; + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::mouseMoveEvent( QMouseEvent* e ) +{ + Qt::MouseButtons buttons = e->buttons(); + + if(_colorCurve && buttons & Qt::LeftButton) + { + if (_dragColorCtrlPnt) + { + if (!_colorAttribute->canMoveControlPointHorizontally()) + return; + + QPoint mousePos = e->pos(); + ColorControlPoint pnt = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + pnt.x = _screenToValue(mousePos.x()); + + //make control point move in value range + if (pnt.x < _colorCurve->getMinValue()) + pnt.x = _colorCurve->getMinValue(); + else if (pnt.x > _colorCurve->getMaxValue()) + pnt.x = _colorCurve->getMaxValue(); + + _colorCurve->setControlPoint(_pickedColorCtrlPnt, pnt); + _colorCurve->_reOrderControlPoints(_pickedColorCtrlPnt); + emit ColorAttributeChanged(_colorAttribute); + } + + if (_dragColorWeight) + { + QPoint mousePos = e->pos(); + ColorControlPoint pnt0 = _colorCurve->getControlPoint(_pickedColorWeight); + ColorControlPoint pnt1 = _colorCurve->getControlPoint(_pickedColorWeight + 1); + int xPnt0Screen = _valueToScreen(pnt0.x); + int xPnt1Screen = _valueToScreen(pnt1.x); + if (mousePos.x() < (xPnt0Screen + WEIGHT_CURSOR_W)) + mousePos.setX(xPnt0Screen + WEIGHT_CURSOR_W); + if (mousePos.x() > (xPnt1Screen - WEIGHT_CURSOR_W)) + mousePos.setX(xPnt1Screen - WEIGHT_CURSOR_W); + pnt0.weight = ((float)(mousePos.x() - xPnt0Screen))/(xPnt1Screen - xPnt0Screen); + _colorCurve->setControlPoint(_pickedColorWeight, pnt0); + emit ColorAttributeChanged(_colorAttribute); + } + + if (!_isLink) + { + if (_dragAlphaCtrlPnt) + { + if (!_colorAttribute->canMoveControlPointHorizontally()) + return; + + QPoint mousePos = e->pos(); + ColorControlPoint pnt = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + pnt.x = _screenToValue(mousePos.x()); + + //make control point move in value range + if (pnt.x < _alphaCurve->getMinValue()) + pnt.x = _alphaCurve->getMinValue(); + else if (pnt.x > _alphaCurve->getMaxValue()) + pnt.x = _alphaCurve->getMaxValue(); + + _alphaCurve->setControlPoint(_pickedAlphaCtrlPnt, pnt); + _alphaCurve->_reOrderControlPoints(_pickedAlphaCtrlPnt); + _alphaCurve->_needSample = true; + emit ColorAttributeChanged(_colorAttribute); + } + + if (_dragAlphaWeight) + { + QPoint mousePos = e->pos(); + ColorControlPoint pnt0 = _alphaCurve->getControlPoint(_pickedAlphaWeight); + ColorControlPoint pnt1 = _alphaCurve->getControlPoint(_pickedAlphaWeight + 1); + int xPnt0Screen = _valueToScreen(pnt0.x); + int xPnt1Screen = _valueToScreen(pnt1.x); + if (mousePos.x() < (xPnt0Screen + WEIGHT_CURSOR_W)) + mousePos.setX(xPnt0Screen + WEIGHT_CURSOR_W); + if (mousePos.x() > (xPnt1Screen - WEIGHT_CURSOR_W)) + mousePos.setX(xPnt1Screen - WEIGHT_CURSOR_W); + pnt0.weight = ((float)(mousePos.x() - xPnt0Screen))/(xPnt1Screen - xPnt0Screen); + _alphaCurve->setControlPoint(_pickedAlphaWeight, pnt0); + emit ColorAttributeChanged(_colorAttribute); + } + } + + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::_updateCurveFitWindowPara() +{ + int widgetWidth = width(); + + if (_colorCurve && _colorCurve->getControlPointCount() > 1) + { + float minX = _colorCurve->getMinValue(); + float maxX = _colorCurve->getMaxValue(); + + if (!_isLink) + { + if (minX < _alphaCurve->getMinValue()) + minX = _alphaCurve->getMinValue(); + + if (maxX < _alphaCurve->getMaxValue()) + maxX = _alphaCurve->getMaxValue(); + } + + float curveWidth = maxX - minX; + + if (0 == curveWidth) + { + curveWidth = 1.0; + } + + _curveFitWindowScale = (widgetWidth - MARGIN_X * 2) / curveWidth; + _curveFitWindowOffset = MARGIN_X - minX * _curveFitWindowScale; + } +} + +////////////////////////////////////////////////////////////////////////////// +float ColorWidget::_valueToScreen(float x) +{ + return ROUND(_curveFitWindowScale * x + _curveFitWindowOffset); +} + +////////////////////////////////////////////////////////////////////////////// +float ColorWidget::_screenToValue(float x) +{ + return (x - _curveFitWindowOffset) / _curveFitWindowScale; +} + +////////////////////////////////////////////////////////////////////////////// +void ColorWidget::_fillRampImage(QImage& colorImg, QImage& alphaImg) +{ + assert(colorImg.width() == alphaImg.width()); + assert(colorImg.height() == alphaImg.height()); + + int width = colorImg.width(); + int height = colorImg.height(); + + QRgb *colorPixels = nullptr; + QRgb *alphaPixels = nullptr; + { + colorPixels = new QRgb[width]; + //TimeConsumeTracker t("calcuate one line colorPixels"); + for (int i = 0; i < width; ++i) + { + colorPixels[i] = _colorCurve->getColorByX(_screenToValue(i + MARGIN_X)).rgba(); + } + + if (!_isLink) + { + alphaPixels = new QRgb[width]; + //TimeConsumeTracker t("calcuate one line alphaPixels"); + for (int i = 0; i < width; ++i) + { + alphaPixels[i] = _alphaCurve->getColorByX(_screenToValue(i + MARGIN_X)).rgba(); + } + } + } + + { + //TimeConsumeTracker tt("fill images' pixel"); + for (int m = 0; m < height; ++m) + { + void* bytesPerLine = const_cast<uchar*>(colorImg.scanLine(m)); + memcpy(bytesPerLine, colorPixels, sizeof(QRgb) * width); + + bytesPerLine = const_cast<uchar*>(alphaImg.scanLine(m)); + if (nullptr == alphaPixels) + memcpy(bytesPerLine, colorPixels, sizeof(QRgb) * width); + else + memcpy(bytesPerLine, alphaPixels, sizeof(QRgb) * width); + } + } + + delete[] colorPixels; +} + +void ColorWidget::_drawRampArea(QPainter& painter) +{ + QImage colorImg(width() - MARGIN_X * 2, (height() - SPACING_V - CONTROL_POINT_CURSOR_H * 2 - MARGIN_Y * 2) / 2, QImage::Format_RGB32); + QImage alphaImg(width() - MARGIN_X * 2, (height() - SPACING_V - CONTROL_POINT_CURSOR_H * 2 - MARGIN_Y * 2) / 2, QImage::Format_RGB32); + _fillRampImage(colorImg, alphaImg); + painter.drawImage(MARGIN_X, MARGIN_Y + CONTROL_POINT_CURSOR_H, colorImg); + painter.drawImage(MARGIN_X, MARGIN_Y + CONTROL_POINT_CURSOR_H + (height() - SPACING_V - CONTROL_POINT_CURSOR_H * 2 - MARGIN_Y * 2) / 2, alphaImg); +} + +void ColorWidget::_drawCtrlPntCursors(QPainter& painter) +{ + int colorCtrlPntCount = _colorCurve->getControlPointCount(); + + for (int i = 0; i < colorCtrlPntCount; ++i) + { + const ColorControlPoint& pnt = _colorCurve->getControlPoint(i); + + float xPosCtrlPnt = ROUND(_valueToScreen(pnt.x)); + float yColorCtrlPnt = MARGIN_Y; + float yAlphaCtrlPnt = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + + QRect rcColorCtrnPntCursor(xPosCtrlPnt - CONTROL_POINT_CURSOR_W / 2, yColorCtrlPnt, CONTROL_POINT_CURSOR_W, CONTROL_POINT_CURSOR_H); + QRect rcAlphaCtrnPntCursor(xPosCtrlPnt - CONTROL_POINT_CURSOR_W / 2, yAlphaCtrlPnt, CONTROL_POINT_CURSOR_W, CONTROL_POINT_CURSOR_H); + if (i == _pickedColorCtrlPnt) + { + if (pnt.texturePath.empty()) + painter.drawImage(rcColorCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.red(), pnt.color.green(), pnt.color.blue(), 255), true)); + else + painter.drawImage(rcColorCtrnPntCursor, S_CtrlPntWithTexCursorPickedImg); + + if (_isLink) + { + if (pnt.texturePath.empty()) + painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha()), true)); + else + painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorPickedImg); + } + } + else + { + if (pnt.texturePath.empty()) + painter.drawImage(rcColorCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.red(), pnt.color.green(), pnt.color.blue(), 255))); + else + painter.drawImage(rcColorCtrnPntCursor, S_CtrlPntWithTexCursorNormalImg); + + if (_isLink) + { + if (pnt.texturePath.empty()) + painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha()))); + else + painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorNormalImg); + } + + } + } + + if (!_isLink) + { + int alphaCtrlPntCount = _alphaCurve->getControlPointCount(); + + for (int i = 0; i < alphaCtrlPntCount; ++i) + { + const ColorControlPoint& pnt = _alphaCurve->getControlPoint(i); + + float xPosCtrlPnt = ROUND(_valueToScreen(pnt.x)); + float yAlphaCtrlPnt = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + + QRect rcAlphaCtrnPntCursor(xPosCtrlPnt - CONTROL_POINT_CURSOR_W / 2, yAlphaCtrlPnt, CONTROL_POINT_CURSOR_W, CONTROL_POINT_CURSOR_H); + + if (i == _pickedAlphaCtrlPnt) + { + if (pnt.texturePath.empty()) + painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha()), true)); + else + painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorPickedImg); + } + else + { + if (pnt.texturePath.empty()) + painter.drawImage(rcAlphaCtrnPntCursor, genControlPointCursorImg(QColor(pnt.color.alpha(), pnt.color.alpha(), pnt.color.alpha()) )); + else + painter.drawImage(rcAlphaCtrnPntCursor, S_CtrlPntWithTexCursorNormalImg); + } + } + } +} + +void ColorWidget::_drawWeightCursors(QPainter& painter) +{ + float yColorWeight = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H; + + int colorCtrlPntCount = _colorCurve->getControlPointCount(); + if (0 == _pickedColorCtrlPnt) + { + const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1); + + _drawColorWeightCursor(painter, pnt0, pnt1, _pickedColorCtrlPnt == _pickedColorWeight); + } + else if ((colorCtrlPntCount - 1) == _pickedColorCtrlPnt) + { + const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(_pickedColorCtrlPnt - 1); + const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + + _drawColorWeightCursor(painter, pnt0, pnt1, (_pickedColorCtrlPnt - 1) == _pickedColorWeight); + } + else if (0 < _pickedColorCtrlPnt && _pickedColorCtrlPnt < (colorCtrlPntCount - 1)) + { + const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(_pickedColorCtrlPnt - 1); + const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(_pickedColorCtrlPnt); + const ColorControlPoint& pnt2 = _colorCurve->getControlPoint(_pickedColorCtrlPnt + 1); + + _drawColorWeightCursor(painter, pnt0, pnt1, (_pickedColorCtrlPnt - 1) == _pickedColorWeight); + _drawColorWeightCursor(painter, pnt1, pnt2, _pickedColorCtrlPnt == _pickedColorWeight); + } + + if (!_isLink) + { + float yAlphaWeight = height() - SPACING_V - WEIGHT_CURSOR_H - MARGIN_Y; + int alphaCtrlPntCount = _alphaCurve->getControlPointCount(); + if (0 == _pickedAlphaCtrlPnt) + { + const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt + 1); + + _drawAlphaWeightCursor(painter, pnt0, pnt1, _pickedAlphaCtrlPnt == _pickedAlphaWeight); + } + else if ((alphaCtrlPntCount - 1) == _pickedAlphaCtrlPnt) + { + const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt - 1); + const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + + _drawAlphaWeightCursor(painter, pnt0, pnt1, (_pickedAlphaCtrlPnt - 1) == _pickedAlphaWeight); + } + else if (0 < _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (alphaCtrlPntCount - 1)) + { + const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt - 1); + const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt); + const ColorControlPoint& pnt2 = _alphaCurve->getControlPoint(_pickedAlphaCtrlPnt + 1); + + _drawAlphaWeightCursor(painter, pnt0, pnt1, (_pickedAlphaCtrlPnt - 1) == _pickedAlphaWeight); + _drawAlphaWeightCursor(painter, pnt1, pnt2, _pickedAlphaCtrlPnt == _pickedAlphaWeight); + } + } +} + +void ColorWidget::_drawColorWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked) +{ + if (pnt0.mode != eLinear) + return ; + + float yColorWeight = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H; + float yAlphaWeight = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + + float xPosWeightCursor = ROUND(_valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x))); + QRect rcColorWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yColorWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H); + QRect rcAlphaWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yAlphaWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H); + + painter.drawImage(rcColorWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg); + + if (_isLink) + painter.drawImage(rcAlphaWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg); +} + +void ColorWidget::_drawAlphaWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked) +{ + if (pnt0.mode != eLinear) + return ; + + float yColorWeight = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H; + float yAlphaWeight = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + + float xPosWeightCursor = ROUND(_valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x))); + QRect rcColorWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yColorWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H); + QRect rcAlphaWeightCursor(xPosWeightCursor - WEIGHT_CURSOR_W / 2, yAlphaWeight, WEIGHT_CURSOR_W, WEIGHT_CURSOR_H); + + painter.drawImage(rcAlphaWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg); + + if (_isLink) + painter.drawImage(rcColorWeightCursor, picked?S_WeightCursorPickedImg:S_WeightCursorNormalImg); +} + +int ColorWidget::_checkColorCtrlPntCursorSelected(const QPointF& pickPos) +{ + if (nullptr == _colorCurve) + return -1; + int colorCtrlPntCount = _colorCurve->getControlPointCount(); + for (int i = 0; i < colorCtrlPntCount; ++i) + { + const ColorControlPoint& pnt = _colorCurve->getControlPoint(i); + + float xPos = _valueToScreen(pnt.x); + float yPos = MARGIN_Y; + bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos); + if (picked) + { + return i; + } + } + + return -1; +} + +int ColorWidget::_checkAlphaCtrlPntCursorSelected(const QPointF& pickPos) +{ + if (_isLink) + { + if (nullptr == _colorCurve) + return -1; + int colorCtrlPntCount = _colorCurve->getControlPointCount(); + for (int i = 0; i < colorCtrlPntCount; ++i) + { + const ColorControlPoint& pnt = _colorCurve->getControlPoint(i); + + float xPos = _valueToScreen(pnt.x); + float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos); + if (picked) + { + return i; + } + } + } + else + { + if (nullptr == _alphaCurve) + return -1; + int colorCtrlPntCount = _alphaCurve->getControlPointCount(); + for (int i = 0; i < colorCtrlPntCount; ++i) + { + const ColorControlPoint& pnt = _alphaCurve->getControlPoint(i); + + float xPos = _valueToScreen(pnt.x); + float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos); + if (picked) + { + return i; + } + } + } + + return -1; +} + +int ColorWidget::_checkColorWeightCursorSelected(const QPointF& pickPos) +{ + int colorCtrlPntCount = _colorCurve->getControlPointCount(); + if (-1 != _pickedColorCtrlPnt) + { + if (0 == _pickedColorCtrlPnt) + { + return _checkColorWeightCursorSelected(0, pickPos); + } + else if ((colorCtrlPntCount - 1) == _pickedColorCtrlPnt) + { + return _checkColorWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos); + } + else if (0 < _pickedColorCtrlPnt && _pickedColorCtrlPnt < (colorCtrlPntCount - 1)) + { + int pickedWeightCursor = _checkColorWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos); + if (-1 != pickedWeightCursor) + return pickedWeightCursor; + else + return _checkColorWeightCursorSelected(_pickedColorCtrlPnt, pickPos); + } + } + + return -1; +} + +int ColorWidget::_checkColorWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos) +{ + const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(pickedCtrlPnt); + const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(pickedCtrlPnt + 1); + + if (pnt0.weight >= 0) + { + float xPos = _valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x)); + float yPos = MARGIN_Y + CONTROL_POINT_CURSOR_H - WEIGHT_CURSOR_H; + bool picked = isClickedInWeightCursor(QPointF(xPos, yPos), pickPos); + if (picked) + { + return pickedCtrlPnt; + } + } + + return - 1; +} + +int ColorWidget::_checkAlphaWeightCursorSelected(const QPointF& pickPos) +{ + if (_isLink) + { + int count = _colorCurve->getControlPointCount(); + if (-1 != _pickedAlphaCtrlPnt) + { + if (0 == _pickedAlphaCtrlPnt) + { + return _checkAlphaWeightCursorSelected(0, pickPos); + } + else if ((count - 1) == _pickedAlphaCtrlPnt) + { + return _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos); + } + else if (0 < _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (count - 1)) + { + int pickedWeightCursor = _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos); + if (-1 != pickedWeightCursor) + return pickedWeightCursor; + else + return _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt, pickPos); + } + } + } + else + { + int count = _alphaCurve->getControlPointCount(); + if (-1 != _pickedAlphaCtrlPnt) + { + if (0 == _pickedAlphaCtrlPnt) + { + return _checkAlphaWeightCursorSelected(0, pickPos); + } + else if ((count - 1) == _pickedAlphaCtrlPnt) + { + return _checkAlphaWeightCursorSelected(count - 1, pickPos); + } + else if (0 < _pickedAlphaCtrlPnt && _pickedAlphaCtrlPnt < (count - 1)) + { + int pickedWeightCursor = _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt - 1, pickPos); + if (-1 != pickedWeightCursor) + return pickedWeightCursor; + else + return _checkAlphaWeightCursorSelected(_pickedColorCtrlPnt, pickPos); + } + } + } + + return -1; +} + +int ColorWidget::_checkAlphaWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos) +{ + if (_isLink) + { + const ColorControlPoint& pnt0 = _colorCurve->getControlPoint(pickedCtrlPnt); + const ColorControlPoint& pnt1 = _colorCurve->getControlPoint(pickedCtrlPnt + 1); + + if (pnt0.weight >= 0) + { + float xPos = _valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x)); + float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + bool picked = isClickedInWeightCursor(QPointF(xPos, yPos), pickPos); + if (picked) + { + return pickedCtrlPnt; + } + } + } + else + { + int colorCtrlPntCount = _alphaCurve->getControlPointCount(); + for (int i = 0; i < colorCtrlPntCount - 1; ++i) + { + const ColorControlPoint& pnt0 = _alphaCurve->getControlPoint(i); + const ColorControlPoint& pnt1 = _alphaCurve->getControlPoint(i + 1); + + if (pnt0.weight >= 0) + { + float xPos = _valueToScreen(pnt0.x + pnt0.weight * (pnt1.x - pnt0.x)); + float yPos = height() - SPACING_V - CONTROL_POINT_CURSOR_H - MARGIN_Y; + bool picked = isClickedInCtrlPntCursor(QPointF(xPos, yPos), pickPos); + if (picked) + { + return i; + } + } + else + break; + } + } + + return -1; +} + +void ColorWidget::_addColorControlPoint(int xPos) +{ + float x = _screenToValue(xPos); + + int ctrlPntCount = _colorCurve->getControlPointCount(); + for (int i = 0; i < ctrlPntCount - 1; ++i) + { + const ColorControlPoint& pntLeft = _colorCurve->getControlPoint(i); + const ColorControlPoint& pntRight = _colorCurve->getControlPoint(i + 1); + + if (pntLeft.x < x && x < pntRight.x) + { + QColor color = _colorCurve->getColorByX(x); + ColorControlPoint newCtrlPnt(x, color, pntLeft.mode); + + std::vector<ColorControlPoint>::iterator itr = _colorCurve->_controlPoints.begin(); + std::advance(itr, i + 1); + _colorCurve->_controlPoints.insert(itr, newCtrlPnt); + + _pickedColorCtrlPnt = i + 1; + if (_isLink) + _pickedAlphaCtrlPnt = _pickedColorCtrlPnt; + + break; + } + } +} + +void ColorWidget::_addAlphaControlPoint(int xPos) +{ + float x = _screenToValue(xPos); + + int ctrlPntCount = _alphaCurve->getControlPointCount(); + for (int i = 0; i < ctrlPntCount - 1; ++i) + { + const ColorControlPoint& pntLeft = _alphaCurve->getControlPoint(i); + const ColorControlPoint& pntRight = _alphaCurve->getControlPoint(i + 1); + + if (pntLeft.x < x && x < pntRight.x) + { + QColor color = _alphaCurve->getColorByX(x); + ColorControlPoint newCtrlPnt(x, color, pntLeft.mode); + + std::vector<ColorControlPoint>::iterator itr = _alphaCurve->_controlPoints.begin(); + std::advance(itr, i + 1); + _alphaCurve->_controlPoints.insert(itr, newCtrlPnt); + + _pickedAlphaCtrlPnt = i + 1; + if (_isLink) + _pickedColorCtrlPnt = _pickedAlphaCtrlPnt; + + break; + } + } +} + +} // namespace CurveEditor +} // namespace nvidia
\ No newline at end of file diff --git a/tools/CurveEditor/source/Internal/Window/ColorWidget.h b/tools/CurveEditor/source/Internal/Window/ColorWidget.h new file mode 100644 index 0000000..d910789 --- /dev/null +++ b/tools/CurveEditor/source/Internal/Window/ColorWidget.h @@ -0,0 +1,126 @@ +#ifndef COLORWIDGET_H +#define COLORWIDGET_H + +#include <QtWidgets/QFrame> +#include <QtWidgets/QMenu> +#include <QtWidgets/QAction> +#include "Attribute.h" + +namespace nvidia { +namespace CurveEditor { + +class ColorWidget : public QFrame +{ + Q_OBJECT +public: + explicit ColorWidget(QWidget *parent = 0); + + inline bool isLink() { return _isLink; } + QColor getColor(); + int getAlpha(); + void setColor(const QColor& color); + void setAlpha(int alpha); + float getColorFallOff(); + void setColorFallOff(float fallOff); + float getAlphaFallOff(); + void setAlphaFallOff(float fallOff); + + // if alphaCurve of colorAttribute is with less than 2 control points, + // it treats that rgb color curve and alpha curve share same control points + // else, it uses rgb components of colorCurve of ColorAttribute, and it uses alpha component of alphaCurve of ColorAttribute + void setColorAttribute(ColorAttribute* colorAttribute); + void reset(); + inline void setCanAddRemoveControlPoint(bool val) { _canAddRemoveControlPoint = val; } + + void addControlPointsBeforeSelected(); + void addControlPointsAfterSelected(); + void removeSelectedControlPoint(); + + void setTangentType(InterpolateMode mode); + void setSmoothTangent(); + void setEaseInTangent(); + void setEaseOutTangent(); + + QString getColorTex(); + void setColorTex(const QString& strPath); + void reloadColorTex(); + void clearColorTex(); + QString getAlphaTex(); + void setAlphaTex(const QString& strPath); + void reloadAlphaTex(); + void clearAlphaTex(); + + void setAddCtrlPntByClick(bool value) { _canAddCtrlPntByClick = value; } + void setRemoveCtrlPntByClick(bool value) { _canRemoveCtrlPntByClick = value; } + + void setUseAlphaFromColor(bool val); + +signals: + void PickedControlPointChanged(bool isColorCtrlPnt); + void ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute* attribute); + void ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute* attribute, bool reloadColorTex, int selectedCtrlPntIndex); + +private slots: + void onShowContextMenu(const QPoint& pos); + void onRemoveControlPoint(); + +protected: + // QWidget events + virtual bool event(QEvent *event); + virtual void paintEvent(QPaintEvent * e); + virtual void resizeEvent(QResizeEvent* e); + virtual void mousePressEvent(QMouseEvent* e); + virtual void mouseReleaseEvent(QMouseEvent* e); + virtual void mouseMoveEvent(QMouseEvent* e); + +private: + void _updateCurveFitWindowPara(); + inline float _valueToScreen(float x); + inline float _screenToValue(float x); + + void _fillRampImage(QImage& colorImg, QImage& alphaImg); + void _drawRampArea(QPainter& painter); + void _drawCtrlPntCursors(QPainter& painter); + void _drawWeightCursors(QPainter& painter); + void _drawColorWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked = false); + void _drawAlphaWeightCursor(QPainter& painter, const ColorControlPoint& pnt0, const ColorControlPoint& pnt1, bool picked = false); + int _checkColorCtrlPntCursorSelected(const QPointF& pickPos); + int _checkAlphaCtrlPntCursorSelected(const QPointF& pickPos); + int _checkColorWeightCursorSelected(const QPointF& pickPos); + int _checkColorWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos); + int _checkAlphaWeightCursorSelected(const QPointF& pickPos); + int _checkAlphaWeightCursorSelected(int pickedCtrlPnt, const QPointF& pickPos); + void _addColorControlPoint(int xPos); + void _addAlphaControlPoint(int xPos); + +private: + bool _isLink; // if it's true, rgb color and alpha share the same control points + ColorAttribute* _colorAttribute; + ColorCurve* _colorCurve; + ColorCurve* _alphaCurve; + bool _canAddRemoveControlPoint; + bool _canAddCtrlPntByClick; + bool _canRemoveCtrlPntByClick; + + float _curveFitWindowScale; + float _curveFitWindowOffset; + + int _pickedColorCtrlPnt; + int _pickedAlphaCtrlPnt; + int _pickedColorWeight; + int _pickedAlphaWeight; + bool _dragColorCtrlPnt; + bool _dragAlphaCtrlPnt; + bool _dragColorWeight; + bool _dragAlphaWeight; + + int _colorCtrlPntToRemove; + int _alphaCtrlPntToRemove; + QMenu* _contextMenu; + QAction* _removeCtrlPntAction; +}; + +} // namespace CurveEditor +} // namespace nvidia + +#endif // COLORWIDGET_H diff --git a/tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp b/tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp new file mode 100644 index 0000000..b11c4cf --- /dev/null +++ b/tools/CurveEditor/source/Internal/Window/CurveEditorMainWindow.cpp @@ -0,0 +1,1530 @@ +#include "CurveEditorMainWindow.h" +#include "ui_CurveEditorMainWindow.h" +#include <QtWidgets/QSplitter> +#include <QtWidgets/QColorDialog> +#include "CurveWidget.h" +#include "ColorWidget.h" +#include "AlphaDialog.h" +#include <QtCore/QDebug> +#include <QtWidgets/QFileDialog> +#include <QtWidgets/QMessageBox> +#include <float.h> + +namespace nvidia { +namespace CurveEditor { + +// each value is associated with the tab index of tab control of attributes +enum AttributesTabIndex +{ + eCurveTab = 0, + eColorTab = 1, +}; + +///////////////////////////////////////////////////////////////////////////////////// +QString InterpolateModeToString(InterpolateMode mode) +{ + switch(mode) + { + case eDiscret: + return "Discret"; + case eLinear: + return "Linear"; + case eBezierSpline: + return "BezierSpline"; + case eCatmullRomSpline: + return "CatmullRomSpline"; + default: + return "Discret"; + } +} + +///////////////////////////////////////////////////////////////////////////////////// +InterpolateMode StringToInterpolateMode(const QString& mode) +{ + if (mode == "Discret") + { + return eDiscret; + } + else if (mode == "Linear") + { + return eLinear; + } + else if (mode == "BezierSpline") + { + return eBezierSpline; + } + else if (mode == "CatmullRomSpline") + { + return eCatmullRomSpline; + } + else + { + return eDiscret; + } +} + +QString OpenTextureFile( QString lastDir, QString title = "") +{ + QString titleStr = "Open Texture File"; + if(!title.isEmpty()) + titleStr = title; + + QString fileName = QFileDialog::getOpenFileName(nullptr, titleStr, lastDir, "Images (*.dds *.png *.bmp *.jpg *.tga)"); + + return fileName; +} + +///////////////////////////////////////////////////////////////////////////////////// +void setTextureButtons(QPushButton *pTex, QPushButton *pReload, QPushButton *pClear) +{ + pTex->setIcon(QIcon(":/AppMainWindow/Icon/TextureEnabled_icon.png")); + pReload->setIcon(QIcon(":/AppMainWindow/Icon/Refresh_icon.png")); + pClear->setIcon(QIcon(":/AppMainWindow/Icon/Remove_icon.png")); + + pTex->setIconSize(QSize(12,12)); + pReload->setIconSize(QSize(12,12)); + pClear->setIconSize(QSize(12,12)); +} + +////////////////////////////////////////////////////////// +QString addStar(QString text, bool add) +{ + QByteArray ba = text.toUtf8(); + + const char* in = ba.data(); + char out[1024]; + + int i = 0; + for (i = 0; i < strlen(in); i++) + { + if (in[i] == '*') + break; + out[i] = in[i]; + } + out[i] = 0; + + QString newtext; + if (add) + newtext = QString((const char*)out) + QString("*"); + else + newtext = QString((const char*)out) ; + return newtext; +} + +////////////////////////////////////////////////////////// +void setFocusColor(QWidget* qWidget, bool sameForAllAttributes) +{ + if (!qWidget) + return; + + QString sameStyle = QString("font: ; color: rgb(150,150,150);") ; + QString differentStyle = QString("font: bold; color: rgb(255,55,55);"); + QString style = (sameForAllAttributes) ? sameStyle : differentStyle; + + qWidget->setStyleSheet(style); + + QLabel* label = dynamic_cast<QLabel*>(qWidget); + if (label) + { + QString newtext = addStar(label->text(), !sameForAllAttributes); + + label->setFrameStyle(0); + label->setText(newtext); + } +} + +////////////////////////////////////////////////////////// +void pickColor(QColor& color, QWidget* parent) +{ + QColor newColor = QColorDialog::getColor(color, parent); + if(newColor.isValid()) + { + color = newColor; + } +} + +////////////////////////////////////////////////////////// +void pickAlpha(int& alpha, QWidget* parent) +{ + alpha = AlphaDialog::getAlpha(alpha, parent); +} + +////////////////////////////////////////////////////////// +void setButtonColor(QPushButton *button, const QColor& color) +{ + QString specBtnStyle = QString("background-color: rgb(%1,%2,%3);") + .arg(color.red()) + .arg(color.green()) + .arg(color.blue()); + + button->setStyleSheet(specBtnStyle); +} + +////////////////////////////////////////////////////////// +void setButtonTex(QPushButton *button, bool used) +{ + if (used) + button->setIcon(QIcon(":/AppMainWindow/Icon/TextureIsUsed_icon.png")); + else + button->setIcon(QIcon(":/AppMainWindow/Icon/TextureEnabled_icon.png")); +} + +CurveEditorMainWindow::CurveEditorMainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::CurveEditorMainWindow) + , _curveWidget(nullptr) + , _colorWidget(nullptr) + , _curveAttributeCache(nullptr) + , _colorAttributeCache(nullptr) + , _updateUIFromData(false) + , _canMoveCurveControlPointHorizontally(true) + , _canAddRemoveCurveControlPoint(true) + , _canChangeCurveTangentType(true) +{ + Q_INIT_RESOURCE(CurveEditor); + + ui->setupUi(this); + + setTextureButtons(ui->btnColorTex, ui->btnColorReload, ui->btnColorClear); + setTextureButtons(ui->btnAlphaTex, ui->btnAlphaReload, ui->btnAlphaClear); + + ui->centralWidget->setStretchFactor(0, 30); + ui->centralWidget->setStretchFactor(1, 70); + + { + QActionGroup* groupSnap = new QActionGroup(this); + groupSnap->addAction(ui->actionSnap_All); + groupSnap->addAction(ui->actionSnap_Horizontal); + groupSnap->addAction(ui->actionSnap_Vertical); + } + + { + QActionGroup* groupAddRemoveCtrlPnt = new QActionGroup(this); + groupAddRemoveCtrlPnt->addAction(ui->actionAdd_Control_Point_By_Click); + groupAddRemoveCtrlPnt->addAction(ui->actionRemove_Control_Point_By_Click); + } + + _fillCurveAttributesTree(); + + _fillColorAttributesTree(); + + { + _curveWidget = new CurveWidget(ui->frameCurveEditorArea); + ui->layoutCurveEditorArea->addWidget(_curveWidget); + connect(_curveWidget, SIGNAL(PickedControlPointChanged(const std::vector<CurveEntity*>)), this, SLOT(onCurvePickedControlPointChanged(const std::vector<CurveEntity*>))); + connect(_curveWidget, SIGNAL(PickedControlPointValueChanged(QPointF&)), this, SLOT(onCurvePickedControlPointValueChanged(QPointF&))); + } + + { + _colorWidget = new ColorWidget(ui->frameColorAlphaRamp); + ui->layoutColorEditorArea->addWidget(_colorWidget); + connect(_colorWidget, SIGNAL(PickedControlPointChanged(bool)), this, SLOT(onColorPickedControlPointChanged(bool))); + + QColor color = _colorWidget->getColor(); + setButtonColor(ui->btnColor, color); + setButtonColor(ui->btnAlpha, QColor(color.alpha(), color.alpha(), color.alpha())); + } + + connect(_curveWidget, SIGNAL(CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute*)), this, SIGNAL(CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute*))); + connect(_colorWidget, SIGNAL(ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute*)), this, SIGNAL(ColorAttributeChanged(nvidia::CurveEditor::ColorAttribute*))); + connect(_colorWidget, SIGNAL(ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute*, bool, int)), this, SIGNAL(ReloadColorAttributeTexture(nvidia::CurveEditor::ColorAttribute*, bool, int))); + + QString defFilePath; + + QString appDir = qApp->applicationDirPath(); + QDir dir(appDir); + if (dir.cd("../../media")) + defFilePath = dir.absolutePath(); + + _lastFilePath = defFilePath; + _presetPath = _lastFilePath + "/Presets/"; +} + +CurveEditorMainWindow::~CurveEditorMainWindow() +{ + delete ui; + ui = nullptr; +} + +void CurveEditorMainWindow::setCurveAttributes(const std::vector<CurveAttributeBase*>& attributes) +{ + _curveWidget->setCurveAttributes(std::vector<CurveAttributeBase*>()); + + _curveAttributes = attributes; + _fillCurveAttributesTree(); + + _canMoveCurveControlPointHorizontally = false; + _canAddRemoveCurveControlPoint = false; + _canChangeCurveTangentType = false; + size_t countAttributes = _curveAttributes.size(); + for (size_t i = 0; i < countAttributes; ++i) + { + CurveAttributeBase* attribute = _curveAttributes[i]; + + if (attribute->getType() == eGroupAttr) + { + CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute); + size_t countAttributesInGroup = attributeGroup->attributes.size(); + for (size_t j = 0; j < countAttributesInGroup; ++j) + { + CurveAttribute* attributeInGroup = static_cast<CurveAttribute*>(attributeGroup->attributes[j]); + if (attributeInGroup->canMoveControlPointHorizontally()) + _canMoveCurveControlPointHorizontally = true; + if (attributeInGroup->canAddRemoveControlPoint()) + _canAddRemoveCurveControlPoint = true; + if (attributeInGroup->canChangeTangentType()) + _canChangeCurveTangentType = true; + } + } + else + { + CurveAttribute* attributeSecific = static_cast<CurveAttribute*>(attribute); + if (attributeSecific->canMoveControlPointHorizontally()) + _canMoveCurveControlPointHorizontally = true; + if (attributeSecific->canAddRemoveControlPoint()) + _canAddRemoveCurveControlPoint = true; + if (attributeSecific->canChangeTangentType()) + _canChangeCurveTangentType = true; + } + } + + ui->spinBoxLocation->setEnabled(_canMoveCurveControlPointHorizontally); + _syncUIStatusWithSelectedAttribute(_canAddRemoveCurveControlPoint, _canChangeCurveTangentType); +} + +void CurveEditorMainWindow::setColorCurveAttributes(const std::vector<ColorAttribute*>& attributes) +{ + _colorWidget->setColorAttribute(nullptr); + + _colorAttributes = attributes; + _fillColorAttributesTree(); +} + +void CurveEditorMainWindow::setSelectedCurveAttributes(const std::vector<CurveAttributeBase*>& attributes) +{ + ui->tabWidgetAttributes->setCurrentIndex(eCurveTab); + + for (size_t i = 0; i < attributes.size(); ++i) + { + CurveAttributeBase* attribute = attributes[i]; + QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->findItems(attribute->getName().c_str(), Qt::MatchExactly); + if (items.size() > 0) + items[0]->setSelected(true); + } +} + +void CurveEditorMainWindow::setSelectedColorAttribute(const ColorAttribute* attribute) +{ + ui->tabWidgetAttributes->setCurrentIndex(eColorTab); + + if (attribute) + { + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->findItems(attribute->getName().c_str(), Qt::MatchExactly); + if (items.size() > 0) + items[0]->setSelected(true); + } +} + +void CurveEditorMainWindow::setResampleEnabled(bool enable) +{ + ui->checkBoxResamplePoints->setVisible(enable); + ui->spinBoxResamplePoints->setVisible(enable); + ui->checkBoxResamplePoints->setEnabled(enable); + ui->spinBoxResamplePoints->setEnabled(enable); +} + +void CurveEditorMainWindow::on_actionCopy_triggered() +{ + if (eCurveTab == ui->tabWidgetAttributes->currentIndex()) + { + QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems(); + if (1 == items.count()) + { + CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0)); + + if (eSingleAttr == item->_attribute->getType()) + { + if (_curveAttributeCache == nullptr) + _curveAttributeCache = new CurveAttribute("curveAttributeCache"); + + CurveAttribute* selectedAttribute = static_cast<CurveAttribute*>(item->_attribute); + _curveAttributeCache->curve = selectedAttribute->curve; + return ; + } + } + + QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to copy attribute data.")); + } + else if (eColorTab == ui->tabWidgetAttributes->currentIndex()) + { + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems(); + if (1 == items.count()) + { + ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0)); + + if (eColorAttr == item->_attribute->getType()) + { + if (_colorAttributeCache == nullptr) + _colorAttributeCache = new ColorAttribute("colorAttributeCache"); + + ColorAttribute* selectedAttribute = static_cast<ColorAttribute*>(item->_attribute); + _colorAttributeCache->colorCurve = selectedAttribute->colorCurve; + _colorAttributeCache->alphaCurve = selectedAttribute->alphaCurve; + return ; + } + } + } +} + +void CurveEditorMainWindow::on_actionPaste_triggered() +{ + if (eCurveTab == ui->tabWidgetAttributes->currentIndex()) + { + if (nullptr == _curveAttributeCache) + { + QMessageBox::warning(this, tr("Warning"), tr("You should copy or load an curve attribute's data first.")); + return ; + } + + QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems(); + if (1 == items.count()) + { + CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0)); + + if (eSingleAttr == item->_attribute->getType()) + { + CurveAttribute* selectedAttribute = static_cast<CurveAttribute*>(item->_attribute); + bool compatible = true; + if (compatible) + { + selectedAttribute->curve = _curveAttributeCache->curve; + on_treeWidgetCurveAttributes_itemSelectionChanged(); + CurveAttributeChanged(selectedAttribute); + } + else + { + QMessageBox::warning(this, tr("Warning"), tr("The data types between the curve attribute copyed from and the curve attribute copy to are incompatible .")); + } + return ; + } + } + + QMessageBox::warning(this, tr("Warning"), tr("You should select only one curve attribute to paste curve attribute data.")); + } + else if (eColorTab == ui->tabWidgetAttributes->currentIndex()) + { + if (nullptr == _colorAttributeCache) + { + QMessageBox::warning(this, tr("Warning"), tr("You should copy or load an color attribute's data first.")); + return ; + } + + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems(); + if (1 == items.count()) + { + ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0)); + + if (eColorAttr == item->_attribute->getType()) + { + ColorAttribute* selectedAttribute = static_cast<ColorAttribute*>(item->_attribute); + bool compatible = true; + if (compatible) + { + selectedAttribute->colorCurve = _colorAttributeCache->colorCurve; + selectedAttribute->alphaCurve = _colorAttributeCache->alphaCurve; + on_treeWidgetColorAttributes_itemSelectionChanged(); + ColorAttributeChanged(selectedAttribute); + } + else + { + QMessageBox::warning(this, tr("Warning"), tr("The data types between copy from attribute and copy to attribute are incompatible .")); + } + return ; + } + } + + QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to paste attribute data.")); + } +} + +void CurveEditorMainWindow::on_actionSave_Selected_as_Preset_triggered() +{ + QDir dir(_presetPath); + if (!dir.exists()) + dir.mkdir(_presetPath); + + CurveAttribute* curveAttribute = nullptr; + ColorAttribute* colorAttribute = nullptr; + QString presetFile = _presetPath; + + if (eCurveTab == ui->tabWidgetAttributes->currentIndex()) + { + QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems(); + if (1 != items.count()) + { + QMessageBox::warning(this, tr("Warning"), tr("You should select one attribute only to save preset.")); + return ; + } + + CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0)); + + if (eSingleAttr != item->_attribute->getType()) + { + return; + } + + curveAttribute = static_cast<CurveAttribute*>(item->_attribute); + presetFile += curveAttribute->getName().c_str(); + presetFile += ".cps"; + } + else if (eColorTab == ui->tabWidgetAttributes->currentIndex()) + { + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems(); + if (1 != items.count()) + { + QMessageBox::warning(this, tr("Warning"), tr("You should select one attribute only to save preset.")); + return ; + } + + ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0)); + + if (eColorAttr != item->_attribute->getType()) + { + return; + } + + colorAttribute = item->_attribute; + presetFile += colorAttribute->getName().c_str(); + presetFile += ".cps"; + } + + QString filePath = QFileDialog::getSaveFileName(this, tr("Save Curve PreSet"), presetFile, tr("Curve PreSet(*.cps)")); + if (filePath.length() == 0) + { + QMessageBox::warning(this, tr("Path"), tr("You didn't select any files.")); + return ; + } + + QFileInfo fileInfo(filePath); + _presetPath = fileInfo.absoluteDir().absolutePath(); + if (!_presetPath.endsWith("/")) + _presetPath += "/"; + + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly|QIODevice::Truncate)) + { + return; + } + QTextStream out(&file); + + QDomDocument xmlDoc; + QDomElement rootElm = xmlDoc.createElement(tr("CurvePreSet")); + xmlDoc.appendChild(rootElm); + + if (curveAttribute != nullptr) + { + _saveAttribute(rootElm, curveAttribute); + } + else if (colorAttribute != nullptr) + { + _saveAttribute(rootElm, colorAttribute); + } + // 4 is count of indent + xmlDoc.save(out, 4); +} + +void CurveEditorMainWindow::on_actionLoad_Preset_to_Copy_Buffer_triggered() +{ + QString filePath = QFileDialog::getOpenFileName(this, tr("Open Curve PreSet"), _presetPath, tr("Curve PreSet(*.cps)")); + if (filePath.length() == 0) + { + QMessageBox::warning(this, tr("Path"), tr("You didn't select any files.")); + return; + } + + QFileInfo fileInfo(filePath); + _presetPath = fileInfo.absoluteDir().absolutePath(); + if (!_presetPath.endsWith("/")) + _presetPath += "/"; + + QFile file(filePath); + + if (!file.open(QIODevice::ReadOnly)) + { + return; + } + + QDomDocument xmlDoc; + if (!xmlDoc.setContent(&file)) + { + file.close(); + return; + } + file.close(); + + if (xmlDoc.isNull() || xmlDoc.documentElement().tagName() != tr("CurvePreSet")) + { + QMessageBox::warning(this, tr("Warning"), tr("The file you selected is empty or not a cps file.")); + return; + } + + QDomElement elm = xmlDoc.documentElement().firstChildElement(); + CurveAttributeBase* presetAttribute = _loadAttribute(elm); + if (nullptr == presetAttribute) + { + QMessageBox::warning(this, tr("Warning"), tr("Faid to load the cps file!")); + return; + } + + if (eSingleAttr == presetAttribute->_type) + { + if (_curveAttributeCache == nullptr) + _curveAttributeCache = new CurveAttribute("curveAttributeCache"); + + CurveAttribute* presetCurveAttribute = static_cast<CurveAttribute*>(presetAttribute); + _curveAttributeCache->curve = presetCurveAttribute->curve; + } + else if (eColorAttr == presetAttribute->_type) + { + if (_colorAttributeCache == nullptr) + _colorAttributeCache = new ColorAttribute("colorAttributeCache"); + + ColorAttribute* presetColorAttribute = static_cast<ColorAttribute*>(presetAttribute); + _colorAttributeCache->colorCurve = presetColorAttribute->colorCurve; + _colorAttributeCache->alphaCurve = presetColorAttribute->alphaCurve; + } +} + +void CurveEditorMainWindow::on_actionImport_Preset_onto_Selected_triggered() +{ + CurveAttribute* curveAttribute = nullptr; + ColorAttribute* colorAttribute = nullptr; + if (eCurveTab == ui->tabWidgetAttributes->currentIndex()) + { + QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems(); + if (1 != items.count()) + { + QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to import preset.")); + return; + } + + CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(0)); + + if (eSingleAttr != item->_attribute->getType()) + { + return; + } + + curveAttribute = static_cast<CurveAttribute*>(item->_attribute); + } + else if (eColorTab == ui->tabWidgetAttributes->currentIndex()) + { + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems(); + if (1 != items.count()) + { + QMessageBox::warning(this, tr("Warning"), tr("You should select only one attribute to import preset.")); + return; + } + + ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0)); + + if (eColorAttr != item->_attribute->getType()) + { + return; + } + + colorAttribute = item->_attribute; + } + + QString filePath = QFileDialog::getOpenFileName(this, tr("Open Curve PreSet"), _presetPath, tr("Curve PreSet(*.cps)")); + if (filePath.length() == 0) + { + QMessageBox::warning(this, tr("Path"), tr("You didn't select any files.")); + return; + } + + QFileInfo fileInfo(filePath); + _presetPath = fileInfo.absoluteDir().absolutePath(); + if (!_presetPath.endsWith("/")) + _presetPath += "/"; + + QFile file(filePath); + + if (!file.open(QIODevice::ReadOnly)) + { + return; + } + + QDomDocument xmlDoc; + if (!xmlDoc.setContent(&file)) + { + file.close(); + return; + } + file.close(); + + if (xmlDoc.isNull() || xmlDoc.documentElement().tagName() != tr("CurvePreSet")) + { + QMessageBox::warning(this, tr("Warning"), tr("The file you selected is empty or not a cps file.")); + return; + } + + QDomElement elm = xmlDoc.documentElement().firstChildElement(); + CurveAttributeBase* presetAttribute = _loadAttribute(elm); + if (nullptr == presetAttribute) + { + QMessageBox::warning(this, tr("Warning"), tr("Faid to load the cps file!")); + return; + } + + if (eSingleAttr == presetAttribute->_type) + { + CurveAttribute* presetCurveAttribute = static_cast<CurveAttribute*>(presetAttribute); + + bool compatible = (curveAttribute != nullptr) ? true:false; + if (compatible) + { + curveAttribute->curve = presetCurveAttribute->curve; + on_treeWidgetCurveAttributes_itemSelectionChanged(); + CurveAttributeChanged(curveAttribute); + } + else + { + QMessageBox::warning(this, tr("Warning"), tr("The selected attribute is incompatible with preset attribute.")); + } + } + else if (eColorAttr == presetAttribute->_type) + { + ColorAttribute* presetColorAttribute = static_cast<ColorAttribute*>(presetAttribute); + + bool compatible = (colorAttribute != nullptr) ? true:false;; + if (compatible) + { + colorAttribute->colorCurve = presetColorAttribute->colorCurve; + colorAttribute->alphaCurve = presetColorAttribute->alphaCurve; + on_treeWidgetColorAttributes_itemSelectionChanged(); + ColorAttributeChanged(colorAttribute); + } + else + { + QMessageBox::warning(this, tr("Warning"), tr("The selected attribute is incompatible with preset attribute.")); + } + } +} + +void CurveEditorMainWindow::on_actionReset_Curve_triggered() +{ + if (ui->tabWidgetAttributes->currentIndex() == eCurveTab) + { + _curveWidget->reset(); + } + else if (ui->tabWidgetAttributes->currentIndex() == eColorTab) + { + _colorWidget->reset(); + } + +} + +void CurveEditorMainWindow::on_actionAdd_Before_Selected_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->addControlPointsBeforeSelected(); + + if (_colorWidget->hasFocus()) + _colorWidget->addControlPointsBeforeSelected(); +} + +void CurveEditorMainWindow::on_actionAdd_After_Selected_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->addControlPointsAfterSelected(); + + if (_colorWidget->hasFocus()) + _colorWidget->addControlPointsAfterSelected(); +} + +void CurveEditorMainWindow::on_actionRemove_Selected_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->removeSelectedControlPoints(); + + if (_colorWidget->hasFocus()) + _colorWidget->removeSelectedControlPoint(); +} + +void CurveEditorMainWindow::on_actionTangent_Stepped_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->setTangentType(eDiscret); + + if (_colorWidget->hasFocus()) + _colorWidget->setTangentType(eDiscret); +} + +void CurveEditorMainWindow::on_actionTangent_Linear_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->setTangentType(eLinear); + + if (_colorWidget->hasFocus()) + _colorWidget->setTangentType(eLinear); +} + +void CurveEditorMainWindow::on_actionTangent_Smooth_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->setSmoothTangent(); + + if (_colorWidget->hasFocus()) + _colorWidget->setSmoothTangent(); +} + +void CurveEditorMainWindow::on_actionTangent_Ease_Out_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->setEaseOutTangent(); + + if (_colorWidget->hasFocus()) + _colorWidget->setEaseOutTangent(); +} + +void CurveEditorMainWindow::on_actionTangent_Ease_In_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->setEaseInTangent(); + + if (_colorWidget->hasFocus()) + _colorWidget->setEaseInTangent(); +} + +void CurveEditorMainWindow::on_actionTangent_Spline_triggered() +{ + if (_curveWidget->hasFocus()) + _curveWidget->setTangentType(eCatmullRomSpline); + + if (_colorWidget->hasFocus()) + _colorWidget->setTangentType(eCatmullRomSpline); +} + +void CurveEditorMainWindow::on_actionSnap_All_triggered() +{ + _curveWidget->setSnapAll(); +} + +void CurveEditorMainWindow::on_actionSnap_Horizontal_triggered() +{ + _curveWidget->setSnapHorizontal(); +} + +void CurveEditorMainWindow::on_actionSnap_Vertical_triggered() +{ + _curveWidget->setSnapVertical(); +} + +void CurveEditorMainWindow::on_actionContract_Horizontally_triggered() +{ + _curveWidget->decreaseCurveScaleHorizontally(); +} + +void CurveEditorMainWindow::on_actionExpand_Horizontally_triggered() +{ + _curveWidget->increaseCurveScaleHorizontally(); +} + +void CurveEditorMainWindow::on_actionContract_Vertically_triggered() +{ + _curveWidget->decreaseCurveScaleVertically(); +} + +void CurveEditorMainWindow::on_actionExpand_Vertically_triggered() +{ + _curveWidget->increaseCurveScaleVertically(); +} + +void CurveEditorMainWindow::on_actionFrame_Horizontally_triggered() +{ + _curveWidget->frameCurveScaleHorizontally(); +} + +void CurveEditorMainWindow::on_actionFrame_Vertically_triggered() +{ + _curveWidget->frameCurveScaleVertically(); +} + +void CurveEditorMainWindow::on_actionFrame_All_triggered() +{ + _curveWidget->frameCurveScale(); +} + +void CurveEditorMainWindow::on_spinBoxLocation_valueChanged(double value) +{ + if (!_updateUIFromData) + _curveWidget->setLocation(value); +} + +void CurveEditorMainWindow::on_spinBoxValue_valueChanged(double value) +{ + if (!_updateUIFromData) + _curveWidget->setValue(value); +} + +void CurveEditorMainWindow::on_btnColor_clicked() +{ + QColor color = _colorWidget->getColor(); + pickColor(color, nullptr); + _colorWidget->setColor(color); + setButtonColor(ui->btnColor, color); +} + +void CurveEditorMainWindow::on_btnColorTex_clicked() +{ + QString filePath = OpenTextureFile(_colorWidget->getColorTex().isEmpty() ? _lastFilePath : _colorWidget->getColorTex()); + _colorWidget->setColorTex(filePath); + setButtonTex(ui->btnColorTex, !filePath.isEmpty()); + + if (!filePath.isEmpty()) + { + QFileInfo fileInfo(filePath); + _lastFilePath = fileInfo.absoluteDir().absolutePath(); + } +} + +void CurveEditorMainWindow::on_btnColorReload_clicked() +{ + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems(); + if (0 ==items.count()) + return; + + _colorWidget->reloadColorTex(); +} + +void CurveEditorMainWindow::on_btnColorClear_clicked() +{ + _colorWidget->clearColorTex(); + setButtonTex(ui->btnColorTex, false); +} + +void CurveEditorMainWindow::on_btnAlpha_clicked() +{ + int alpha = _colorWidget->getAlpha(); + pickAlpha(alpha, nullptr); + _colorWidget->setAlpha(alpha); + setButtonColor(ui->btnAlpha, QColor(alpha, alpha, alpha)); +} + +void CurveEditorMainWindow::on_btnAlphaTex_clicked() +{ + QString filePath = OpenTextureFile(_colorWidget->getAlphaTex().isEmpty() ? _lastFilePath : _colorWidget->getAlphaTex()); + _colorWidget->setAlphaTex(filePath); + setButtonTex(ui->btnAlphaTex, !filePath.isEmpty()); + + if (!filePath.isEmpty()) + { + QFileInfo fileInfo(filePath); + _lastFilePath = fileInfo.absoluteDir().absolutePath(); + } +} + +void CurveEditorMainWindow::on_btnAlphaReload_clicked() +{ + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems(); + if (0 ==items.count()) + return; + + _colorWidget->reloadAlphaTex(); +} + +void CurveEditorMainWindow::on_btnAlphaClear_clicked() +{ + _colorWidget->clearAlphaTex(); + setButtonTex(ui->btnAlphaTex, false); +} + +void CurveEditorMainWindow::on_checkBoxUseAlphaChannellFromColor_stateChanged(int val) +{ + _colorWidget->setUseAlphaFromColor(0 != val); +} + +void CurveEditorMainWindow::on_treeWidgetCurveAttributes_itemSelectionChanged() +{ + std::vector<CurveAttributeBase*> attributes; + + QList<QTreeWidgetItem*> items = ui->treeWidgetCurveAttributes->selectedItems(); + int count = items.count(); + for (int i = 0; i < items.count(); ++i) + { + CurveAttributeTreeItem* item = static_cast<CurveAttributeTreeItem*>(items.at(i)); + + attributes.push_back(item->_attribute); + + qDebug()<< item->_attribute->getName().c_str(); + } + + _curveWidget->setCurveAttributes(attributes); + + bool canMoveControlPointHorizontally = _canMoveCurveControlPointHorizontally; + bool canAddRemoveControlPoint = _canAddRemoveCurveControlPoint; + bool canChangeTangentType = _canChangeCurveTangentType; + for (size_t i = 0; i < attributes.size(); ++i) + { + CurveAttributeBase* attribute = attributes[i]; + if (eGroupAttr == attribute->getType()) + { + CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute); + for (size_t j = 0; j < attributeGroup->attributes.size(); ++j) + { + CurveAttributeBase* attributeInGroup = attributeGroup->attributes[j]; + + if (attributeInGroup->canMoveControlPointHorizontally()) + canMoveControlPointHorizontally = true; + + if (attributeInGroup->canAddRemoveControlPoint()) + canAddRemoveControlPoint = true; + + if (attributeInGroup->canChangeTangentType()) + canChangeTangentType = true; + } + } + else + { + if (attribute->canMoveControlPointHorizontally()) + canMoveControlPointHorizontally = true; + + if (attribute->canAddRemoveControlPoint()) + canAddRemoveControlPoint = attribute->canAddRemoveControlPoint(); + + if (attribute->canChangeTangentType()) + canChangeTangentType = true; + } + } + + ui->spinBoxLocation->setEnabled(canMoveControlPointHorizontally); + _syncUIStatusWithSelectedAttribute(canAddRemoveControlPoint, canChangeTangentType); +} + +void CurveEditorMainWindow::on_treeWidgetColorAttributes_itemSelectionChanged() +{ + QList<QTreeWidgetItem*> items = ui->treeWidgetColorAttributes->selectedItems(); + if (0 == items.count()) + return; + + ColorAttributeTreeItem* item = static_cast<ColorAttributeTreeItem*>(items.at(0)); + _colorWidget->setColorAttribute(item->_attribute); + _colorWidget->setCanAddRemoveControlPoint(item->_attribute->canAddRemoveControlPoint()); + + _syncUIStatusWithSelectedAttribute(item->_attribute->canAddRemoveControlPoint(), item->_attribute->canChangeTangentType()); +} + +void CurveEditorMainWindow::on_tabWidgetAttributes_currentChanged(int index) +{ + //if (eCurveTab == index) + //{ + // _setCurveExclusiveUIEnable(true); + //} + //else if (eColorTab == index) + //{ + // _setCurveExclusiveUIEnable(false); + //} +} + +void CurveEditorMainWindow::on_sliderColorFallOff_sliderMoved(int value) +{ + if (!_updateUIFromData) + { + _colorWidget->setColorFallOff((float)value/100); + + if (_colorWidget->isLink()) + { + _updateUIFromData = true; + ui->sliderAlphaFallOff->setValue(value); + _updateUIFromData = false; + } + } +} + +void CurveEditorMainWindow::on_sliderAlphaFallOff_sliderMoved(int value) +{ + if (!_updateUIFromData) + { + _colorWidget->setAlphaFallOff((float)value/100); + + if (_colorWidget->isLink()) + { + _updateUIFromData = true; + ui->sliderAlphaFallOff->setValue(value); + _updateUIFromData = false; + } + } +} + +void CurveEditorMainWindow::on_actionAdd_Control_Point_By_Click_triggered(bool val) +{ + _curveWidget->setAddCtrlPntByClick(val); + _curveWidget->setRemoveCtrlPntByClick(false); + + _colorWidget->setAddCtrlPntByClick(val); + _colorWidget->setRemoveCtrlPntByClick(false); +} + +void CurveEditorMainWindow::on_actionRemove_Control_Point_By_Click_triggered(bool val) +{ + _curveWidget->setAddCtrlPntByClick(false); + _curveWidget->setRemoveCtrlPntByClick(val); + + _colorWidget->setAddCtrlPntByClick(false); + _colorWidget->setRemoveCtrlPntByClick(val); +} + +void CurveEditorMainWindow::onCurvePickedControlPointChanged(const std::vector<CurveEntity*>& pickedCurves) +{ + bool enableChangeTangentType = true; + bool enableAddRemoveCtrlPnts = true; + bool enableLoactionEditor = true; + bool locationSameForAllAttributes = true; + bool valueSameForAllAttributes = true; + float location = FLT_MIN, value = FLT_MIN; + _updateUIFromData = true; + ui->spinBoxLocation->setValue(location); + ui->spinBoxValue->setValue(value); + _updateUIFromData = false; + for(size_t i = 0; i < pickedCurves.size(); ++i) + { + CurveEntity* curveEntity = pickedCurves[i]; + std::vector<int>& pickedControlPoints = pickedCurves[i]->getPickedControlPointIndexes(); + const ControlPoint& ctrlPnt = pickedCurves[i]->_curve->getControlPoint(pickedControlPoints[0]); + + if (!curveEntity->_attribute->canMoveControlPointHorizontally()) + enableLoactionEditor = false; + + if (pickedControlPoints.size() > 1) + enableLoactionEditor = false; + + if (location == FLT_MIN) + { + location = ctrlPnt.value.x(); + _updateUIFromData = true; + ui->spinBoxLocation->setValue(location); + _updateUIFromData = false; + } + else if (location != ctrlPnt.value.x()) + locationSameForAllAttributes = false; + + if (value == FLT_MIN) + { + value = ctrlPnt.value.y(); + _updateUIFromData = true; + ui->spinBoxValue->setValue(value); + _updateUIFromData = false; + } + else if (value != ctrlPnt.value.y()) + valueSameForAllAttributes = false; + + if (!curveEntity->_attribute->canChangeTangentType() && pickedControlPoints.size() != 0) + enableChangeTangentType = false; + + if (!curveEntity->_attribute->canAddRemoveControlPoint() && pickedControlPoints.size() != 0) + enableAddRemoveCtrlPnts = false; + + } + + if (pickedCurves.size() > 0) + { + ui->spinBoxLocation->setEnabled(enableLoactionEditor); + + setFocusColor(ui->labelLoacation, locationSameForAllAttributes); + setFocusColor(ui->labelValue, valueSameForAllAttributes); + + _setTangentTypeUIStatus(enableChangeTangentType); + _setAddRemoveCtrlPntUIStatus(enableAddRemoveCtrlPnts); + } + else + { + on_treeWidgetCurveAttributes_itemSelectionChanged(); + } + +} + +void CurveEditorMainWindow::onCurvePickedControlPointValueChanged(QPointF& value) +{ + _updateUIFromData = true; + ui->spinBoxLocation->setValue(value.x()); + ui->spinBoxValue->setValue(value.y()); + _updateUIFromData = false; + + QList<QTreeWidgetItem*> selectedAttributes = ui->treeWidgetCurveAttributes->selectedItems(); + if (selectedAttributes.count() > 0) + { + + } +} + +void CurveEditorMainWindow::_fillCurveAttributesTree() +{ + ui->treeWidgetCurveAttributes->clear(); + + size_t countAttributes = _curveAttributes.size(); + for (size_t i = 0; i < countAttributes; ++i) + { + CurveAttributeBase* attribute = _curveAttributes[i]; + CurveAttributeTreeItem* itemFirstLevel = new CurveAttributeTreeItem(ui->treeWidgetCurveAttributes, attribute); + itemFirstLevel->setText(0, attribute->getName().c_str()); + + if (attribute->getType() == eGroupAttr) + { + CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute); + size_t countAttributesInGroup = attributeGroup->attributes.size(); + for (size_t j = 0; j < countAttributesInGroup; ++j) + { + CurveAttribute* attributeInGroup = static_cast<CurveAttribute*>(attributeGroup->attributes[j]); + CurveAttributeTreeItem* itemSecondLevel = new CurveAttributeTreeItem(itemFirstLevel, attributeInGroup); + itemSecondLevel->setText(0, attributeInGroup->getName().c_str()); + itemSecondLevel->setForeground(0, QBrush(attributeInGroup->color)); + } + } + else + { + CurveAttribute* attributeSecific = static_cast<CurveAttribute*>(attribute); + itemFirstLevel->setForeground(0, QBrush(attributeSecific->color)); + } + } +} + +void CurveEditorMainWindow::_fillColorAttributesTree() +{ + ui->treeWidgetColorAttributes->clear(); + + size_t countAttributes = _colorAttributes.size(); + for (size_t i = 0; i < countAttributes; ++i) + { + ColorAttribute* attribute = _colorAttributes[i]; + ColorAttributeTreeItem* itemFirstLevel = new ColorAttributeTreeItem(ui->treeWidgetColorAttributes, attribute); + itemFirstLevel->setText(0, attribute->getName().c_str()); + } +} + +void CurveEditorMainWindow::_syncUIStatusWithSelectedAttribute(bool canAddRemoveControlPoint, bool canChangeTangentType) +{ + _setAddRemoveCtrlPntUIStatus(canAddRemoveControlPoint); + _setTangentTypeUIStatus(canChangeTangentType); +} + +void CurveEditorMainWindow::_setCurveExclusiveUIEnable(bool enable) +{ + ui->actionSnap_All->setEnabled(enable); + ui->actionSnap_Horizontal->setEnabled(enable); + ui->actionSnap_Vertical->setEnabled(enable); + ui->actionExpand_Horizontally->setEnabled(enable); + ui->actionExpand_Vertically->setEnabled(enable); + ui->actionFrame_Horizontally->setEnabled(enable); + ui->actionFrame_Vertically->setEnabled(enable); + ui->actionFrame_All->setEnabled(enable); + ui->actionContract_Horizontally->setEnabled(enable); + ui->actionContract_Vertically->setEnabled(enable); +} + +void CurveEditorMainWindow::_setColorUIEnable(bool enable) +{ + ui->btnColor->setEnabled(enable); + ui->btnColorTex->setEnabled(enable); + ui->btnColorReload->setEnabled(enable); + ui->btnColorClear->setEnabled(enable); + ui->sliderColorFallOff->setEnabled(enable); +} + +void CurveEditorMainWindow::_setAlphaUIEnable(bool enable) +{ + if (_colorWidget->isLink()) + ui->btnAlpha->setEnabled(true); + else + ui->btnAlpha->setEnabled(enable); + ui->btnAlphaTex->setEnabled(enable); + ui->btnAlphaReload->setEnabled(enable); + ui->btnAlphaClear->setEnabled(enable); + ui->sliderAlphaFallOff->setEnabled(enable); +} + +void CurveEditorMainWindow::onColorPickedControlPointChanged(bool isColorCtrlPnt) +{ + QColor color = _colorWidget->getColor(); + setButtonColor(ui->btnColor, color); + int alpha = _colorWidget->getAlpha(); + setButtonColor(ui->btnAlpha, QColor(alpha, alpha, alpha)); + + QString colorTex = _colorWidget->getColorTex(); + setButtonTex(ui->btnColorTex, !colorTex.isEmpty()); + QString alphaTex = _colorWidget->getAlphaTex(); + setButtonTex(ui->btnAlphaTex, !alphaTex.isEmpty()); + + _updateUIFromData = true; + ui->sliderColorFallOff->setValue(_colorWidget->getColorFallOff() * 100); + ui->sliderAlphaFallOff->setValue(_colorWidget->getAlphaFallOff() * 100); + _setColorUIEnable(isColorCtrlPnt); + _setAlphaUIEnable(!isColorCtrlPnt); + _updateUIFromData = false; +} + +void CurveEditorMainWindow::_saveAttribute(QDomElement& parentElm, CurveAttribute* attribute) +{ + QDomElement newElm = parentElm.ownerDocument().createElement(tr("Attribute")); + parentElm.appendChild(newElm); + newElm.setAttribute(tr("Name"), attribute->getName().c_str()); + newElm.setAttribute(tr("Color"), QString().setNum(attribute->color.rgba(), 16)); + if (!ui->checkBoxResamplePoints->isChecked()) + { + _saveCurve(newElm, attribute->curve); + } + else + { + _saveCurve(newElm, attribute->curve.resampleCurve(ui->spinBoxResamplePoints->value())); + } +} + +void CurveEditorMainWindow::_saveAttribute(QDomElement& parentElm, ColorAttribute* attribute) +{ + QDomElement newElm = parentElm.ownerDocument().createElement(tr("Attribute")); + parentElm.appendChild(newElm); + newElm.setAttribute(tr("Name"), attribute->getName().c_str()); + + _saveCurve(newElm, attribute->colorCurve, tr("ColorCurve")); + if (attribute->alphaCurve.getControlPointCount() > 0) + _saveCurve(newElm, attribute->alphaCurve, tr("AlphaCurve")); +} + +void CurveEditorMainWindow::_saveCurve(QDomElement& parentElm, Curve& curve) +{ + QDomDocument domDoc = parentElm.ownerDocument(); + QDomElement curveElm = domDoc.createElement(tr("Curve")); + parentElm.appendChild(curveElm); + curveElm.setAttribute(tr("MinValueX"), curve.getMinValue().x()); + curveElm.setAttribute(tr("MinValueY"), curve.getMinValue().y()); + curveElm.setAttribute(tr("MaxValueX"), curve.getMaxValue().x()); + curveElm.setAttribute(tr("MaxValueY"), curve.getMaxValue().y()); + + int ctrlPntCount = curve.getControlPointCount(); + for (int i = 0; i < ctrlPntCount; ++i) + { + const ControlPoint& ctrlPnt = curve.getControlPoint(i); + _saveCtrlPnt(curveElm, ctrlPnt); + } +} + +void CurveEditorMainWindow::_saveCurve(QDomElement& parentElm, ColorCurve& curve, const QString& curveName) +{ + QDomDocument domDoc = parentElm.ownerDocument(); + QDomElement curveElm = domDoc.createElement(curveName); + parentElm.appendChild(curveElm); + curveElm.setAttribute(tr("MinValue"), curve.getMinValue()); + curveElm.setAttribute(tr("MaxValue"), curve.getMaxValue()); + + int ctrlPntCount = curve.getControlPointCount(); + for (int i = 0; i < ctrlPntCount; ++i) + { + const ColorControlPoint& ctrlPnt = curve.getControlPoint(i); + _saveCtrlPnt(curveElm, ctrlPnt); + } +} + +void CurveEditorMainWindow::_saveCtrlPnt(QDomElement& parentElm, const ControlPoint& ctrlPnt) +{ + QDomDocument domDoc = parentElm.ownerDocument(); + QDomElement ctrlPntElm = domDoc.createElement(tr("ControlPoint")); + parentElm.appendChild(ctrlPntElm); + + QDomElement valueElm = domDoc.createElement(tr("Value")); + ctrlPntElm.appendChild(valueElm); + valueElm.setAttribute(tr("X"), ctrlPnt.value.x()); + valueElm.setAttribute(tr("Y"), ctrlPnt.value.y()); + + QDomElement modeElm = domDoc.createElement(tr("InterpolateMode")); + ctrlPntElm.appendChild(modeElm); + QDomNode txt = domDoc.createTextNode(InterpolateModeToString(ctrlPnt.mode)); + modeElm.appendChild(txt); + + if (eBezierSpline == ctrlPnt.mode) + { + QDomElement bezierSplineDataElm = domDoc.createElement(tr("BezierSplineData")); + ctrlPntElm.appendChild(bezierSplineDataElm); + + bezierSplineDataElm.setAttribute(tr("InTan"), QString("%0").arg(ctrlPnt.splineData.inTan)); + bezierSplineDataElm.setAttribute(tr("InLen"), QString("%0").arg(ctrlPnt.splineData.inLen)); + bezierSplineDataElm.setAttribute(tr("OutTan"), QString("%0").arg(ctrlPnt.splineData.outTan)); + bezierSplineDataElm.setAttribute(tr("OutLen"), QString("%0").arg(ctrlPnt.splineData.outLen)); + } +} + +void CurveEditorMainWindow::_saveCtrlPnt(QDomElement& parentElm, const ColorControlPoint& ctrlPnt) +{ + QDomDocument domDoc = parentElm.ownerDocument(); + QDomElement ctrlPntElm = domDoc.createElement(tr("ColorControlPoint")); + parentElm.appendChild(ctrlPntElm); + + QDomElement valueElm = domDoc.createElement(tr("Value")); + ctrlPntElm.appendChild(valueElm); + valueElm.setAttribute(tr("X"), ctrlPnt.x); + valueElm.setAttribute(tr("Color"), QString().setNum(ctrlPnt.color.rgba(), 16)); + valueElm.setAttribute(tr("Weight"), ctrlPnt.weight); + valueElm.setAttribute(tr("FallOff"), ctrlPnt.fallOff); + valueElm.setAttribute(tr("TexturePath"), ctrlPnt.texturePath.c_str()); + + QDomElement modeElm = domDoc.createElement(tr("InterpolateMode")); + ctrlPntElm.appendChild(modeElm); + QDomNode txt = domDoc.createTextNode(InterpolateModeToString(ctrlPnt.mode)); + modeElm.appendChild(txt); + + if (eBezierSpline == ctrlPnt.mode) + { + QDomElement bezierSplineDataElm = domDoc.createElement(tr("BezierSplineData")); + ctrlPntElm.appendChild(bezierSplineDataElm); + + bezierSplineDataElm.setAttribute(tr("InTan"), QString("%0").arg(ctrlPnt.splineData.inTan)); + bezierSplineDataElm.setAttribute(tr("InLen"), QString("%0").arg(ctrlPnt.splineData.inLen)); + bezierSplineDataElm.setAttribute(tr("OutTan"), QString("%0").arg(ctrlPnt.splineData.outTan)); + bezierSplineDataElm.setAttribute(tr("OutLen"), QString("%0").arg(ctrlPnt.splineData.outLen)); + } +} + +CurveAttributeBase* CurveEditorMainWindow::_loadAttribute(QDomElement& elm) +{ + QString name = elm.attribute(tr("Name")); + + QDomElement curveElm = elm.firstChildElement(tr("Curve")); + if (!curveElm.isNull()) + { + CurveAttribute* attribute = new CurveAttribute(""); + attribute->_name = name.toStdString(); + //qDebug()<<"attribute Name"<<name<<" Color:"<<elm.attribute(tr("Color")); + attribute->color.setRgba(elm.attribute(tr("Color")).toUInt(0, 16)); + //qDebug()<<"color:::"<<QString().setNum(attrData->color.rgba(), 16); + float minValueX = curveElm.attribute(tr("MinValueX")).toFloat(); + float minValueY = curveElm.attribute(tr("MinValueY")).toFloat(); + float maxValueX = curveElm.attribute(tr("MaxValueX")).toFloat(); + float maxValueY = curveElm.attribute(tr("MaxValueY")).toFloat(); + attribute->curve.initValueRange(QPointF(minValueX, minValueY), QPointF(maxValueX, maxValueY)); + _loadCurve(curveElm, attribute->curve); + + return attribute; + } + else + { + curveElm = elm.firstChildElement(tr("ColorCurve")); + + if (!curveElm.isNull()) + { + ColorAttribute* attribute = new ColorAttribute(""); + attribute->_name = name.toStdString(); + float minValue = curveElm.attribute(tr("MinValue")).toFloat(); + float maxValue = curveElm.attribute(tr("MaxValue")).toFloat(); + attribute->colorCurve.initValueRange(minValue, maxValue); + _loadCurve(curveElm, attribute->colorCurve); + + curveElm = elm.firstChildElement(tr("AlphaCurve")); + minValue = curveElm.attribute(tr("MinValue")).toFloat(); + maxValue = curveElm.attribute(tr("MaxValue")).toFloat(); + attribute->alphaCurve.initValueRange(minValue, maxValue); + _loadCurve(curveElm, attribute->alphaCurve); + return attribute; + } + } + + return nullptr; +} + +void CurveEditorMainWindow::_loadCurve(QDomElement& elm, Curve& curve) +{ + QDomNodeList nodeList = elm.elementsByTagName(tr("ControlPoint")); + for (int i = 0; i < nodeList.count(); ++i) + { + QDomElement ctrlElm = nodeList.at(i).toElement(); + + ControlPoint ctrlPnt; + if (!ctrlElm.isNull()) + { + _loadCtrlPnt(ctrlElm, ctrlPnt); + curve.appendControlPoint(ctrlPnt, false); + } + } +} + +void CurveEditorMainWindow::_loadCurve(QDomElement& elm, ColorCurve& curve) +{ + QDomNodeList nodeList = elm.elementsByTagName(tr("ColorControlPoint")); + for (int i = 0; i < nodeList.count(); ++i) + { + QDomElement ctrlElm = nodeList.at(i).toElement(); + + ColorControlPoint ctrlPnt; + if (!ctrlElm.isNull()) + { + _loadCtrlPnt(ctrlElm, ctrlPnt); + curve.appendControlPoint(ctrlPnt, false); + } + } +} + +void CurveEditorMainWindow::_loadCtrlPnt(QDomElement& elm, ControlPoint& ctrlPnt) +{ + QDomElement valueElm = elm.firstChildElement(tr("Value")); + ctrlPnt.value.setX(valueElm.attribute(tr("X")).toFloat()); + ctrlPnt.value.setY(valueElm.attribute(tr("Y")).toFloat()); + + QDomElement modeElm = elm.firstChildElement(tr("InterpolateMode")); + + ctrlPnt.mode = StringToInterpolateMode(modeElm.text()); + + if (eBezierSpline == ctrlPnt.mode) + { + QDomElement bezierElm = elm.firstChildElement(tr("BezierSplineData")); + + ctrlPnt.splineData.inTan = bezierElm.attribute(tr("InTan")).toFloat(); + ctrlPnt.splineData.inLen = bezierElm.attribute(tr("InLen")).toFloat(); + ctrlPnt.splineData.outTan = bezierElm.attribute(tr("OutTan")).toFloat(); + ctrlPnt.splineData.outLen = bezierElm.attribute(tr("OutLen")).toFloat(); + } +} + +void CurveEditorMainWindow::_loadCtrlPnt(QDomElement& elm, ColorControlPoint& ctrlPnt) +{ + QDomElement valueElm = elm.firstChildElement(tr("Value")); + ctrlPnt.x = valueElm.attribute(tr("X")).toFloat(); + ctrlPnt.color.setRgba(valueElm.attribute(tr("Color")).toUInt(0, 16)); + ctrlPnt.weight = valueElm.attribute(tr("Weight")).toFloat(); + ctrlPnt.fallOff = valueElm.attribute(tr("FallOff")).toFloat(); + ctrlPnt.weight = valueElm.attribute(tr("Weight")).toFloat(); + ctrlPnt.texturePath = valueElm.attribute(tr("TexturePath")).toStdString(); + + QDomElement modeElm = elm.firstChildElement(tr("InterpolateMode")); + + ctrlPnt.mode = StringToInterpolateMode(modeElm.text()); + + if (eBezierSpline == ctrlPnt.mode) + { + QDomElement bezierElm = elm.firstChildElement(tr("BezierSplineData")); + + ctrlPnt.splineData.inTan = bezierElm.attribute(tr("InTan")).toFloat(); + ctrlPnt.splineData.inLen = bezierElm.attribute(tr("InLen")).toFloat(); + ctrlPnt.splineData.outTan = bezierElm.attribute(tr("OutTan")).toFloat(); + ctrlPnt.splineData.outLen = bezierElm.attribute(tr("OutLen")).toFloat(); + } +} + +void CurveEditorMainWindow::_setTangentTypeUIStatus(bool enable) +{ + ui->actionTangent_Stepped->setEnabled(enable); + ui->actionTangent_Linear->setEnabled(enable); + ui->actionTangent_Smooth->setEnabled(enable); + ui->actionTangent_Ease_Out->setEnabled(enable); + ui->actionTangent_Ease_In->setEnabled(enable); + ui->actionTangent_Spline->setEnabled(enable); +} + +void CurveEditorMainWindow::_setAddRemoveCtrlPntUIStatus(bool enable) +{ + ui->actionAdd_Before_Selected->setEnabled(enable); + ui->actionAdd_After_Selected->setEnabled(enable); + ui->actionRemove_Selected->setEnabled(enable); + ui->actionAdd_Control_Point_By_Click->setEnabled(enable); + ui->actionRemove_Control_Point_By_Click->setEnabled(enable); +} + +} // namespace CurveEditor +} // namespace nvidia
\ No newline at end of file diff --git a/tools/CurveEditor/source/Internal/Window/CurveWidget.cpp b/tools/CurveEditor/source/Internal/Window/CurveWidget.cpp new file mode 100644 index 0000000..fc778e5 --- /dev/null +++ b/tools/CurveEditor/source/Internal/Window/CurveWidget.cpp @@ -0,0 +1,1229 @@ +#include "CurveWidget.h" + +#include <QtWidgets/QLabel> +#include <QtGui/QImage> +#include <QtWidgets/QVBoxLayout> +#include <QtGui/QMouseEvent> +#include <QtGui/QPaintEvent> +#include <QtGui/QPainter> +#include <QtGui/QPainterPath> +#include <QtCore/QDebug> +#include "CurveEditorMainWindow.h" + +namespace nvidia { +namespace CurveEditor { + +const int MARGIN_X = 2; +const int MARGIN_Y = 2; +const int SNAP_DISTANCE = 5; +const float CROSS_THRESHOLD = 5.0f; +const int GRID_INTIAL_SEGMENT_COUNT = 4; +const int CTRL_PNT_ICON_SIZE = 6; +const int CLICK_ON_CURVE_THRESHOLD = 4; +const int CURVE_WIDTH = 2; +const QColor GRID_COLOR = QColor(32, 32, 32, 64); + +////////////////////////////////////////////////////////////////////////////// +QPointF NDCToScreenCoord(QWidget* pWidget, QPointF p) +{ + int w = pWidget->width(); + int h = pWidget->height(); + + float x = MARGIN_X + p.x() * (w - MARGIN_X * 2.0f); + float y = h - MARGIN_Y * 2.0 + p.y() * (MARGIN_Y * 3.0f - h); + + return QPointF(x, y); +} + +////////////////////////////////////////////////////////////////////////////// +QPointF ScreenToNDC(QWidget* pWidget, QPointF p) +{ + int w = pWidget->width(); + int h = pWidget->height(); + + float sizey = 1.0f - 2.0f * MARGIN_Y; + + float x = (p.x() - MARGIN_X) / (2 - MARGIN_X * 2.0f); + float y = (MARGIN_Y * 2.0f + p.y() - h) / (MARGIN_Y * 3.0f - h); + + return QPointF(x, y); +} + +////////////////////////////////////////////////////////////////////////////// +bool IsInSelectedCtrlPnts(const std::vector<int>& pickedPoints, int pointIndex) +{ + for (std::vector<int>::const_iterator itr = pickedPoints.begin(); itr != pickedPoints.end(); ++itr) + { + if (*itr == pointIndex) + return true; + } + return false; +} + +////////////////////////////////////////////////////////////////////////////// +bool IsSamePoint(const QPointF& pntA, const QPointF& pntB, int threshold) +{ + float dx = pntB.x() - pntA.x(); + float dy = pntB.y() - pntA.y(); + + float r = sqrt(dx * dx + dy * dy); + if (r <= threshold) + return true; + else + return false; +} + +////////////////////////////////////////////////////////////////////////////// +int FindSelectedCtrlPnt(const std::vector<QPointF>& points, const QPointF& pickPos) +{ + for (size_t i = 0; i < points.size(); i++) + { + if (IsSamePoint(points[i], pickPos, CTRL_PNT_ICON_SIZE/2)) + return (int)i; + } + return -1; +} + +////////////////////////////////////////////////////////////////////////////// +CurveEntity::CurveEntity(CurveWidget* holder, CurveAttribute* attribute, const QColor& color) + : _holder(holder) + , _attribute(attribute) + , _curve(&(attribute->curve)) + , _color(color) + , _pickedPoint(-1) + , _pickedPoints() + , _lastMousePosScreen() + , _ctrlPntToRemove(-1) +{ + +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::setLocation(float location) +{ + if (_pickedPoints.size() != 1) + return ; + + ControlPoint pnt = _curve->getControlPoint(_pickedPoints[0]); + pnt.value.setX(location); + _curve->setControlPoint(_pickedPoints[0], pnt); + emit _holder->CurveAttributeChanged(_attribute); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::setValue(float value) +{ + if (_pickedPoints.size() != 1) + return ; + + ControlPoint pnt = _curve->getControlPoint(_pickedPoints[0]); + pnt.value.setY(value); + _curve->setControlPoint(_pickedPoints[0], pnt); + emit _holder->CurveAttributeChanged(_attribute); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::addControlPointsBeforeSelected() +{ + bool update = false; + for (std::vector<int>::iterator itr = _pickedPoints.begin(); itr != _pickedPoints.end(); ++itr) + { + if (*itr == 0) + continue; + + _curve->insertControlPointAt(*itr); + ++(*itr); + update = true; + + if (*itr <= _pickedPoint) + { + ++_pickedPoint; + } + + for (std::vector<int>::iterator itrRight = itr + 1; itrRight != _pickedPoints.end(); ++itrRight) + { + ++(*itrRight); + } + } + + if (update) + { + _curve->_needSample = true; + emit _holder->CurveAttributeChanged(_attribute); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::addControlPointsAfterSelected() +{ + bool update = false; + for (std::vector<int>::iterator itr = _pickedPoints.begin(); itr != _pickedPoints.end(); ++itr) + { + _curve->insertControlPointAt(*itr + 1); + update = true; + + if ((*itr + 1) < _pickedPoint) + { + ++_pickedPoint; + } + + for (std::vector<int>::iterator itrRight = itr + 1; itrRight != _pickedPoints.end(); ++itrRight) + { + ++(*itrRight); + } + } + + if (update) + { + _curve->_needSample = true; + emit _holder->CurveAttributeChanged(_attribute); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::removeSelectedControlPoints() +{ + if (_pickedPoints.size() > 0) + { + _curve->removeControlPoints(_pickedPoints); + _pickedPoints.clear(); + _pickedPoint = -1; + _curve->_needSample = true; + emit _holder->CurveAttributeChanged(_attribute); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::setTangentType(InterpolateMode mode) +{ + size_t pointsCount = _curve->getControlPointCount(); + for (int i = 0; i < pointsCount; i++) + { + if (IsInSelectedCtrlPnts(_pickedPoints, i)) + { + ControlPoint ctrlPnt = _curve->getControlPoint(i); + ctrlPnt.mode = mode; + _curve->setControlPoint(i, ctrlPnt); + emit _holder->CurveAttributeChanged(_attribute); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::setSmoothTangent() +{ + size_t pointsCount = _curve->getControlPointCount(); + for (int i = 0; i < pointsCount; i++) + { + if (IsInSelectedCtrlPnts(_pickedPoints, i) && i != pointsCount - 1) + { + ControlPoint ctrlctrlPntFront = _curve->getControlPoint(i); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 1.0; + ctrlctrlPntFront.splineData.outTan = 0; + _curve->setControlPoint(i, ctrlctrlPntFront); + + ControlPoint ctrlPntBehiand = _curve->getControlPoint(i + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 1.0; + ctrlPntBehiand.splineData.inTan = 0.0; + _curve->setControlPoint(i + 1, ctrlPntBehiand); + + emit _holder->CurveAttributeChanged(_attribute); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::setEaseInTangent() +{ + size_t pointsCount = _curve->getControlPointCount(); + for (int i = 0; i < pointsCount; i++) + { + if (IsInSelectedCtrlPnts(_pickedPoints, i) && i != pointsCount - 1) + { + ControlPoint ctrlctrlPntFront = _curve->getControlPoint(i); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 0.0; + ctrlctrlPntFront.splineData.outTan = 0; + _curve->setControlPoint(i, ctrlctrlPntFront); + + ControlPoint ctrlPntBehiand = _curve->getControlPoint(i + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 1.0; + ctrlPntBehiand.splineData.inTan = 0; + _curve->setControlPoint(i + 1, ctrlPntBehiand); + + emit _holder->CurveAttributeChanged(_attribute); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::setEaseOutTangent() +{ + size_t pointsCount = _curve->getControlPointCount(); + for (int i = 0; i < pointsCount; i++) + { + if (IsInSelectedCtrlPnts(_pickedPoints, i) && i != pointsCount - 1) + { + ControlPoint ctrlctrlPntFront = _curve->getControlPoint(i); + ctrlctrlPntFront.mode = eBezierSpline; + ctrlctrlPntFront.splineData.outLen = 1.0; + ctrlctrlPntFront.splineData.outTan = 0; + _curve->setControlPoint(i, ctrlctrlPntFront); + + ControlPoint ctrlPntBehiand = _curve->getControlPoint(i + 1); + ctrlPntBehiand.mode = eBezierSpline; + ctrlPntBehiand.splineData.inLen = 0.0; + ctrlPntBehiand.splineData.inTan = 0; + _curve->setControlPoint(i + 1, ctrlPntBehiand); + + emit _holder->CurveAttributeChanged(_attribute); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +int CurveEntity::getControlPointCount() +{ + return _curve->getControlPointCount(); +} + +////////////////////////////////////////////////////////////////////////////// +QRectF CurveEntity::getBoundingBox() +{ + return QRectF(_curve->getMinValue(), _curve->getMaxValue()); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::mousePressEvent( QMouseEvent* e, bool& pickedPoint) +{ + if (!(e->modifiers() & Qt::ControlModifier)) + { + _pickedPoints.clear(); + } + + std::vector<QPointF> points; + _makePoints(points); + QPoint mousePos = e->pos(); + _lastMousePosScreen = mousePos; + + _pickedPoint = FindSelectedCtrlPnt(points, mousePos); + if (-1 != _pickedPoint) + { + if (_holder->_canRemoveCtrlPntByClick && _attribute->canAddRemoveControlPoint()) + { + _curve->removeControlPoint(_pickedPoint); + _pickedPoint = -1; + return; + } + pickedPoint = true; + } + else + { + if (_holder->_canAddCtrlPntByClick) + { + _addCtrlPntByClick(mousePos); + } + return ; + } + + std::vector<int>::iterator itr = _pickedPoints.begin(); + for (; itr != _pickedPoints.end(); ++itr) + { + if (*itr == _pickedPoint) + break; + else if (*itr > _pickedPoint) + { + itr = _pickedPoints.insert(itr, _pickedPoint); + break; + } + } + + if (itr == _pickedPoints.end()) + { + _pickedPoints.insert(itr, _pickedPoint); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::mouseReleaseEvent( QMouseEvent* e ) +{ +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::mouseMoveEvent( QMouseEvent* e ) +{ + Qt::MouseButton buttons = e->button(); + + { + //if (_pickedPoint >= 0) + QPointF mousePosScreen = e->pos(); + QPointF deltaPosScreen = mousePosScreen - _lastMousePosScreen; + QPointF destinationPosScreen = mousePosScreen; + _lastMousePosScreen = mousePosScreen; + std::vector<int>::iterator itr = _pickedPoints.begin(); + for (; itr != _pickedPoints.end(); ++itr) + { + int pickedPoint = *itr; + ControlPoint pickedCtrlPnt = _curve->getControlPoint(pickedPoint); + QPointF ctrlPntLastScreenPos = _holder->_valueToScreen(pickedCtrlPnt.value); + + destinationPosScreen = ctrlPntLastScreenPos + deltaPosScreen; + destinationPosScreen = _holder->_getSnapSreenPos(destinationPosScreen); + + if (!_attribute->canMoveControlPointHorizontally()) + destinationPosScreen.setX(ctrlPntLastScreenPos.x()); + else + { + // make sure this picked control point not move accross other control point + if (pickedPoint == 0) + { + QPointF nextCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint + 1).value); + if (destinationPosScreen.x() > (nextCtrlPntScreenPos.x() - CROSS_THRESHOLD)) + destinationPosScreen.setX(nextCtrlPntScreenPos.x() - CROSS_THRESHOLD); + } + else if (pickedPoint == (_curve->getControlPointCount() - 1) ) + { + QPointF fomerCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint - 1).value); + if (destinationPosScreen.x() < (fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD)) + destinationPosScreen.setX(fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD); + } + else + { + QPointF fomerCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint - 1).value); + QPointF nextCtrlPntScreenPos = _holder->_valueToScreen(_curve->getControlPoint(pickedPoint + 1).value); + if (destinationPosScreen.x() < (fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD)) + destinationPosScreen.setX(fomerCtrlPntScreenPos.x() + CROSS_THRESHOLD); + if (destinationPosScreen.x() > (nextCtrlPntScreenPos.x() - CROSS_THRESHOLD)) + destinationPosScreen.setX(nextCtrlPntScreenPos.x() - CROSS_THRESHOLD); + } + } + + QPointF p = _holder->_screenToValue(destinationPosScreen); + + QPointF min = _curve->getMinValue(); + QPointF max = _curve->getMaxValue(); + + //make control point move in value range + { + if (p.x() < min.x()) + p.setX(min.x()); + else if (p.x() > max.x()) + p.setX(max.x()); + + if (p.y() < min.y()) + p.setY(min.y()); + else if (p.y() > max.y()) + p.setY(max.y()); + } + + pickedCtrlPnt.value = p; + _curve->setControlPoint(pickedPoint, pickedCtrlPnt); + emit _holder->PickedControlPointValueChanged(p); + + emit _holder->CurveAttributeChanged(_attribute); + } + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::draw(QPainter &painter) +{ + std::vector<QPointF> points; + _makePoints(points); + + _drawCurve(painter); + + _drawPoints(points, painter, _pickedPoints); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::_drawCurve(QPainter &painter) +{ + painter.save(); + + { + QPen pen( Qt::black ); + pen.setColor(_color); + pen.setWidth(CURVE_WIDTH); + pen.setStyle(Qt::SolidLine); + + painter.setPen(pen); + painter.setRenderHint(QPainter::Antialiasing, false); + } + + QPainterPath path; + + std::vector<QPointF> samplePoints = _curve->getSamplePoints(); + path.moveTo(_holder->_valueToScreen(samplePoints[0])); + + for (size_t i = 0; i < samplePoints.size(); ++i) + { + path.lineTo(_holder->_valueToScreen(samplePoints[i])); + } + painter.drawPath(path); + + painter.restore(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::_makePoints(std::vector<QPointF>& points) +{ + size_t ctrlPntsCount = _curve->getControlPointCount(); + for (int i = 0; i < ctrlPntsCount; i++) + points.push_back( _holder->_valueToScreen(_curve->getControlPoint(i).value) ); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::_drawPoints(const std::vector<QPointF>& points, QPainter &painter, const std::vector<int>& pickedPoints) +{ + { + QPen pen( Qt::black ); + pen.setColor(QColor(255,255,255)); + pen.setWidth(6); + pen.setStyle(Qt::SolidLine); + + painter.setPen(pen); + painter.setRenderHint(QPainter::Antialiasing, false); + } + + for (int i = 0; i < points.size(); i++) + { + QPen pen( Qt::black ); + pen.setWidth(CTRL_PNT_ICON_SIZE); + pen.setStyle(Qt::SolidLine); + + if (IsInSelectedCtrlPnts(pickedPoints,i)) + pen.setColor(QColor(255,0,0)); + else + pen.setColor(QColor(255,255,255)); + + painter.setPen(pen); + painter.drawPoint( points[i] ); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveEntity::_addCtrlPntByClick(const QPointF& mouseScreenPos) +{ + if (!_attribute->canAddRemoveControlPoint()) + return ; + + QPointF pos= _holder->_screenToValue(mouseScreenPos); + + QPointF pntOnCurve = _curve->getPointByX(pos.x()); + QPointF pntOnCurveScreen = _holder->_valueToScreen(pntOnCurve); + + if ( IsSamePoint(mouseScreenPos, pntOnCurveScreen, CLICK_ON_CURVE_THRESHOLD) ) + { + _pickedPoint = _curve->appendControlPoint(pntOnCurve.x()); + _holder->update(); + } + +} + +////////////////////////////////////////////////////////////////////////////// +bool CurveEntity::_canRemoveCtrlPntByRightClick(const QPointF& mouseScreenPos) +{ + std::vector<QPointF> points; + _makePoints(points); + + _ctrlPntToRemove = FindSelectedCtrlPnt(points, mouseScreenPos); + + if ( !_attribute->canAddRemoveControlPoint() + || (-1 == _ctrlPntToRemove) + || 2 == _curve->_controlPoints.size() && -1 != _ctrlPntToRemove) + { + return false; + } + else + return true; +} + +void CurveEntity::_removeCtrlPntByRightClick() +{ + if (-1 != _ctrlPntToRemove && _attribute->canAddRemoveControlPoint()) + { + _curve->removeControlPoint(_ctrlPntToRemove); + } + _ctrlPntToRemove = -1; + _pickedPoint = -1; + _pickedPoints.clear(); +} + +////////////////////////////////////////////////////////////////////////////// +CurveWidget::CurveWidget(QWidget* parent) + : QFrame(parent) + , _parent(parent) + , _moveCrossOtherCtrlPnt(false) + , _moveCtrlPnt(false) + , _pan(false) + , _snapHorizontal(false) + , _snapVertical(false) + , _canAddCtrlPntByClick(false) + , _canRemoveCtrlPntByClick(false) + , _curveFitWindowScale(1.0, 1.0) + , _curveFitWindowOffset(0.0, 0.0) + , _curveScaleLevel(1.0, 1.0) + , _contextMenu(nullptr) + , _removeCtrlPntAction(nullptr) +{ + setFocusPolicy(Qt::ClickFocus ); + //QString focusStyle = QString("QFrame:focus { border:1px solid #FF0000; }"); + //setStyleSheet(focusStyle); + + setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(onShowContextMenu(const QPoint&))); + + _contextMenu = new QMenu(this);; + _removeCtrlPntAction = new QAction(this); + _removeCtrlPntAction->setText(tr("Remove Control Point")); + _contextMenu->addAction(_removeCtrlPntAction); + + connect(_removeCtrlPntAction, SIGNAL(triggered()), this, SLOT(onRemoveControlPoint()) ); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::onShowContextMenu(const QPoint& pos) +{ + bool enableRemoveCtrlPntAction = false; + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + if (curveEntity._canRemoveCtrlPntByRightClick(pos)) + enableRemoveCtrlPntAction = true; + } + + _removeCtrlPntAction->setEnabled(enableRemoveCtrlPntAction); + _contextMenu->exec(QCursor::pos()); +} + +void CurveWidget::onRemoveControlPoint() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity._removeCtrlPntByRightClick(); + } + + std::vector<CurveEntity*> pickedCurves; + emit PickedControlPointChanged(pickedCurves); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::paintEvent(QPaintEvent * e) +{ + QFrame::paintEvent(e); + + QPainter painter(this); + painter.setRenderHints(QPainter::Antialiasing, true); + + _drawGrid(painter); + + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.draw(painter); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::resizeEvent(QResizeEvent* e) +{ + _updateCurveFitWindowPara(); + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::mousePressEvent( QMouseEvent* e ) +{ + if (e->buttons() == Qt::MiddleButton) + { + setCursor(Qt::OpenHandCursor); + _mousePressScreenPos = QPointF(e->pos().x(), e->pos().y()); + _pan = true; + } + else + { + std::vector<CurveEntity*> pickedCurves; + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.mousePressEvent(e, _moveCtrlPnt); + if (curveEntity.getPickedControlPointIndexes().size() > 0) + pickedCurves.push_back(&curveEntity); + } + + emit PickedControlPointChanged(pickedCurves); + + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::mouseReleaseEvent( QMouseEvent* e ) +{ + if (_moveCtrlPnt) + { + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.mouseReleaseEvent(e); + } + } + else if (_pan) + { + setCursor(Qt::ArrowCursor); + _curOrinScreenPos = _lastOrinScreenPos + (QPointF(e->pos().x() - _mousePressScreenPos.x(), _mousePressScreenPos.y() - e->pos().y())); + _lastOrinScreenPos = _curOrinScreenPos; + _updateCurveFitWindowPara(); + + } + + _moveCtrlPnt = false; + _pan = false; + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::mouseMoveEvent( QMouseEvent* e ) +{ + if (_moveCtrlPnt) + { + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.mouseMoveEvent(e); + } + } + else if (e->buttons() & Qt::MiddleButton) + { + _curOrinScreenPos = _lastOrinScreenPos + (QPointF(e->pos().x() - _mousePressScreenPos.x(), _mousePressScreenPos.y() - e->pos().y())); + _updateCurveFitWindowPara(); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::wheelEvent(QWheelEvent *e) +{ + int numDegrees = e->delta() / 8; + + float zoom = 1.0 + numDegrees / 360.0f; + _curveScaleLevel.setX(_curveScaleLevel.x() * zoom); + _curveScaleLevel.setY(_curveScaleLevel.y() * zoom); + + _updateCurveFitWindowPara(); + update(); + e->accept(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::keyPressEvent(QKeyEvent *e) +{ + bool move = false; + switch(e->key()) + { + case Qt::Key_Left: + _curOrinScreenPos = _lastOrinScreenPos + QPointF(-1.0f, 0.0f); + _lastOrinScreenPos = _curOrinScreenPos; + move = true; + break; + case Qt::Key_Up: + _curOrinScreenPos = _lastOrinScreenPos + QPointF(0.0f, 1.0f); + _lastOrinScreenPos = _curOrinScreenPos; + move = true; + break; + case Qt::Key_Right: + _curOrinScreenPos = _lastOrinScreenPos + QPointF(1.0f, 0.0f); + _lastOrinScreenPos = _curOrinScreenPos; + move = true; + break; + case Qt::Key_Down: + _curOrinScreenPos = _lastOrinScreenPos + QPointF(0.0f, -1.0f); + _lastOrinScreenPos = _curOrinScreenPos; + move = true; + break; + } + + if (move) + { + _updateCurveFitWindowPara(); + update(); + } +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::setLocation(float location) +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.setLocation(location); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::setValue(float value) +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.setValue(value); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::setCurveAttributes(std::vector<CurveAttributeBase*> attributes) +{ + _curves.clear(); + + for (std::vector<CurveAttributeBase*>::iterator itr = attributes.begin(); itr != attributes.end(); ++itr) + { + CurveAttributeBase* attribute = *itr; + if (attribute->getType() == eSingleAttr) + { + CurveAttribute* attributeSpecific = static_cast<CurveAttribute*>(attribute); + + CurveEntity curveEntity(this, attributeSpecific, attributeSpecific->color); + _curves.push_back(curveEntity); + } + else if (attribute->getType() == eGroupAttr) + { + CurveAttributeGroup* attributeGroup = static_cast<CurveAttributeGroup*>(attribute); + size_t countAttributesInGroup = attributeGroup->attributes.size(); + for (size_t i = 0; i < countAttributesInGroup; ++i) + { + CurveAttribute* attributeInGroup = attributeGroup->attributes[i]; + + CurveEntity curveEntity(this, attributeInGroup, attributeInGroup->color); + _curves.push_back(curveEntity); + } + } + } + + _updateCurveFitWindowPara(); + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::reset() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity._attribute->curve.reset(); + emit CurveAttributeChanged(curveEntity._attribute); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::addControlPointsBeforeSelected() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.addControlPointsBeforeSelected(); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::addControlPointsAfterSelected() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.addControlPointsAfterSelected(); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::removeSelectedControlPoints() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.removeSelectedControlPoints(); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::setTangentType(InterpolateMode mode) +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.setTangentType(mode); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::setSmoothTangent() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.setSmoothTangent(); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::setEaseInTangent() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.setEaseInTangent(); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::setEaseOutTangent() +{ + size_t curveCount = _curves.size(); + for (size_t i = 0; i < curveCount; ++i) + { + CurveEntity& curveEntity = _curves[i]; + curveEntity.setEaseOutTangent(); + } + + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::increaseCurveScaleHorizontally() +{ + _curveScaleLevel.setX(_curveScaleLevel.x() * 2); + _updateCurveFitWindowPara(); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::decreaseCurveScaleHorizontally() +{ + _curveScaleLevel.setX(_curveScaleLevel.x() / 2); + _updateCurveFitWindowPara(); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::increaseCurveScaleVertically() +{ + _curveScaleLevel.setY(_curveScaleLevel.y() * 2); + _updateCurveFitWindowPara(); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::decreaseCurveScaleVertically() +{ + _curveScaleLevel.setY(_curveScaleLevel.y() / 2); + _updateCurveFitWindowPara(); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::frameCurveScaleHorizontally() +{ + _curveScaleLevel.setX(1.0f); + _curOrinScreenPos.setX(0); + _lastOrinScreenPos.setX(0); + _updateCurveFitWindowPara(); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::frameCurveScaleVertically() +{ + _curveScaleLevel.setY(1.0f); + _curOrinScreenPos.setY(0); + _lastOrinScreenPos.setY(0); + _updateCurveFitWindowPara(); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::frameCurveScale() +{ + _curveScaleLevel.setX(1.0f); + _curveScaleLevel.setY(1.0f); + _curOrinScreenPos = QPointF(0,0); + _lastOrinScreenPos = QPointF(0,0); + _updateCurveFitWindowPara(); + update(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::_updateCurveFitWindowPara() +{ + QRect winSize = rect(); + + float minX = 0; + float minY = 0; + float maxX = 0; + float maxY = 0; + + for (size_t i = 0; i < _curves.size(); ++i) + { + CurveEntity& curveEntity = _curves[i]; + + QRectF boundingBox = curveEntity.getBoundingBox(); + + if (minX > boundingBox.x()) + minX = boundingBox.x(); + + if (minY > boundingBox.y()) + minY = boundingBox.y(); + + if (maxX < boundingBox.right()) + maxX = boundingBox.right(); + + if (maxY < boundingBox.bottom()) + maxY = boundingBox.bottom(); + } + + float curveWidth = maxX - minX; + float curveHeight = maxY - minY; + + if (0 == curveWidth && 0 == curveHeight) + { + curveWidth = 1.0; + curveHeight = 1.0; + } + else if (0 == curveWidth) + { + curveWidth = curveHeight; + } + else if (0 == curveHeight) + { + curveHeight = curveWidth; + } + + float widthScale = (winSize.width() - MARGIN_X * 2.0f) / curveWidth; + float heightScale = (MARGIN_Y * 2.0f - winSize.height()) / curveHeight; + _curveFitWindowScale = QPointF(widthScale, heightScale); + + float widthOffset = MARGIN_X + _curOrinScreenPos.x() - minX * widthScale * _curveScaleLevel.x(); + float heightOffset = (winSize.height() - MARGIN_Y - _curOrinScreenPos.y())- minY * heightScale * _curveScaleLevel.y(); + _curveFitWindowOffset = QPointF(widthOffset, heightOffset); +} + +////////////////////////////////////////////////////////////////////////////// +QPointF CurveWidget::_valueToScreen(const QPointF& pnt) +{ + QPointF curveScale = QPointF(_curveFitWindowScale.x() * _curveScaleLevel.x(), _curveFitWindowScale.y() * _curveScaleLevel.y()); + + float x = pnt.x() * curveScale.x() + _curveFitWindowOffset.x(); + float y = pnt.y() * curveScale.y() + _curveFitWindowOffset.y(); + return QPointF(x, y); +} + +////////////////////////////////////////////////////////////////////////////// +QPointF CurveWidget::_screenToValue(const QPointF& pnt) +{ + QPointF curveScale = QPointF(_curveFitWindowScale.x() * _curveScaleLevel.x(), _curveFitWindowScale.y() * _curveScaleLevel.y()); + + float x = (pnt.x() - _curveFitWindowOffset.x()) / curveScale.x(); + float y = (pnt.y() - _curveFitWindowOffset.y()) / curveScale.y(); + + return QPointF(x, y); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::_drawAxis(QPainter &painter) +{ + painter.save(); + { + QPen pen( Qt::black ); + pen.setColor(GRID_COLOR); + pen.setWidth(2); + pen.setStyle(Qt::SolidLine); + + painter.setPen(pen); + painter.setRenderHint(QPainter::Antialiasing, false); + } + + { + int w = width() - MARGIN_X * 2; + int h = height() - MARGIN_Y * 2; + + QPainterPath path; + + QPointF x = _dragedCoordinateToScreen(QPointF(w, 0)); + QPointF y = _dragedCoordinateToScreen(QPointF(0, h)); + + path.moveTo(_dragedCoordinateToScreen(QPointF(0, 0))); + path.lineTo(x); + path.moveTo(_dragedCoordinateToScreen(QPointF(0, 0))); + path.lineTo(y); + + painter.drawPath(path); + } + + painter.restore(); +} + +////////////////////////////////////////////////////////////////////////////// +void CurveWidget::_drawGrid(QPainter &painter) +{ + painter.save(); + { + QPen pen( Qt::black ); + pen.setColor(GRID_COLOR); + pen.setWidth(1); + pen.setStyle(Qt::SolidLine); + + painter.setPen(pen); + painter.setRenderHint(QPainter::Antialiasing, false); + } + + { + QPainterPath path; + + int w = width() - MARGIN_X * 2; + int h = height() - MARGIN_Y * 2; + + QPointF newOri = _dragedCoordinateToScreen(_curOrinScreenPos); + + float width = w; + float height = h; + int gridXSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.x(); + int gridYSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.y(); + + if (_curveScaleLevel.x() > 1) + { + width = w * _curveScaleLevel.x(); + gridXSegmentCount *= _curveScaleLevel.x(); + } + + if (_curveScaleLevel.y() > 1) + { + height = h * _curveScaleLevel.y(); + gridYSegmentCount *= _curveScaleLevel.y(); + } + + // draw horizontal lines + for (int i = 0 - gridXSegmentCount; i <= gridXSegmentCount * 2; ++i) + { + QPointF bottom = _dragedCoordinateToScreen(QPointF(width * i / (float)gridXSegmentCount, -height)); + QPointF up = _dragedCoordinateToScreen(QPointF(width * i / (float)gridXSegmentCount, height * 2)); + path.moveTo(bottom); + path.lineTo(up); + + painter.drawPath(path); + } + + // draw vertical lines + for (int i = 0 - gridYSegmentCount; i <= gridYSegmentCount * 2; ++i) + { + QPointF left = _dragedCoordinateToScreen(QPointF(-width, i * height / (float)gridYSegmentCount)); + QPointF right = _dragedCoordinateToScreen(QPointF(2 * width, i * height / (float)gridYSegmentCount)); + path.moveTo(left); + path.lineTo(right); + + painter.drawPath(path); + } + + } + painter.restore(); +} + +////////////////////////////////////////////////////////////////////////////// +QPointF CurveWidget::_getSnapSreenPos(const QPointF& mouseScreenPos) +{ + int w = width() - MARGIN_X * 2; + int h = height() - MARGIN_Y * 2; + + QPointF pos = _screenToDragedCoordinate(mouseScreenPos); + + // snap horizontally + if (_snapHorizontal) + { + int gridXSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.x(); + if (gridXSegmentCount < 2) + gridXSegmentCount = 2; + for (int i = 0; i <= gridXSegmentCount; ++i) + { + if (abs(i * w / gridXSegmentCount - pos.x()) <= SNAP_DISTANCE ) + { + pos.setX(i * w / gridXSegmentCount); + break; + } + } + } + + // snap vertically + if (_snapVertical) + { + int gridYSegmentCount = GRID_INTIAL_SEGMENT_COUNT / _curveScaleLevel.y(); + if (gridYSegmentCount < 2) + gridYSegmentCount = 2; + for (int i = 0; i <= gridYSegmentCount; ++i) + { + if (abs(i * h / gridYSegmentCount - pos.y()) <= SNAP_DISTANCE) + { + pos.setY(i * h / gridYSegmentCount); + } + } + } + + return _dragedCoordinateToScreen(pos); +} + +////////////////////////////////////////////////////////////////////////////// +QPointF CurveWidget::_dragedCoordinateToScreen(const QPointF& pnt) +{ + float x = pnt.x() + MARGIN_X + _curOrinScreenPos.x(); + float y = height() - MARGIN_Y - pnt.y() - _curOrinScreenPos.y(); + return QPointF(x, y); +} + +////////////////////////////////////////////////////////////////////////////// +QPointF CurveWidget::_screenToDragedCoordinate(const QPointF& pnt) +{ + float x = pnt.x() - MARGIN_X - _curOrinScreenPos.x(); + float y = height() - MARGIN_Y - pnt.y() - _curOrinScreenPos.y(); + return QPointF(x, y); +} + +} // namespace CurveEditor +} // namespace nvidia
\ No newline at end of file diff --git a/tools/CurveEditor/source/Internal/Window/CurveWidget.h b/tools/CurveEditor/source/Internal/Window/CurveWidget.h new file mode 100644 index 0000000..04c38d0 --- /dev/null +++ b/tools/CurveEditor/source/Internal/Window/CurveWidget.h @@ -0,0 +1,158 @@ +#ifndef CurveWidget_h__ +#define CurveWidget_h__ + +#include <QtWidgets/QWidget> +#include <QtWidgets/QFrame> +#include <QtWidgets/QLabel> +#include <QtWidgets/QMenu> +#include <QtWidgets/QAction> +#include <vector> +#include "Curve.h" + +namespace nvidia { +namespace CurveEditor { + +class CurveAttributeBase; +class CurveAttribute; +class CurveWidget; + +class CurveEntity +{ + friend class CurveWidget; + friend class CurveEditorMainWindow; +public: + CurveEntity(CurveWidget* holder, CurveAttribute* attribute, const QColor& color); + + void setLocation(float location); + void setValue(float value); + + void addControlPointsBeforeSelected(); + void addControlPointsAfterSelected(); + void removeSelectedControlPoints(); + void setTangentType(InterpolateMode mode); + void setSmoothTangent(); + void setEaseInTangent(); + void setEaseOutTangent(); + + int getControlPointCount(); + int getPickedControlPointIndex() { return _pickedPoint; } + std::vector<int>& getPickedControlPointIndexes() { return _pickedPoints; } + + QRectF getBoundingBox(); + + void mousePressEvent(QMouseEvent* e, bool& pickedPoint); + void mouseReleaseEvent(QMouseEvent* e); + void mouseMoveEvent(QMouseEvent* e); + + void draw(QPainter &painter); + +private: + void _drawCurve(QPainter &painter); + void _makePoints(std::vector<QPointF>& points); + void _drawPoints(const std::vector<QPointF>& points, QPainter &painter, const std::vector<int>& pickedPoints); + void _addCtrlPntByClick(const QPointF& mouseScreenPos); + bool _canRemoveCtrlPntByRightClick(const QPointF& mouseScreenPos); + void _removeCtrlPntByRightClick(); + + CurveWidget* _holder; + CurveAttribute* _attribute; + Curve* _curve; + QColor _color; + int _pickedPoint; + std::vector<int> _pickedPoints; + QPointF _lastMousePosScreen; + int _ctrlPntToRemove; +}; + +class CurveWidget : public QFrame +{ + Q_OBJECT + + friend class CurveEntity; + +public: + explicit CurveWidget(QWidget* parent); + + void setLocation(float location); + void setValue(float value); + + void setCurveAttributes(std::vector<CurveAttributeBase*> attributes); + void reset(); + + void addControlPointsBeforeSelected(); + void addControlPointsAfterSelected(); + void removeSelectedControlPoints(); + void setTangentType(InterpolateMode mode); + void setSmoothTangent(); + void setEaseInTangent(); + void setEaseOutTangent(); + + void setSnapAll() { _snapHorizontal = true; _snapVertical = true; } + void setSnapHorizontal() { _snapHorizontal = true; _snapVertical = false; } + void setSnapVertical() { _snapHorizontal = false; _snapVertical = true; } + + void increaseCurveScaleHorizontally(); + void decreaseCurveScaleHorizontally(); + void increaseCurveScaleVertically(); + void decreaseCurveScaleVertically(); + void frameCurveScaleHorizontally(); + void frameCurveScaleVertically(); + void frameCurveScale(); + + void setAddCtrlPntByClick(bool value) { _canAddCtrlPntByClick = value; } + void setRemoveCtrlPntByClick(bool value) { _canRemoveCtrlPntByClick = value; } + +signals: + void PickedControlPointValueChanged(QPointF& value); + void PickedControlPointChanged(const std::vector<CurveEntity*> pickedCurves); + void CurveAttributeChanged(nvidia::CurveEditor::CurveAttribute* attribute); + +private slots: + void onShowContextMenu(const QPoint& pos); + void onRemoveControlPoint(); + +private: + // QWidget events + virtual void paintEvent(QPaintEvent * e); + virtual void resizeEvent(QResizeEvent* e); + + virtual void mousePressEvent(QMouseEvent* e); + virtual void mouseReleaseEvent(QMouseEvent* e); + virtual void mouseMoveEvent(QMouseEvent* e); + virtual void wheelEvent(QWheelEvent *e); + virtual void keyPressEvent(QKeyEvent *e); + + void _updateCurveFitWindowPara(); + QPointF _valueToScreen(const QPointF& pnt); + QPointF _screenToValue(const QPointF& pnt); + void _drawAxis(QPainter &painter); + void _drawGrid(QPainter &painter); + QPointF _getSnapSreenPos(const QPointF& mouseScreenPos); + QPointF _dragedCoordinateToScreen(const QPointF& pnt); + QPointF _screenToDragedCoordinate(const QPointF& pnt); + +private: + QWidget* _parent; + bool _moveCrossOtherCtrlPnt;// whether can move control point across other control points + bool _moveCtrlPnt; + bool _pan; + bool _snapHorizontal; + bool _snapVertical; + bool _canAddCtrlPntByClick; + bool _canRemoveCtrlPntByClick; + std::vector<CurveEntity> _curves; + QPointF _curveFitWindowScale; + QPointF _curveFitWindowOffset; + QPointF _curveScaleLevel; + QPointF _mousePressScreenPos; + QPointF _lastOrinScreenPos; + QPointF _curOrinScreenPos; + + QMenu* _contextMenu; + QAction* _removeCtrlPntAction; +}; + +} // namespace CurveEditor +} // namespace nvidia + +#endif // CurveWidget_h__ |