From d82acf9b7e31b0311f795a3bb13e8faa07cbba68 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 28 Dec 2019 00:27:13 +1100 Subject: [PATCH] implemented basic animation curve editor widgets Frontend is largely done, it just needs backend and connecting to other widgets to function correctly. --- app/panel/curve/curve.cpp | 4 ++ app/panel/curve/curve.h | 3 ++ app/widget/CMakeLists.txt | 1 + app/widget/curveview/curveview.cpp | 6 --- app/widget/curveview/curveview.h | 11 ----- app/widget/curvewidget/CMakeLists.txt | 24 ++++++++++ app/widget/curvewidget/curveview.cpp | 43 +++++++++++++++++- app/widget/curvewidget/curveview.h | 12 ++++- app/widget/curvewidget/curvewidget.cpp | 45 +++++++++++++++++++ app/widget/curvewidget/curvewidget.h | 25 +++++++++++ app/widget/nodeparamview/nodeparamview.cpp | 2 + .../nodeparamview/nodeparamviewitem.cpp | 16 ++++++- app/widget/nodeparamview/nodeparamviewitem.h | 3 ++ .../nodeparamviewkeyframecontrol.cpp | 40 +++++++++++++---- .../nodeparamviewkeyframecontrol.h | 6 ++- app/window/mainwindow/mainwindow.cpp | 5 +++ 16 files changed, 215 insertions(+), 31 deletions(-) delete mode 100644 app/widget/curveview/curveview.cpp delete mode 100644 app/widget/curveview/curveview.h create mode 100644 app/widget/curvewidget/CMakeLists.txt create mode 100644 app/widget/curvewidget/curvewidget.cpp create mode 100644 app/widget/curvewidget/curvewidget.h diff --git a/app/panel/curve/curve.cpp b/app/panel/curve/curve.cpp index 48223f277..165a332c8 100644 --- a/app/panel/curve/curve.cpp +++ b/app/panel/curve/curve.cpp @@ -6,6 +6,10 @@ CurvePanel::CurvePanel(QWidget *parent) : // FIXME: This won't work if there's ever more than one of this panel setObjectName("CurvePanel"); + // Create main widget and set it + widget_ = new CurveWidget(); + setWidget(widget_); + // Set strings Retranslate(); } diff --git a/app/panel/curve/curve.h b/app/panel/curve/curve.h index d793b610d..ecdee580d 100644 --- a/app/panel/curve/curve.h +++ b/app/panel/curve/curve.h @@ -1,6 +1,7 @@ #ifndef CURVEPANEL_H #define CURVEPANEL_H +#include "widget/curvewidget/curvewidget.h" #include "widget/panel/panel.h" class CurvePanel : public PanelWidget @@ -14,6 +15,8 @@ protected: private: void Retranslate(); + CurveWidget* widget_; + }; #endif // CURVEPANEL_H diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index 1de01521b..4ae18ef53 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -17,6 +17,7 @@ add_subdirectory(audiomonitor) add_subdirectory(clickablelabel) add_subdirectory(columnedgridlayout) +add_subdirectory(curvewidget) add_subdirectory(flowlayout) add_subdirectory(focusablelineedit) add_subdirectory(footagecombobox) diff --git a/app/widget/curveview/curveview.cpp b/app/widget/curveview/curveview.cpp deleted file mode 100644 index dfa49d5c3..000000000 --- a/app/widget/curveview/curveview.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "curveview.h" - -CurveView::CurveView() -{ - -} diff --git a/app/widget/curveview/curveview.h b/app/widget/curveview/curveview.h deleted file mode 100644 index 757b240dd..000000000 --- a/app/widget/curveview/curveview.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef CURVEVIEW_H -#define CURVEVIEW_H - - -class CurveView -{ -public: - CurveView(); -}; - -#endif // CURVEVIEW_H diff --git a/app/widget/curvewidget/CMakeLists.txt b/app/widget/curvewidget/CMakeLists.txt new file mode 100644 index 000000000..69be102f4 --- /dev/null +++ b/app/widget/curvewidget/CMakeLists.txt @@ -0,0 +1,24 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 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/curvewidget/curveview.h + widget/curvewidget/curveview.cpp + widget/curvewidget/curvewidget.h + widget/curvewidget/curvewidget.cpp + PARENT_SCOPE +) diff --git a/app/widget/curvewidget/curveview.cpp b/app/widget/curvewidget/curveview.cpp index dfa49d5c3..4f32d18e7 100644 --- a/app/widget/curvewidget/curveview.cpp +++ b/app/widget/curvewidget/curveview.cpp @@ -1,6 +1,45 @@ #include "curveview.h" -CurveView::CurveView() -{ +#include +#include "common/qtversionabstraction.h" + +CurveView::CurveView(QWidget *parent) : + TimelineViewBase(parent) +{ + setAlignment(Qt::AlignLeft | Qt::AlignBottom); + setDragMode(RubberBandDrag); + setViewportUpdateMode(FullViewportUpdate); + + text_padding_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("i")); +} + +void CurveView::drawBackground(QPainter *painter, const QRectF &rect) +{ + QVector lines; + + //painter->setPen(palette().window().color()); + + int grid_interval = 100; + + int x_start = qCeil(rect.left() / grid_interval) * grid_interval; + int y_start = qCeil(rect.top() / grid_interval) * grid_interval; + + QPoint viewport_edges(0, qRound(rect.height())); + QPointF scene_edges = mapToScene(viewport_edges); + //QRectF scene_edges = mapToScene(viewport()->geometry()).boundingRect(); + + // Add vertical lines + for (int i=x_start;idrawText(i + text_padding_, qRound(scene_edges.y()) - text_padding_, QString::number(i)); + lines.append(QLine(i, qRound(rect.top()), i, qRound(rect.bottom()))); + } + + // Add horizontal lines + for (int i=y_start;idrawText(qRound(scene_edges.x()) + text_padding_, i - text_padding_, QString::number(-i)); + lines.append(QLine(qRound(rect.left()), i, qRound(rect.right()), i)); + } + + painter->drawLines(lines); } diff --git a/app/widget/curvewidget/curveview.h b/app/widget/curvewidget/curveview.h index 757b240dd..8f8ada0f9 100644 --- a/app/widget/curvewidget/curveview.h +++ b/app/widget/curvewidget/curveview.h @@ -1,11 +1,19 @@ #ifndef CURVEVIEW_H #define CURVEVIEW_H +#include "widget/timelinewidget/view/timelineviewbase.h" -class CurveView +class CurveView : public TimelineViewBase { public: - CurveView(); + CurveView(QWidget* parent = nullptr); + +protected: + virtual void drawBackground(QPainter* painter, const QRectF& rect) override; + +private: + int text_padding_; + }; #endif // CURVEVIEW_H diff --git a/app/widget/curvewidget/curvewidget.cpp b/app/widget/curvewidget/curvewidget.cpp new file mode 100644 index 000000000..5cdeb1e7f --- /dev/null +++ b/app/widget/curvewidget/curvewidget.cpp @@ -0,0 +1,45 @@ +#include "curvewidget.h" + +#include +#include + +#include "widget/nodeparamview/nodeparamviewkeyframecontrol.h" + +CurveWidget::CurveWidget(QWidget *parent) : + QWidget(parent) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + QHBoxLayout* top_controls = new QHBoxLayout(); + + NodeParamViewKeyframeControl* key_controls = new NodeParamViewKeyframeControl(false); + key_controls->SetEnableButtonVisible(false); + key_controls->SetPreviousButtonEnabled(false); + key_controls->SetToggleButtonEnabled(false); + key_controls->SetNextButtonEnabled(false); + top_controls->addWidget(key_controls); + + top_controls->addStretch(); + + linear_button_ = new QPushButton(tr("Linear")); + linear_button_->setCheckable(true); + linear_button_->setEnabled(false); + top_controls->addWidget(linear_button_); + + bezier_button_ = new QPushButton(tr("Bezier")); + bezier_button_->setCheckable(true); + bezier_button_->setEnabled(false); + top_controls->addWidget(bezier_button_); + + hold_button_ = new QPushButton(tr("Hold")); + hold_button_->setCheckable(true); + hold_button_->setEnabled(false); + top_controls->addWidget(hold_button_); + + layout->addLayout(top_controls); + + view_ = new CurveView(); + layout->addWidget(view_); + + layout->addWidget(new QLabel("Values")); +} diff --git a/app/widget/curvewidget/curvewidget.h b/app/widget/curvewidget/curvewidget.h new file mode 100644 index 000000000..21758e24d --- /dev/null +++ b/app/widget/curvewidget/curvewidget.h @@ -0,0 +1,25 @@ +#ifndef CURVEWIDGET_H +#define CURVEWIDGET_H + +#include +#include + +#include "curveview.h" + +class CurveWidget : public QWidget +{ +public: + CurveWidget(QWidget* parent = nullptr); + +private: + QPushButton* linear_button_; + + QPushButton* bezier_button_; + + QPushButton* hold_button_; + + CurveView* view_; + +}; + +#endif // CURVEWIDGET_H diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index d027629d1..6e4da7860 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -131,6 +131,8 @@ void NodeParamView::SetNodes(QList nodes) connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::ItemRequestedTimeChanged); items_.append(item); + + QTimer::singleShot(1, item, &NodeParamViewItem::SignalAllKeyframes); } if (!nodes_.isEmpty()) { diff --git a/app/widget/nodeparamview/nodeparamviewitem.cpp b/app/widget/nodeparamview/nodeparamviewitem.cpp index c3ea054d8..be4556e96 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.cpp +++ b/app/widget/nodeparamview/nodeparamviewitem.cpp @@ -88,6 +88,19 @@ void NodeParamViewItem::SetTime(const rational &time) } } +void NodeParamViewItem::SignalAllKeyframes() +{ + foreach (NodeParam* param, node_->parameters()) { + if (param->type() == NodeParam::kInput) { + NodeInput* input = static_cast(param); + + foreach (NodeKeyframePtr key, input->keyframes()) { + InputAddedKeyframeInternal(input, key); + } + } + } +} + void NodeParamViewItem::changeEvent(QEvent *e) { if (e->type() == QEvent::LanguageChange) { @@ -146,7 +159,8 @@ void NodeParamViewItem::SetupUI() // Hacky but effective way to make sure this widget is always as far right as possible int control_column = 10; - NodeParamViewKeyframeControl* key_control = new NodeParamViewKeyframeControl(input); + NodeParamViewKeyframeControl* key_control = new NodeParamViewKeyframeControl(); + key_control->SetInput(input); content_layout_->addWidget(key_control, row_count, control_column); connect(key_control, &NodeParamViewKeyframeControl::KeyframeEnableChanged, this, &NodeParamViewItem::UserChangedKeyframeEnable); connect(key_control, &NodeParamViewKeyframeControl::GoToPreviousKey, this, &NodeParamViewItem::GoToPreviousKey); diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 824ddf011..7528db49e 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -47,6 +47,9 @@ public: void SetTime(const rational& time); +public slots: + void SignalAllKeyframes(); + signals: void KeyframeAdded(NodeKeyframePtr key, int y); diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp index 72c28b8e0..66d9e26d4 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.cpp @@ -4,16 +4,18 @@ #include "ui/icons/icons.h" -NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(NodeInput* input, QWidget *parent) : +NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(bool right_align, QWidget *parent) : QWidget(parent), - input_(input) + input_(nullptr) { QHBoxLayout* layout = new QHBoxLayout(this); layout->setMargin(0); layout->setSpacing(0); - // Automatically right aligns all buttons - layout->addStretch(); + if (right_align) { + // Automatically right aligns all buttons + layout->addStretch(); + } prev_key_btn_ = CreateNewToolButton(icon::TriLeft); prev_key_btn_->setIconSize(prev_key_btn_->iconSize() / 2); @@ -38,10 +40,6 @@ NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(NodeInput* input, QWi connect(toggle_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::KeyframeToggled); connect(enable_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable); connect(enable_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::KeyframeEnableChanged); - connect(input_, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewKeyframeControl::SetKeyframeEnabled); - - // Pick up keyframing value - ShowButtonsFromKeyframeEnable(input_->is_keyframing()); } NodeInput *NodeParamViewKeyframeControl::GetConnectedInput() const @@ -59,6 +57,11 @@ void NodeParamViewKeyframeControl::SetNextButtonEnabled(bool enabled) next_key_btn_->setEnabled(enabled); } +void NodeParamViewKeyframeControl::SetToggleButtonEnabled(bool enable) +{ + toggle_key_btn_->setEnabled(enable); +} + void NodeParamViewKeyframeControl::SetToggleButtonChecked(bool checked) { // Suppress KeyframeToggled() signal from this object @@ -69,6 +72,27 @@ void NodeParamViewKeyframeControl::SetToggleButtonChecked(bool checked) blockSignals(false); } +void NodeParamViewKeyframeControl::SetEnableButtonVisible(bool visible) +{ + enable_key_btn_->setVisible(visible); +} + +void NodeParamViewKeyframeControl::SetInput(NodeInput *input) +{ + if (input_ != nullptr) { + disconnect(input_, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewKeyframeControl::SetKeyframeEnabled); + } + + input_ = input; + + if (input_ != nullptr) { + connect(input_, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewKeyframeControl::SetKeyframeEnabled); + + // Pick up keyframing value + ShowButtonsFromKeyframeEnable(input_->is_keyframing()); + } +} + void NodeParamViewKeyframeControl::SetKeyframeEnabled(bool e) { // Suppress KeyframeEnableChanged() signal from this object diff --git a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h index f3a566940..028925bff 100644 --- a/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h +++ b/app/widget/nodeparamview/nodeparamviewkeyframecontrol.h @@ -10,13 +10,17 @@ class NodeParamViewKeyframeControl : public QWidget { Q_OBJECT public: - NodeParamViewKeyframeControl(NodeInput* input, QWidget* parent = nullptr); + NodeParamViewKeyframeControl(bool right_align = true, QWidget* parent = nullptr); NodeInput* GetConnectedInput() const; void SetPreviousButtonEnabled(bool enabled); void SetNextButtonEnabled(bool enabled); + void SetToggleButtonEnabled(bool enable); void SetToggleButtonChecked(bool checked); + void SetEnableButtonVisible(bool visible); + + void SetInput(NodeInput* input); public slots: void SetKeyframeEnabled(bool e); diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 8807dbb73..295c63bb5 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -27,6 +27,7 @@ // Panel objects #include "panel/panelmanager.h" #include "panel/audiomonitor/audiomonitor.h" +#include "panel/curve/curve.h" #include "panel/node/node.h" #include "panel/param/param.h" #include "panel/project/project.h" @@ -137,6 +138,10 @@ void MainWindow::ProjectOpen(Project* p) task_man_panel->setFloating(true); task_man_panel->setVisible(false); + CurvePanel* curve_panel = PanelManager::instance()->CreatePanel(this); + addDockWidget(Qt::BottomDockWidgetArea, curve_panel); + task_man_panel->setFloating(true); + connect(node_panel, SIGNAL(SelectionChanged(QList)), param_panel, SLOT(SetNodes(QList))); }