began UI for keyframing
Largely extending the existing NodeParamView with functionality from the previous release.
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
|
||||
NodeInput::NodeInput(const QString& id) :
|
||||
NodeParam(id),
|
||||
keyframable_(true),
|
||||
keyframing_(false),
|
||||
dependent_(true),
|
||||
has_minimum_(false),
|
||||
@@ -241,6 +242,16 @@ void NodeInput::set_is_keyframing(bool k)
|
||||
keyframing_ = k;
|
||||
}
|
||||
|
||||
bool NodeInput::is_keyframable() const
|
||||
{
|
||||
return keyframable_;
|
||||
}
|
||||
|
||||
void NodeInput::set_is_keyframable(bool k)
|
||||
{
|
||||
keyframable_ = k;
|
||||
}
|
||||
|
||||
const QVariant &NodeInput::minimum() const
|
||||
{
|
||||
return minimum_;
|
||||
|
||||
@@ -98,6 +98,16 @@ public:
|
||||
*/
|
||||
void set_is_keyframing(bool k);
|
||||
|
||||
/**
|
||||
* @brief Return whether this input can be keyframed or not
|
||||
*/
|
||||
bool is_keyframable() const;
|
||||
|
||||
/**
|
||||
* @brief Set whether this input can be keyframed or not
|
||||
*/
|
||||
void set_is_keyframable(bool k);
|
||||
|
||||
const QVariant& minimum() const;
|
||||
bool has_minimum() const;
|
||||
void set_minimum(const QVariant& min);
|
||||
@@ -122,6 +132,11 @@ private:
|
||||
*/
|
||||
DataType data_type_;
|
||||
|
||||
/**
|
||||
* @brief Internal keyframable value
|
||||
*/
|
||||
bool keyframable_;
|
||||
|
||||
/**
|
||||
* @brief Internal keyframe array
|
||||
*
|
||||
|
||||
@@ -69,6 +69,8 @@ QIcon olive::icon::Record;
|
||||
QIcon olive::icon::Add;
|
||||
QIcon olive::icon::Error;
|
||||
QIcon olive::icon::DirUp;
|
||||
QIcon olive::icon::Clock;
|
||||
QIcon olive::icon::Diamond;
|
||||
|
||||
void olive::icon::LoadAll(const QString& theme)
|
||||
{
|
||||
@@ -116,6 +118,8 @@ void olive::icon::LoadAll(const QString& theme)
|
||||
Add = Create(theme, "add-button");
|
||||
Error = Create(theme, "error");
|
||||
DirUp = Create(theme, "dirup");
|
||||
Clock = Create(theme, "clock");
|
||||
Diamond = Create(theme, "diamond");
|
||||
}
|
||||
|
||||
QIcon olive::icon::Create(const QString& theme, const QString &name)
|
||||
|
||||
@@ -76,6 +76,8 @@ extern QIcon Record;
|
||||
extern QIcon Add;
|
||||
extern QIcon Error;
|
||||
extern QIcon DirUp;
|
||||
extern QIcon Clock;
|
||||
extern QIcon Diamond;
|
||||
|
||||
/**
|
||||
* @brief Create an icon object loaded from file
|
||||
|
||||
@@ -20,6 +20,7 @@ add_subdirectory(columnedgridlayout)
|
||||
add_subdirectory(flowlayout)
|
||||
add_subdirectory(focusablelineedit)
|
||||
add_subdirectory(footagecombobox)
|
||||
add_subdirectory(keyframeview)
|
||||
add_subdirectory(menu)
|
||||
add_subdirectory(nodeview)
|
||||
add_subdirectory(nodeparamview)
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/keyframeview/keyframeview.h
|
||||
widget/keyframeview/keyframeview.cpp
|
||||
widget/keyframeview/keyframeviewitem.h
|
||||
widget/keyframeview/keyframeviewitem.cpp
|
||||
PARENT_SCOPE
|
||||
)
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "keyframeview.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
KeyframeView::KeyframeView(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
QVBoxLayout* layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(0);
|
||||
layout->setMargin(0);
|
||||
|
||||
ruler_ = new TimeRuler();
|
||||
ruler_->SetTextVisible(true);
|
||||
layout->addWidget(ruler_);
|
||||
|
||||
view_ = new QGraphicsView();
|
||||
view_->setScene(&scene_);
|
||||
view_->setBackgroundRole(QPalette::Base);
|
||||
view_->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
view_->setDragMode(QGraphicsView::RubberBandDrag);
|
||||
layout->addWidget(view_);
|
||||
}
|
||||
|
||||
void KeyframeView::SetTimebase(const rational &timebase)
|
||||
{
|
||||
ruler_->SetTimebase(timebase);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef KEYFRAMEVIEW_H
|
||||
#define KEYFRAMEVIEW_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "keyframeviewitem.h"
|
||||
#include "widget/timeruler/timeruler.h"
|
||||
|
||||
class KeyframeView : public QWidget
|
||||
{
|
||||
public:
|
||||
KeyframeView(QWidget* parent = nullptr);
|
||||
|
||||
void AddKeyframe(const rational& time, int y);
|
||||
|
||||
void SetTimebase(const rational& timebase);
|
||||
|
||||
private:
|
||||
TimeRuler* ruler_;
|
||||
QGraphicsView* view_;
|
||||
|
||||
QGraphicsScene scene_;
|
||||
};
|
||||
|
||||
#endif // KEYFRAMEVIEW_H
|
||||
@@ -0,0 +1,83 @@
|
||||
#include "keyframeviewitem.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
#include <QWidget>
|
||||
|
||||
#include "common/qtversionabstraction.h"
|
||||
|
||||
KeyframeViewItem::KeyframeViewItem(QGraphicsItem *parent) :
|
||||
QGraphicsRectItem(parent),
|
||||
key_(nullptr),
|
||||
scale_(1.0)
|
||||
{
|
||||
keyframe_size_ = QFontMetricsWidth(qApp->fontMetrics(), "Oi");
|
||||
setFlag(QGraphicsItem::ItemIsSelectable);
|
||||
setFlag(QGraphicsItem::ItemIsMovable);
|
||||
}
|
||||
|
||||
void KeyframeViewItem::SetKeyframe(NodeKeyframe *key)
|
||||
{
|
||||
key_ = key;
|
||||
UpdateRect();
|
||||
}
|
||||
|
||||
void KeyframeViewItem::SetVerticalCenter(int middle)
|
||||
{
|
||||
middle_ = middle;
|
||||
UpdateRect();
|
||||
}
|
||||
|
||||
void KeyframeViewItem::SetScale(double scale)
|
||||
{
|
||||
scale_ = scale;
|
||||
UpdateRect();
|
||||
}
|
||||
|
||||
void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
||||
{
|
||||
if (!key_) {
|
||||
return;
|
||||
}
|
||||
|
||||
painter->setPen(Qt::black);
|
||||
|
||||
if (option->state & QStyle::State_Selected) {
|
||||
painter->setBrush(widget->palette().highlight());
|
||||
} else {
|
||||
painter->setBrush(widget->palette().text());
|
||||
}
|
||||
|
||||
switch (key_->type()) {
|
||||
case NodeKeyframe::kLinear:
|
||||
{
|
||||
QPointF points[] = {
|
||||
QPointF(rect().center().x(), rect().top()),
|
||||
QPointF(rect().right(), rect().center().y()),
|
||||
QPointF(rect().center().x(), rect().bottom()),
|
||||
QPointF(rect().left(), rect().center().y())
|
||||
};
|
||||
|
||||
painter->drawPolygon(points, 4);
|
||||
break;
|
||||
}
|
||||
case NodeKeyframe::kBezier:
|
||||
painter->drawEllipse(rect());
|
||||
break;
|
||||
case NodeKeyframe::kHold:
|
||||
painter->drawRect(rect());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewItem::UpdateRect()
|
||||
{
|
||||
if (!key_) {
|
||||
return;
|
||||
}
|
||||
|
||||
double x_center = key_->time().toDouble() * scale_;
|
||||
|
||||
setRect(x_center - keyframe_size_/2, middle_ - keyframe_size_/2, keyframe_size_, keyframe_size_);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef KEYFRAMEVIEWITEM_H
|
||||
#define KEYFRAMEVIEWITEM_H
|
||||
|
||||
#include <QGraphicsRectItem>
|
||||
|
||||
#include "node/keyframe.h"
|
||||
|
||||
class KeyframeViewItem : public QGraphicsRectItem
|
||||
{
|
||||
public:
|
||||
KeyframeViewItem(QGraphicsItem *parent = nullptr);
|
||||
|
||||
void SetKeyframe(NodeKeyframe* key);
|
||||
|
||||
void SetVerticalCenter(int middle);
|
||||
|
||||
void SetScale(double scale);
|
||||
|
||||
protected:
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
|
||||
|
||||
private:
|
||||
void UpdateRect();
|
||||
|
||||
NodeKeyframe* key_;
|
||||
|
||||
double scale_;
|
||||
|
||||
int middle_;
|
||||
|
||||
int keyframe_size_;
|
||||
};
|
||||
|
||||
#endif // KEYFRAMEVIEWITEM_H
|
||||
@@ -20,6 +20,10 @@ set(OLIVE_SOURCES
|
||||
widget/nodeparamview/nodeparamview.cpp
|
||||
widget/nodeparamview/nodeparamviewitem.h
|
||||
widget/nodeparamview/nodeparamviewitem.cpp
|
||||
widget/nodeparamview/nodeparamviewkeyframecontrol.h
|
||||
widget/nodeparamview/nodeparamviewkeyframecontrol.cpp
|
||||
widget/nodeparamview/nodeparamviewundo.h
|
||||
widget/nodeparamview/nodeparamviewundo.cpp
|
||||
widget/nodeparamview/nodeparamviewwidgetbridge.h
|
||||
widget/nodeparamview/nodeparamviewwidgetbridge.cpp
|
||||
PARENT_SCOPE
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "nodeparamview.h"
|
||||
|
||||
#include <QScrollArea>
|
||||
#include <QSplitter>
|
||||
|
||||
NodeParamView::NodeParamView(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
@@ -30,10 +31,13 @@ NodeParamView::NodeParamView(QWidget *parent) :
|
||||
widget_layout->setSpacing(0);
|
||||
widget_layout->setMargin(0);
|
||||
|
||||
QSplitter* splitter = new QSplitter(Qt::Horizontal);
|
||||
widget_layout->addWidget(splitter);
|
||||
|
||||
// Set up scroll area for params
|
||||
QScrollArea* scroll_area = new QScrollArea();
|
||||
scroll_area->setWidgetResizable(true);
|
||||
widget_layout->addWidget(scroll_area);
|
||||
splitter->addWidget(scroll_area);
|
||||
|
||||
// Param widget
|
||||
QWidget* param_widget_area = new QWidget();
|
||||
@@ -46,6 +50,13 @@ NodeParamView::NodeParamView(QWidget *parent) :
|
||||
|
||||
// Add a stretch to allow empty space at the bottom of the layout
|
||||
param_layout_->addStretch();
|
||||
|
||||
// Set up keyframe view
|
||||
keyframe_view_ = new KeyframeView();
|
||||
splitter->addWidget(keyframe_view_);
|
||||
|
||||
// Disable collapsing param view (but collapsing keyframe view is permitted)
|
||||
splitter->setCollapsible(0, false);
|
||||
}
|
||||
|
||||
void NodeParamView::SetNodes(QList<Node *> nodes)
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include "node/node.h"
|
||||
#include "nodeparamviewitem.h"
|
||||
#include "widget/keyframeview/keyframeview.h"
|
||||
|
||||
class NodeParamView : public QWidget
|
||||
{
|
||||
@@ -38,6 +39,8 @@ public:
|
||||
private:
|
||||
QVBoxLayout* param_layout_;
|
||||
|
||||
KeyframeView* keyframe_view_;
|
||||
|
||||
QList<Node*> nodes_;
|
||||
|
||||
QList<NodeParamViewItem*> items_;
|
||||
|
||||
@@ -23,10 +23,14 @@
|
||||
#include <QCheckBox>
|
||||
#include <QDebug>
|
||||
#include <QEvent>
|
||||
#include <QMessageBox>
|
||||
#include <QPainter>
|
||||
|
||||
#include "nodeparamviewkeyframecontrol.h"
|
||||
#include "nodeparamviewundo.h"
|
||||
#include "project/item/sequence/sequence.h"
|
||||
#include "ui/icons/icons.h"
|
||||
#include "undo/undostack.h"
|
||||
|
||||
NodeParamViewItem::NodeParamViewItem(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
@@ -110,6 +114,7 @@ void NodeParamViewItem::SetupUI()
|
||||
foreach (NodeParam* param, first_node->parameters()) {
|
||||
// This widget only needs to show input parameters
|
||||
if (param->type() == NodeParam::kInput) {
|
||||
NodeInput* input = static_cast<NodeInput*>(param);
|
||||
|
||||
// Add descriptor label
|
||||
QLabel* param_label = new QLabel();
|
||||
@@ -119,7 +124,7 @@ void NodeParamViewItem::SetupUI()
|
||||
|
||||
// Create a widget/input bridge for this input
|
||||
NodeParamViewWidgetBridge* bridge = new NodeParamViewWidgetBridge(this);
|
||||
bridge->AddInput(static_cast<NodeInput*>(param));
|
||||
bridge->AddInput(input);
|
||||
bridges_.append(bridge);
|
||||
|
||||
// Add widgets for this parameter ot the layout
|
||||
@@ -128,6 +133,15 @@ void NodeParamViewItem::SetupUI()
|
||||
content_layout_->addWidget(widgets_for_param.at(i), row_count, i + 1);
|
||||
}
|
||||
|
||||
// Add keyframe control to this layout if parameter is keyframable
|
||||
if (input->is_keyframable()) {
|
||||
// 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);
|
||||
content_layout_->addWidget(key_control, row_count, control_column);
|
||||
}
|
||||
|
||||
row_count++;
|
||||
}
|
||||
}
|
||||
@@ -181,6 +195,49 @@ void NodeParamViewItem::SetExpanded(bool e)
|
||||
}
|
||||
}
|
||||
|
||||
void NodeParamViewItem::KeyframeEnableChanged(bool e)
|
||||
{
|
||||
NodeParamViewKeyframeControl* control = static_cast<NodeParamViewKeyframeControl*>(sender());
|
||||
NodeInput* input = control->GetConnectedInput();
|
||||
|
||||
if (e == input->is_keyframing()) {
|
||||
// No-op
|
||||
return;
|
||||
}
|
||||
|
||||
if (e) {
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// Enable keyframing
|
||||
new NodeParamSetKeyframing(input, true, command);
|
||||
|
||||
// FIXME: Create a keyframe at this time
|
||||
|
||||
olive::undo_stack.push(command);
|
||||
} else {
|
||||
// Confirm the user wants to clear all keyframes
|
||||
if (QMessageBox::warning(this,
|
||||
tr("Warning"),
|
||||
tr("Are you sure you want to disable keyframing on this value? This will clear all existing keyframes."),
|
||||
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
||||
// Disable keyframing
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// FIXME: Delete all keyframes
|
||||
|
||||
// Disable keyframing
|
||||
new NodeParamSetKeyframing(input, false, command);
|
||||
|
||||
olive::undo_stack.push(command);
|
||||
|
||||
} else {
|
||||
// Disable action has effectively been ignored
|
||||
control->SetKeyframeEnabled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NodeParamViewItemTitleBar::NodeParamViewItemTitleBar(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
|
||||
@@ -78,6 +78,8 @@ private:
|
||||
|
||||
private slots:
|
||||
void SetExpanded(bool e);
|
||||
|
||||
void KeyframeEnableChanged(bool e);
|
||||
};
|
||||
|
||||
#endif // NODEPARAMVIEWITEM_H
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
#include "nodeparamviewkeyframecontrol.h"
|
||||
|
||||
#include <QHBoxLayout>
|
||||
|
||||
#include "ui/icons/icons.h"
|
||||
|
||||
NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(NodeInput* input, QWidget *parent) :
|
||||
QWidget(parent),
|
||||
input_(input)
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->setMargin(0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
// Automatically right aligns all buttons
|
||||
layout->addStretch();
|
||||
|
||||
prev_key_btn_ = CreateNewToolButton(olive::icon::TriLeft);
|
||||
prev_key_btn_->setIconSize(prev_key_btn_->iconSize() / 2);
|
||||
layout->addWidget(prev_key_btn_);
|
||||
|
||||
toggle_key_btn_ = CreateNewToolButton(olive::icon::Diamond);
|
||||
toggle_key_btn_->setCheckable(true);
|
||||
toggle_key_btn_->setIconSize(toggle_key_btn_->iconSize() / 2);
|
||||
layout->addWidget(toggle_key_btn_);
|
||||
|
||||
next_key_btn_ = CreateNewToolButton(olive::icon::TriRight);
|
||||
next_key_btn_->setIconSize(next_key_btn_->iconSize() / 2);
|
||||
layout->addWidget(next_key_btn_);
|
||||
|
||||
enable_key_btn_ = CreateNewToolButton(olive::icon::Clock);
|
||||
enable_key_btn_->setCheckable(true);
|
||||
enable_key_btn_->setIconSize(enable_key_btn_->iconSize() / 4 * 3);
|
||||
layout->addWidget(enable_key_btn_);
|
||||
|
||||
connect(enable_key_btn_, SIGNAL(toggled(bool)), this, SLOT(ShowButtonsFromKeyframeEnable(bool)));
|
||||
connect(enable_key_btn_, SIGNAL(toggled(bool)), this, SIGNAL(KeyframeEnableChanged(bool)));
|
||||
|
||||
// Pick up keyframing value
|
||||
ShowButtonsFromKeyframeEnable(input_->is_keyframing());
|
||||
}
|
||||
|
||||
NodeInput *NodeParamViewKeyframeControl::GetConnectedInput() const
|
||||
{
|
||||
return input_;
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::SetKeyframeEnabled(bool e)
|
||||
{
|
||||
// Suppress KeyframeEnableChanged() signal from this object
|
||||
blockSignals(true);
|
||||
|
||||
enable_key_btn_->setChecked(e);
|
||||
|
||||
blockSignals(false);
|
||||
}
|
||||
|
||||
QPushButton *NodeParamViewKeyframeControl::CreateNewToolButton(const QIcon& icon) const
|
||||
{
|
||||
QPushButton* btn = new QPushButton();
|
||||
btn->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
|
||||
btn->setIcon(icon);
|
||||
|
||||
return btn;
|
||||
}
|
||||
|
||||
void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e)
|
||||
{
|
||||
prev_key_btn_->setVisible(e);
|
||||
toggle_key_btn_->setVisible(e);
|
||||
next_key_btn_->setVisible(e);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef NODEPARAMVIEWKEYFRAMECONTROL_H
|
||||
#define NODEPARAMVIEWKEYFRAMECONTROL_H
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
#include "node/input.h"
|
||||
|
||||
class NodeParamViewKeyframeControl : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
NodeParamViewKeyframeControl(NodeInput* input, QWidget* parent = nullptr);
|
||||
|
||||
NodeInput* GetConnectedInput() const;
|
||||
|
||||
public slots:
|
||||
void SetKeyframeEnabled(bool e);
|
||||
|
||||
signals:
|
||||
void KeyframeEnableChanged(bool);
|
||||
|
||||
private:
|
||||
QPushButton* CreateNewToolButton(const QIcon &icon) const;
|
||||
|
||||
QPushButton* prev_key_btn_;
|
||||
QPushButton* toggle_key_btn_;
|
||||
QPushButton* next_key_btn_;
|
||||
QPushButton* enable_key_btn_;
|
||||
|
||||
NodeInput* input_;
|
||||
|
||||
private slots:
|
||||
void ShowButtonsFromKeyframeEnable(bool e);
|
||||
};
|
||||
|
||||
#endif // NODEPARAMVIEWKEYFRAMECONTROL_H
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "nodeparamviewundo.h"
|
||||
|
||||
NodeParamSetKeyframing::NodeParamSetKeyframing(NodeInput *input, bool setting, QUndoCommand *parent) :
|
||||
QUndoCommand(parent),
|
||||
input_(input),
|
||||
setting_(setting)
|
||||
{
|
||||
Q_ASSERT(setting != input_->is_keyframing());
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframing::redo()
|
||||
{
|
||||
input_->set_is_keyframing(setting_);
|
||||
}
|
||||
|
||||
void NodeParamSetKeyframing::undo()
|
||||
{
|
||||
input_->set_is_keyframing(!setting_);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef NODEPARAMVIEWUNDO_H
|
||||
#define NODEPARAMVIEWUNDO_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
|
||||
#include "node/input.h"
|
||||
|
||||
class NodeParamSetKeyframing : public QUndoCommand {
|
||||
public:
|
||||
NodeParamSetKeyframing(NodeInput* input, bool setting, QUndoCommand* parent = nullptr);
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
private:
|
||||
NodeInput* input_;
|
||||
bool setting_;
|
||||
};
|
||||
|
||||
#endif // NODEPARAMVIEWUNDO_H
|
||||
Reference in New Issue
Block a user