diff --git a/app/common/bezier.cpp b/app/common/bezier.cpp index a1d900d57..b1a5f5fba 100644 --- a/app/common/bezier.cpp +++ b/app/common/bezier.cpp @@ -26,6 +26,36 @@ namespace olive { +Bezier::Bezier() : + x_(0), + y_(0), + cp1_x_(0), + cp1_y_(0), + cp2_x_(0), + cp2_y_(0) +{ +} + +Bezier::Bezier(double x, double y) : + x_(x), + y_(y), + cp1_x_(0), + cp1_y_(0), + cp2_x_(0), + cp2_y_(0) +{ +} + +Bezier::Bezier(double x, double y, double cp1_x, double cp1_y, double cp2_x, double cp2_y) : + x_(x), + y_(y), + cp1_x_(cp1_x), + cp1_y_(cp1_y), + cp2_x_(cp2_x), + cp2_y_(cp2_y) +{ +} + double Bezier::QuadraticXtoT(double x, double a, double b, double c) { // Clamp to prevent infinite loop diff --git a/app/common/bezier.h b/app/common/bezier.h index 16705901f..776c72436 100644 --- a/app/common/bezier.h +++ b/app/common/bezier.h @@ -22,6 +22,7 @@ #define BEZIER_H #include +#include #include "common/define.h" @@ -30,6 +31,39 @@ namespace olive { class Bezier { public: + Bezier(); + Bezier(double x, double y); + Bezier(double x, double y, double cp1_x, double cp1_y, double cp2_x, double cp2_y); + + const double &x() const {return x_; } + const double &y() const {return y_; } + const double &cp1_x() const { return cp1_x_; } + const double &cp1_y() const { return cp1_y_; } + const double &cp2_x() const { return cp2_x_; } + const double &cp2_y() const { return cp2_y_; } + + QPointF ToPointF() const + { + return QPointF(x_, y_); + } + + QPointF ControlPoint1ToPointF() const + { + return QPointF(cp1_x_, cp1_y_); + } + + QPointF ControlPoint2ToPointF() const + { + return QPointF(cp2_x_, cp2_y_); + } + + void set_x(const double &x) { x_ = x; } + void set_y(const double &y) { y_ = y; } + void set_cp1_x(const double &cp1_x) { cp1_x_ = cp1_x; } + void set_cp1_y(const double &cp1_y) { cp1_y_ = cp1_y; } + void set_cp2_x(const double &cp2_x) { cp2_x_ = cp2_x; } + void set_cp2_y(const double &cp2_y) { cp2_y_ = cp2_y; } + static double QuadraticXtoT(double x, double a, double b, double c); static double QuadraticTtoY(double a, double b, double c, double t); @@ -51,8 +85,19 @@ public: private: static double CalculateTFromX(bool cubic, double x, double a, double b, double c, double d); + double x_; + double y_; + + double cp1_x_; + double cp1_y_; + + double cp2_x_; + double cp2_y_; + }; } +Q_DECLARE_METATYPE(olive::Bezier); + #endif // BEZIER_H diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index e962aaef1..451430403 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -21,7 +21,6 @@ #include "polygon.h" #include -#include #include #include "common/cpuoptimize.h" @@ -33,7 +32,7 @@ const QString PolygonGenerator::kColorInput = QStringLiteral("color_in"); PolygonGenerator::PolygonGenerator() { - AddInput(kPointsInput, NodeValue::kVec2, QVector2D(0, 0), InputFlags(kInputFlagArray)); + AddInput(kPointsInput, NodeValue::kBezier, QVector2D(0, 0), InputFlags(kInputFlagArray)); AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(1.0, 1.0, 1.0))); @@ -47,13 +46,13 @@ PolygonGenerator::PolygonGenerator() InputArrayResize(kPointsInput, 5); SetSplitStandardValueOnTrack(kPointsInput, 0, 0, 0); SetSplitStandardValueOnTrack(kPointsInput, 1, -kTopY, 0); - SetSplitStandardValueOnTrack(kPointsInput, 0, -kMiddleX, 1); + SetSplitStandardValueOnTrack(kPointsInput, 0, kMiddleX, 1); SetSplitStandardValueOnTrack(kPointsInput, 1, -kMiddleY, 1); - SetSplitStandardValueOnTrack(kPointsInput, 0, -kBottomX, 2); + SetSplitStandardValueOnTrack(kPointsInput, 0, kBottomX, 2); SetSplitStandardValueOnTrack(kPointsInput, 1, kBottomY, 2); - SetSplitStandardValueOnTrack(kPointsInput, 0, kBottomX, 3); + SetSplitStandardValueOnTrack(kPointsInput, 0, -kBottomX, 3); SetSplitStandardValueOnTrack(kPointsInput, 1, kBottomY, 3); - SetSplitStandardValueOnTrack(kPointsInput, 0, kMiddleX, 4); + SetSplitStandardValueOnTrack(kPointsInput, 0, -kMiddleX, 4); SetSplitStandardValueOnTrack(kPointsInput, 1, -kMiddleY, 4); } @@ -108,18 +107,9 @@ void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) con QImage img(frame->width(), frame->height(), QImage::Format_Grayscale8); img.fill(Qt::transparent); - QPainterPath path; - QVector points = job.GetValue(kPointsInput).data().value< QVector >(); - if (!points.isEmpty()) { - path.moveTo(points.first().data().value().toPointF()); - - // TODO: Implement bezier - for (int i=1; i().toPointF()); - } - } + QPainterPath path = GeneratePath(points); QPainter p(&img); double par = frame->video_params().pixel_aspect_ratio().toDouble(); @@ -164,100 +154,159 @@ bool PolygonGenerator::HasGizmos() const return true; } -/*void PolygonGenerator::DrawGizmos(NodeValueDatabase &db, QPainter *p) const +void PolygonGenerator::DrawGizmos(const NodeValueRow &row, const NodeGlobals &globals, QPainter *p) { - Q_UNUSED(viewport) - - if (!points_input_->GetSize()) { - return; - } + const double handle_radius = GetGizmoHandleRadius(p->transform()); + const double bezier_radius = handle_radius/2; p->setPen(Qt::white); p->setBrush(Qt::white); + p->translate(globals.resolution_by_par().x()/2, globals.resolution_by_par().y()/2); - QVector points = GetGizmoCoordinates(db, scale); - QVector rects = GetGizmoRects(points); + QVector points = row[kPointsInput].data().value< QVector >(); - points.append(points.first()); + gizmo_position_handles_.resize(points.size()); + gizmo_bezier_handles_.resize(points.size() * 2); - p->drawPolyline(points.constData(), points.size()); - p->drawRects(rects); + p->setPen(QPen(Qt::white, 0)); + p->setBrush(Qt::NoBrush); + + if (!points.isEmpty()) { + QVector lines(points.size() * 2); + + for (int i=0; i(); + + QPointF main = pt.ToPointF(); + QPointF cp1 = main + pt.ControlPoint1ToPointF(); + QPointF cp2 = main + pt.ControlPoint2ToPointF(); + + gizmo_position_handles_[i] = CreateGizmoHandleRect(main, handle_radius); + + gizmo_bezier_handles_[i*2] = CreateGizmoHandleRect(cp1, bezier_radius); + lines[i*2] = QLineF(main, cp1); + + gizmo_bezier_handles_[i*2+1] = CreateGizmoHandleRect(cp2, bezier_radius); + lines[i*2+1] = QLineF(main, cp2); + } + + p->drawLines(lines); + } + + gizmo_polygon_path_ = GeneratePath(points); + p->drawPath(gizmo_polygon_path_); + + DrawAndExpandGizmoHandles(p, handle_radius, gizmo_position_handles_.data(), gizmo_position_handles_.size()); + DrawAndExpandGizmoHandles(p, handle_radius, gizmo_bezier_handles_.data(), gizmo_bezier_handles_.size()); } -bool PolygonGenerator::GizmoPress(NodeValueDatabase &db, const QPointF &p, const QVector2D &scale, const QSize& viewport) +bool PolygonGenerator::GizmoPress(const NodeValueRow& row, const NodeGlobals &globals, const QPointF &p) { - Q_UNUSED(viewport) + QPointF adjusted = p - (globals.resolution_by_par() / 2).toPointF(); - QVector points = GetGizmoCoordinates(db, scale); - QVector rects = GetGizmoRects(points); + // First, look for main points - for (int i=0;iAt(i); - gizmo_drag_start_ = points.at(i); - return true; + for (int i=0; i PolygonGenerator::GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D& scale) const -{ - // FIXME: Should Get() use a `kArray` type instead of a `kVec2` type? - QVector array_tbl = db[kPointsInput].Get(NodeValue::kVec2).value< QVector >(); - QVector points(array_tbl.size()); - - for (int i=0;i(); - - v *= scale; - - QPointF pt = v.toPointF(); - points[i] = pt; + for (NodeInputDragger &dragger : gizmo_x_draggers_) { + dragger.Drag(dragger.GetStartValue().toDouble() + diff.x()); } - return points; + for (NodeInputDragger &dragger : gizmo_y_draggers_) { + dragger.Drag(dragger.GetStartValue().toDouble() + diff.y()); + } } -QVector PolygonGenerator::GetGizmoRects(const QVector &points) const +void PolygonGenerator::GizmoRelease(MultiUndoCommand *command) { - QVector rects(points.size()); + for (NodeInputDragger &dragger : gizmo_x_draggers_) { + dragger.End(command); + } + gizmo_x_draggers_.clear(); - int rect_sz = QFontMetrics(qApp->font()).height() / 8; + for (NodeInputDragger &dragger : gizmo_y_draggers_) { + dragger.End(command); + } + gizmo_y_draggers_.clear(); - for (int i=0;icubicTo(before.ToPointF() + before.ControlPoint2ToPointF(), + after.ToPointF() + after.ControlPoint1ToPointF(), + after.ToPointF()); +} + +QPainterPath PolygonGenerator::GeneratePath(const QVector &points) +{ + QPainterPath path; + + if (!points.isEmpty()) { + const Bezier &first_pt = points.first().data().value(); + path.moveTo(first_pt.ToPointF()); + + for (int i=1; i(), points.at(i).data().value()); + } + + AddPointToPath(&path, points.last().data().value(), first_pt); } - return rects; + return path; } } diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index e91491d6a..e7da30009 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -21,6 +21,9 @@ #ifndef POLYGONGENERATOR_H #define POLYGONGENERATOR_H +#include + +#include "common/bezier.h" #include "node/node.h" #include "node/inputdragger.h" @@ -48,26 +51,30 @@ public: virtual void GenerateFrame(FramePtr frame, const GenerateJob &job) const override; virtual bool HasGizmos() const override; - //virtual void DrawGizmos(NodeValueDatabase& db, QPainter *p) const override; + virtual void DrawGizmos(const NodeValueRow& row, const NodeGlobals &globals, QPainter *p) override; - //virtual bool GizmoPress(NodeValueDatabase &db, const QPointF &p) override; - //virtual void GizmoMove(const QPointF &p, const QVector2D &scale, const rational &time) override; - //virtual void GizmoRelease() override; + virtual bool GizmoPress(const NodeValueRow& row, const NodeGlobals &globals, const QPointF &p) override; + virtual void GizmoMove(const QPointF &p, const rational &time, const Qt::KeyboardModifiers &modifiers) override; + virtual void GizmoRelease(MultiUndoCommand *command) override; static const QString kPointsInput; static const QString kColorInput; private: - QVector GetGizmoCoordinates(NodeValueDatabase &db, const QVector2D &scale) const; + static void AddPointToPath(QPainterPath *path, const Bezier &before, const Bezier &after); - QVector GetGizmoRects(const QVector& points) const; + static QPainterPath GeneratePath(const QVector &points); - NodeInput* gizmo_drag_; + QPainterPath gizmo_polygon_path_; + QVector gizmo_position_handles_; + QVector gizmo_bezier_handles_; + + QVector gizmo_x_active_; + QVector gizmo_y_active_; + QVector gizmo_x_draggers_; + QVector gizmo_y_draggers_; QPointF gizmo_drag_start_; - NodeInputDragger gizmo_x_dragger_; - NodeInputDragger gizmo_y_dragger_; - }; } diff --git a/app/node/inputdragger.h b/app/node/inputdragger.h index 26c3ee084..6ab0010f9 100644 --- a/app/node/inputdragger.h +++ b/app/node/inputdragger.h @@ -46,6 +46,11 @@ public: return input_being_dragged; } + const QVariant &GetStartValue() const + { + return start_value_; + } + private: NodeKeyframeTrackReference input_; diff --git a/app/node/value.cpp b/app/node/value.cpp index d9b1dfb34..3cc567a92 100644 --- a/app/node/value.cpp +++ b/app/node/value.cpp @@ -26,6 +26,7 @@ #include #include +#include "common/bezier.h" #include "common/tohex.h" #include "render/audioparams.h" #include "render/videoparams.h" @@ -64,6 +65,15 @@ QString NodeValue::ValueToString(Type data_type, const QVariant &value, bool val QString::number(c.green()), QString::number(c.blue()), QString::number(c.alpha())); + } else if (!value_is_a_key_track && data_type == kBezier) { + Bezier b = value.value(); + + return QStringLiteral("%1:%2:%3:%4:%5:%6").arg(QString::number(b.x()), + QString::number(b.y()), + QString::number(b.cp1_x()), + QString::number(b.cp1_y()), + QString::number(b.cp2_x()), + QString::number(b.cp2_y())); } else if (data_type == kRational) { return value.value().toString(); } else if (data_type == kTexture @@ -116,6 +126,7 @@ QByteArray NodeValue::ValueToBytes(NodeValue::Type type, const QVariant &value) case kVec3: return ValueToBytesInternal(value); case kVec4: return ValueToBytesInternal(value); case kCombo: return ValueToBytesInternal(value); + case kBezier: return ValueToBytesInternal(value); case kVideoParams: return value.value().toBytes(); @@ -174,6 +185,17 @@ QVector NodeValue::split_normal_value_into_track_values(Type type, con vals.replace(3, c.alpha()); break; } + case kBezier: + { + Bezier b = value.value(); + vals.replace(0, b.x()); + vals.replace(1, b.y()); + vals.replace(2, b.cp1_x()); + vals.replace(3, b.cp1_y()); + vals.replace(4, b.cp2_x()); + vals.replace(5, b.cp2_y()); + break; + } default: vals.replace(0, value); } @@ -213,6 +235,13 @@ QVariant NodeValue::combine_track_values_into_normal_value(Type type, const QVec split.at(2).toFloat(), split.at(3).toFloat())); } + case kBezier: + return QVariant::fromValue(Bezier(split.at(0).toDouble(), + split.at(1).toDouble(), + split.at(2).toDouble(), + split.at(3).toDouble(), + split.at(4).toDouble(), + split.at(5).toDouble())); default: return split.first(); } @@ -228,6 +257,8 @@ int NodeValue::get_number_of_keyframe_tracks(Type type) case NodeValue::kVec4: case NodeValue::kColor: return 4; + case NodeValue::kBezier: + return 6; default: return 1; } @@ -259,6 +290,12 @@ QVariant NodeValue::StringToValue(Type data_type, const QString &string, bool va ValidateVectorString(&vals, 4); return QVariant::fromValue(Color(vals.at(0).toDouble(), vals.at(1).toDouble(), vals.at(2).toDouble(), vals.at(3).toDouble())); + } else if (!value_is_a_key_track && data_type == kBezier) { + QStringList vals = string.split(':'); + + ValidateVectorString(&vals, 6); + + return QVariant::fromValue(Bezier(vals.at(0).toDouble(), vals.at(1).toDouble(), vals.at(2).toDouble(), vals.at(3).toDouble(), vals.at(4).toDouble(), vals.at(5).toDouble())); } else if (data_type == kInt) { return QVariant::fromValue(string.toLongLong()); } else if (data_type == kRational) { @@ -309,6 +346,8 @@ QString NodeValue::GetPrettyDataTypeName(Type type) return QCoreApplication::translate("NodeValue", "Vector 3D"); case kVec4: return QCoreApplication::translate("NodeValue", "Vector 4D"); + case kBezier: + return QCoreApplication::translate("NodeValue", "Bezier"); case kVideoParams: return QCoreApplication::translate("NodeValue", "Video Parameters"); case kAudioParams: diff --git a/app/node/value.h b/app/node/value.h index 4c6959c9b..5ef2ff54f 100644 --- a/app/node/value.h +++ b/app/node/value.h @@ -142,6 +142,13 @@ public: */ kVec4, + /** + * Cubic bezier type that contains three X/Y coordinates, the main point, and two control points + * + * Resolves to `Bezier` + */ + kBezier, + /** * ComboBox type * diff --git a/app/render/opengl/openglrenderer.cpp b/app/render/opengl/openglrenderer.cpp index a339bb23e..37e43e88d 100644 --- a/app/render/opengl/openglrenderer.cpp +++ b/app/render/opengl/openglrenderer.cpp @@ -521,6 +521,7 @@ void OpenGLRenderer::Blit(QVariant s, ShaderJob job, Texture *destination, Video case NodeValue::kSampleJob: case NodeValue::kGenerateJob: case NodeValue::kFootageJob: + case NodeValue::kBezier: case NodeValue::kNone: break; } diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index 915214d9e..9faf9c462 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -15,6 +15,7 @@ # along with this program. If not, see . add_subdirectory(audiomonitor) +add_subdirectory(bezier) add_subdirectory(clickablelabel) add_subdirectory(collapsebutton) add_subdirectory(colorbutton) diff --git a/app/widget/bezier/CMakeLists.txt b/app/widget/bezier/CMakeLists.txt new file mode 100644 index 000000000..7f73ab2ba --- /dev/null +++ b/app/widget/bezier/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2021 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + widget/bezier/bezierwidget.cpp + widget/bezier/bezierwidget.h + PARENT_SCOPE +) diff --git a/app/widget/bezier/bezierwidget.cpp b/app/widget/bezier/bezierwidget.cpp new file mode 100644 index 000000000..2f2dec995 --- /dev/null +++ b/app/widget/bezier/bezierwidget.cpp @@ -0,0 +1,101 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "bezierwidget.h" + +#include +#include + +namespace olive { + +BezierWidget::BezierWidget(QWidget *parent) : + QWidget{parent} +{ + QGridLayout *layout = new QGridLayout(this); + + int row = 0; + + layout->addWidget(new QLabel(tr("Center:")), row, 0); + + x_slider_ = new FloatSlider(); + connect(x_slider_, &FloatSlider::ValueChanged, this, &BezierWidget::ValueChanged); + layout->addWidget(x_slider_, row, 1); + + y_slider_ = new FloatSlider(); + connect(y_slider_, &FloatSlider::ValueChanged, this, &BezierWidget::ValueChanged); + layout->addWidget(y_slider_, row, 2); + + row++; + + QGroupBox *bezier_group = new QGroupBox(tr("Bezier")); + layout->addWidget(bezier_group, row, 0, 1, 3); + + QGridLayout *bezier_layout = new QGridLayout(bezier_group); + + row = 0; + + bezier_layout->addWidget(new QLabel(tr("In:")), row, 0); + + cp1_x_slider_ = new FloatSlider(); + connect(cp1_x_slider_, &FloatSlider::ValueChanged, this, &BezierWidget::ValueChanged); + bezier_layout->addWidget(cp1_x_slider_, row, 1); + + cp1_y_slider_ = new FloatSlider(); + connect(cp1_y_slider_, &FloatSlider::ValueChanged, this, &BezierWidget::ValueChanged); + bezier_layout->addWidget(cp1_y_slider_, row, 2); + + row++; + + bezier_layout->addWidget(new QLabel(tr("Out:")), row, 0); + + cp2_x_slider_ = new FloatSlider(); + connect(cp2_x_slider_, &FloatSlider::ValueChanged, this, &BezierWidget::ValueChanged); + bezier_layout->addWidget(cp2_x_slider_, row, 1); + + cp2_y_slider_ = new FloatSlider(); + connect(cp2_y_slider_, &FloatSlider::ValueChanged, this, &BezierWidget::ValueChanged); + bezier_layout->addWidget(cp2_y_slider_, row, 2); +} + +Bezier BezierWidget::GetValue() const +{ + Bezier b; + + b.set_x(x_slider_->GetValue()); + b.set_y(y_slider_->GetValue()); + b.set_cp1_x(cp1_x_slider_->GetValue()); + b.set_cp1_y(cp1_y_slider_->GetValue()); + b.set_cp2_x(cp2_x_slider_->GetValue()); + b.set_cp2_y(cp2_y_slider_->GetValue()); + + return b; +} + +void BezierWidget::SetValue(const Bezier &b) +{ + x_slider_->SetValue(b.x()); + y_slider_->SetValue(b.y()); + cp1_x_slider_->SetValue(b.cp1_x()); + cp1_y_slider_->SetValue(b.cp1_y()); + cp2_x_slider_->SetValue(b.cp2_x()); + cp2_y_slider_->SetValue(b.cp2_y()); +} + +} diff --git a/app/widget/bezier/bezierwidget.h b/app/widget/bezier/bezierwidget.h new file mode 100644 index 000000000..c052fd3b3 --- /dev/null +++ b/app/widget/bezier/bezierwidget.h @@ -0,0 +1,74 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef BEZIERWIDGET_H +#define BEZIERWIDGET_H + +#include +#include + +#include "common/bezier.h" +#include "widget/slider/floatslider.h" + +namespace olive { + +class BezierWidget : public QWidget +{ + Q_OBJECT +public: + explicit BezierWidget(QWidget *parent = nullptr); + + Bezier GetValue() const; + + void SetValue(const Bezier &b); + + FloatSlider *x_slider() const { return x_slider_; } + + FloatSlider *y_slider() const { return y_slider_; } + + FloatSlider *cp1_x_slider() const { return cp1_x_slider_; } + + FloatSlider *cp1_y_slider() const { return cp1_y_slider_; } + + FloatSlider *cp2_x_slider() const { return cp2_x_slider_; } + + FloatSlider *cp2_y_slider() const { return cp2_y_slider_; } + +signals: + void ValueChanged(); + +private: + FloatSlider *x_slider_; + + FloatSlider *y_slider_; + + FloatSlider *cp1_x_slider_; + + FloatSlider *cp1_y_slider_; + + FloatSlider *cp2_x_slider_; + + FloatSlider *cp2_y_slider_; + +}; + +} + +#endif // BEZIERWIDGET_H diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index 658b43118..05a5cccce 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -33,6 +33,7 @@ #include "nodeparamviewtextedit.h" #include "nodeparamviewundo.h" #include "undo/undostack.h" +#include "widget/bezier/bezierwidget.h" #include "widget/colorbutton/colorbutton.h" #include "widget/filefield/filefield.h" #include "widget/slider/floatslider.h" @@ -158,6 +159,19 @@ void NodeParamViewWidgetBridge::CreateWidgets() connect(font_combobox, &QFontComboBox::currentFontChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); break; } + case NodeValue::kBezier: + { + BezierWidget *bezier = new BezierWidget(); + widgets_.append(bezier); + + connect(bezier->x_slider(), &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); + connect(bezier->y_slider(), &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); + connect(bezier->cp1_x_slider(), &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); + connect(bezier->cp1_y_slider(), &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); + connect(bezier->cp2_x_slider(), &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); + connect(bezier->cp2_y_slider(), &FloatSlider::ValueChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); + break; + } } // Check all properties @@ -220,10 +234,8 @@ void NodeParamViewWidgetBridge::SetInputValueInternal(const QVariant &value, int } } -void NodeParamViewWidgetBridge::ProcessSlider(NumericSliderBase *slider, const QVariant &value) +void NodeParamViewWidgetBridge::ProcessSlider(NumericSliderBase *slider, int slider_track, const QVariant &value) { - int slider_track = widgets_.indexOf(slider); - if (slider->IsDragging()) { // While we're dragging, we block the input's normal signalling and create our own @@ -371,11 +383,38 @@ void NodeParamViewWidgetBridge::WidgetCallback() if (cb->itemData(i, Qt::AccessibleDescriptionRole).toString() == QStringLiteral("separator")) { index--; } + } SetInputValue(index, 0); break; } + case NodeValue::kBezier: + { + // Widget is a FloatSlider (child of BezierWidget) + BezierWidget *bw = static_cast(widgets_.first()); + FloatSlider *fs = static_cast(sender()); + + int index = -1; + if (fs == bw->x_slider()) { + index = 0; + } else if (fs == bw->y_slider()) { + index = 1; + } else if (fs == bw->cp1_x_slider()) { + index = 2; + } else if (fs == bw->cp1_y_slider()) { + index = 3; + } else if (fs == bw->cp2_x_slider()) { + index = 4; + } else if (fs == bw->cp2_y_slider()) { + index = 5; + } + + if (index != -1) { + ProcessSlider(fs, index, fs->GetValue()); + } + break; + } } } @@ -509,6 +548,12 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() cb->blockSignals(false); break; } + case NodeValue::kBezier: + { + BezierWidget* bw = static_cast(widgets_.first()); + bw->SetValue(GetInnerInput().GetValueAtTime(node_time).value()); + break; + } } } diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h index 106244d7b..0f80a443b 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.h +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.h @@ -64,7 +64,11 @@ private: void SetInputValueInternal(const QVariant& value, int track, MultiUndoCommand *command, bool insert_on_all_tracks_if_no_key); - void ProcessSlider(NumericSliderBase* slider, const QVariant& value); + void ProcessSlider(NumericSliderBase* slider, int slider_track, const QVariant& value); + void ProcessSlider(NumericSliderBase* slider, const QVariant& value) + { + ProcessSlider(slider, widgets_.indexOf(slider), value); + } void SetProperty(const QString &key, const QVariant &value);