implemented the ability to modify bezier points in the curve editor

This commit is contained in:
itsmattkc
2019-12-28 22:40:30 +11:00
parent 4cd5e103b8
commit 1d3d52db9b
23 changed files with 744 additions and 282 deletions
+1 -2
View File
@@ -479,8 +479,7 @@ void NodeInput::CopyValues(NodeInput *source, NodeInput *dest, bool include_conn
// Copy keyframes
dest->keyframes_.clear();
foreach (NodeKeyframePtr key, source->keyframes_) {
NodeKeyframePtr copy = std::make_shared<NodeKeyframe>(key->time(), key->value(), key->type());
dest->keyframes_.append(copy);
dest->keyframes_.append(key->copy());
}
// Copy keyframing state
+65 -8
View File
@@ -20,20 +20,28 @@
#include "keyframe.h"
NodeKeyframe::NodeKeyframe() :
time_(0),
value_(0),
type_(kLinear)
{
}
NodeKeyframe::NodeKeyframe(const rational &time, const QVariant &value, const NodeKeyframe::Type &type) :
time_(time),
value_(value),
type_(type)
type_(type),
bezier_control_in_(QPointF(-1.0, 0.0)),
bezier_control_out_(QPointF(1.0, 0.0))
{
}
NodeKeyframePtr NodeKeyframe::Create(const rational &time, const QVariant &value, const NodeKeyframe::Type &type)
{
return std::make_shared<NodeKeyframe>(time, value, type);
}
NodeKeyframePtr NodeKeyframe::copy() const
{
NodeKeyframePtr copy = std::make_shared<NodeKeyframe>(time_, value_, type_);
copy->bezier_control_in_ = bezier_control_in_;
copy->bezier_control_out_ = bezier_control_out_;
return copy;
}
const rational &NodeKeyframe::time() const
{
return time_;
@@ -66,3 +74,52 @@ void NodeKeyframe::set_type(const NodeKeyframe::Type &type)
type_ = type;
emit TypeChanged(type_);
}
const QPointF &NodeKeyframe::bezier_control_in() const
{
return bezier_control_in_;
}
void NodeKeyframe::set_bezier_control_in(const QPointF &control)
{
bezier_control_in_ = control;
emit BezierControlInChanged(bezier_control_in_);
}
const QPointF &NodeKeyframe::bezier_control_out() const
{
return bezier_control_out_;
}
void NodeKeyframe::set_bezier_control_out(const QPointF &control)
{
bezier_control_out_ = control;
emit BezierControlOutChanged(bezier_control_out_);
}
const QPointF &NodeKeyframe::bezier_control(NodeKeyframe::BezierType type) const
{
if (type == kInHandle) {
return bezier_control_in();
} else {
return bezier_control_out();
}
}
void NodeKeyframe::set_bezier_control(NodeKeyframe::BezierType type, const QPointF &control)
{
if (type == kInHandle) {
set_bezier_control_in(control);
} else {
set_bezier_control_out(control);
}
}
NodeKeyframe::BezierType NodeKeyframe::get_opposing_bezier_type(NodeKeyframe::BezierType type)
{
if (type == kInHandle) {
return kOutHandle;
} else {
return kInHandle;
}
}
+45 -5
View File
@@ -36,7 +36,6 @@ class NodeKeyframe : public QObject
{
Q_OBJECT
public:
/**
* @brief Methods of interpolation to use with this keyframe
*/
@@ -46,18 +45,25 @@ public:
kBezier
};
static const Type kDefaultType = kLinear;
/**
* @brief NodeKeyframe Constructor
* @brief The two types of bezier handles that are available on bezier keyframes
*/
NodeKeyframe();
enum BezierType {
kInHandle,
kOutHandle
};
/**
* @brief NodeKeyframe Constructor
*/
NodeKeyframe(const rational& time, const QVariant& value, const Type& type);
static const Type kDefaultType = kLinear;
static NodeKeyframePtr Create(const rational& time, const QVariant& value, const Type& type);
NodeKeyframePtr copy() const;
/**
* @brief The time this keyframe is set at
*/
@@ -76,6 +82,26 @@ public:
const Type& type() const;
void set_type(const Type& type);
/**
* @brief For bezier interpolation, the control point leading into this keyframe
*/
const QPointF &bezier_control_in() const;
void set_bezier_control_in(const QPointF& control);
/**
* @brief For bezier interpolation, the control point leading out of this keyframe
*/
const QPointF& bezier_control_out() const;
void set_bezier_control_out(const QPointF& control);
/**
* @brief Convenience functions for retrieving/setting bezier handle information with a BezierType
*/
const QPointF& bezier_control(BezierType type) const;
void set_bezier_control(BezierType type, const QPointF& control);
static BezierType get_opposing_bezier_type(BezierType type);
signals:
/**
* @brief Signal emitted when this keyframe's time is changed
@@ -92,12 +118,26 @@ signals:
*/
void TypeChanged(const Type& type);
/**
* @brief Signal emitted when this keyframe's bezier in control point is changed
*/
void BezierControlInChanged(const QPointF& d);
/**
* @brief Signal emitted when this keyframe's bezier out control point is changed
*/
void BezierControlOutChanged(const QPointF& d);
private:
rational time_;
QVariant value_;
Type type_;
QPointF bezier_control_in_;
QPointF bezier_control_out_;
};
Q_DECLARE_METATYPE(NodeKeyframe::Type)
+2
View File
@@ -16,6 +16,8 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/curvewidget/beziercontrolpointitem.h
widget/curvewidget/beziercontrolpointitem.cpp
widget/curvewidget/curveview.h
widget/curvewidget/curveview.cpp
widget/curvewidget/curvewidget.h
@@ -0,0 +1,80 @@
#include "beziercontrolpointitem.h"
#include <QApplication>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QWidget>
#include "common/qtversionabstraction.h"
BezierControlPointItem::BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe::BezierType mode, QGraphicsItem *parent) :
QGraphicsRectItem(parent),
key_(key),
mode_(mode),
x_scale_(1.0),
y_scale_(1.0)
{
setFlag(QGraphicsItem::ItemIsMovable);
connect(key.get(), &NodeKeyframe::TimeChanged, this, &BezierControlPointItem::UpdatePos);
if (mode_ == NodeKeyframe::kInHandle) {
connect(key.get(), &NodeKeyframe::BezierControlInChanged, this, &BezierControlPointItem::UpdatePos);
} else {
connect(key.get(), &NodeKeyframe::BezierControlOutChanged, this, &BezierControlPointItem::UpdatePos);
}
int control_point_size = QFontMetricsWidth(qApp->fontMetrics(), "o");
int half_sz = control_point_size / 2;
setRect(-half_sz, -half_sz, control_point_size, control_point_size);
}
void BezierControlPointItem::SetXScale(double scale)
{
x_scale_ = scale;
UpdatePos();
}
void BezierControlPointItem::SetYScale(double scale)
{
y_scale_ = scale;
UpdatePos();
}
NodeKeyframePtr BezierControlPointItem::key() const
{
return key_;
}
const NodeKeyframe::BezierType &BezierControlPointItem::mode() const
{
return mode_;
}
QPointF BezierControlPointItem::GetCorrespondingKeyframeHandle() const
{
return key_->bezier_control(mode_);
}
void BezierControlPointItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
if (option->state & QStyle::State_Selected) {
painter->setPen(widget->palette().highlight().color());
} else {
painter->setPen(widget->palette().text().color());
}
painter->drawEllipse(rect());
}
void BezierControlPointItem::UpdatePos()
{
QPointF handle_offset = GetCorrespondingKeyframeHandle();
// Scale handle offset
handle_offset.setX(handle_offset.x() * x_scale_);
handle_offset.setY(handle_offset.y() * y_scale_);
setPos(handle_offset - rect().center());
}
@@ -0,0 +1,44 @@
#ifndef BEZIERCONTROLPOINTITEM_H
#define BEZIERCONTROLPOINTITEM_H
#include <QGraphicsRectItem>
#include "node/keyframe.h"
class BezierControlPointItem : public QObject, public QGraphicsRectItem
{
public:
BezierControlPointItem(NodeKeyframePtr key, NodeKeyframe::BezierType mode, QGraphicsItem* parent = nullptr);
void SetXScale(double scale);
void SetYScale(double scale);
NodeKeyframePtr key() const;
const NodeKeyframe::BezierType& mode() const;
QPointF GetCorrespondingKeyframeHandle() const;
void SetCorrespondingKeyframeHandle(const QPointF& handle);
void SetOpposingKeyframeHandle(const QPointF& handle);
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
NodeKeyframePtr key_;
NodeKeyframe::BezierType mode_;
double x_scale_;
double y_scale_;
private slots:
void UpdatePos();
};
#endif // BEZIERCONTROLPOINTITEM_H
+113 -12
View File
@@ -1,5 +1,6 @@
#include "curveview.h"
#include <QMouseEvent>
#include <QtMath>
#include "common/qtversionabstraction.h"
@@ -15,6 +16,14 @@ CurveView::CurveView(QWidget *parent) :
text_padding_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("i"));
minimum_grid_space_ = QFontMetricsWidth(fontMetrics(), QStringLiteral("00000"));
connect(scene(), &QGraphicsScene::selectionChanged, this, &CurveView::SelectionChanged);
}
CurveView::~CurveView()
{
// Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after other memebers have been destroyed
Clear();
}
void CurveView::Clear()
@@ -24,7 +33,6 @@ void CurveView::Clear()
foreach (QGraphicsLineItem* line, lines_) {
delete line;
}
lines_.clear();
}
@@ -40,6 +48,8 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
return;
}
painter->setRenderHint(QPainter::Antialiasing);
QVector<QLine> lines;
double x_interval = timebase().flipped().toDouble();
@@ -89,7 +99,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
QVector<QLineF> keyframe_lines;
// Draw straight line leading to first keyframe
QPointF first_key_pos = item_map().value(keys.first())->center_pos();
QPointF first_key_pos = item_map().value(keys.first())->pos();
keyframe_lines.append(QLineF(QPointF(scene_bottom_left.x(), first_key_pos.y()), first_key_pos));
// Draw lines between each keyframe
@@ -102,30 +112,76 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
if (before->type() == NodeKeyframe::kHold) {
// Draw a hold keyframe (basically a right angle)
keyframe_lines.append(QLineF(before_item->center_pos().x(),
before_item->center_pos().y(),
after_item->center_pos().x(),
before_item->center_pos().y()));
keyframe_lines.append(QLineF(after_item->center_pos().x(),
before_item->center_pos().y(),
after_item->center_pos().x(),
after_item->center_pos().y()));
keyframe_lines.append(QLineF(before_item->pos().x(),
before_item->pos().y(),
after_item->pos().x(),
before_item->pos().y()));
keyframe_lines.append(QLineF(after_item->pos().x(),
before_item->pos().y(),
after_item->pos().x(),
after_item->pos().y()));
} else if (before->type() == NodeKeyframe::kBezier && after->type() == NodeKeyframe::kBezier) {
// Draw a cubic bezier
// Cubic beziers have two control points, so we can just use both
QPointF before_control_point = before_item->pos() + ScalePoint(before->bezier_control_out());
QPointF after_control_point = after_item->pos() + ScalePoint(after->bezier_control_in());
QPainterPath path;
path.moveTo(before_item->pos());
path.cubicTo(before_control_point, after_control_point, after_item->pos());
painter->drawPath(path);
} else if (before->type() == NodeKeyframe::kBezier || after->type() == NodeKeyframe::kBezier) {
// Draw a quadratic bezier
// Quadratic beziers have a single control point, we just have to determine which it is
QPointF key_anchor;
QPointF control_point;
if (before->type() == NodeKeyframe::kBezier) {
key_anchor = before_item->pos();
control_point = before->bezier_control_out();
} else {
key_anchor = after_item->pos();
control_point = after->bezier_control_in();
}
// Scale control point
control_point = key_anchor + ScalePoint(control_point);
// Create the path from both keyframes
QPainterPath path;
path.moveTo(before_item->pos());
path.quadTo(control_point, after_item->pos());
painter->drawPath(path);
} else {
// Linear to linear
keyframe_lines.append(QLineF(before_item->center_pos(), after_item->center_pos()));
keyframe_lines.append(QLineF(before_item->pos(), after_item->pos()));
}
}
// Draw straight line leading from end keyframe
QPointF last_key_pos = item_map().value(keys.last())->center_pos();
QPointF last_key_pos = item_map().value(keys.last())->pos();
keyframe_lines.append(QLineF(last_key_pos, QPointF(scene_top_right.x(), last_key_pos.y())));
painter->drawLines(keyframe_lines);
}
// Draw bezier control point lines
if (!bezier_control_points_.isEmpty()) {
painter->setPen(QPen(palette().text().color(), 1));
QVector<QLineF> bezier_lines;
foreach (BezierControlPointItem* item, bezier_control_points_) {
// All BezierControlPointItems should be children of a KeyframeViewItem
KeyframeViewItem* par = static_cast<KeyframeViewItem*>(item->parentItem());
bezier_lines.append(QLineF(par->pos(), par->pos() + item->pos()));
}
painter->drawLines(bezier_lines);
}
}
void CurveView::KeyframeAboutToBeRemoved(NodeKeyframe *key)
@@ -133,6 +189,15 @@ void CurveView::KeyframeAboutToBeRemoved(NodeKeyframe *key)
disconnect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
}
void CurveView::ScaleChangedEvent(double scale)
{
KeyframeViewBase::ScaleChangedEvent(scale);
foreach (BezierControlPointItem* item, bezier_control_points_) {
item->SetXScale(scale);
}
}
QList<NodeKeyframe *> CurveView::GetKeyframesSortedByTime()
{
QList<NodeKeyframe *> sorted;
@@ -169,6 +234,11 @@ void CurveView::SetItemYFromKeyframeValue(NodeKeyframe *key, KeyframeViewItem *i
item->SetOverrideY(GetItemYFromKeyframeValue(key));
}
QPointF CurveView::ScalePoint(const QPointF &point)
{
return QPointF(point.x() * scale_, point.y() * y_scale_);
}
void CurveView::KeyframeValueChanged()
{
NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
@@ -177,6 +247,37 @@ void CurveView::KeyframeValueChanged()
SetItemYFromKeyframeValue(key, item);
}
void CurveView::SelectionChanged()
{
// Clear current bezier handles
foreach (BezierControlPointItem* item, bezier_control_points_) {
delete item;
}
bezier_control_points_.clear();
QList<QGraphicsItem*> selected = scene()->selectedItems();
foreach (QGraphicsItem* item, selected) {
KeyframeViewItem* this_item = static_cast<KeyframeViewItem*>(item);
BezierControlPointItem* bezier_in_pt = new BezierControlPointItem(this_item->key(), NodeKeyframe::kInHandle, item);
bezier_in_pt->SetXScale(scale_);
bezier_control_points_.append(bezier_in_pt);
connect(bezier_in_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection);
BezierControlPointItem* bezier_out_pt = new BezierControlPointItem(this_item->key(), NodeKeyframe::kOutHandle, item);
bezier_out_pt->SetXScale(scale_);
bezier_control_points_.append(bezier_out_pt);
connect(bezier_out_pt, &QObject::destroyed, this, &CurveView::BezierControlPointDestroyed, Qt::DirectConnection);
}
}
void CurveView::BezierControlPointDestroyed()
{
BezierControlPointItem* item = static_cast<BezierControlPointItem*>(sender());
bezier_control_points_.removeOne(item);
}
void CurveView::AddKeyframe(NodeKeyframePtr key)
{
KeyframeViewItem* item = AddKeyframeInternal(key);
+13
View File
@@ -1,6 +1,7 @@
#ifndef CURVEVIEW_H
#define CURVEVIEW_H
#include "beziercontrolpointitem.h"
#include "node/keyframe.h"
#include "widget/keyframeview/keyframeview.h"
#include "widget/keyframeview/keyframeviewitem.h"
@@ -10,6 +11,8 @@ class CurveView : public KeyframeViewBase
public:
CurveView(QWidget* parent = nullptr);
virtual ~CurveView() override;
virtual void Clear() override;
void SetYScale(const double& y_scale);
@@ -22,6 +25,8 @@ protected:
virtual void KeyframeAboutToBeRemoved(NodeKeyframe *key) override;
virtual void ScaleChangedEvent(double scale) override;
private:
QList<NodeKeyframe*> GetKeyframesSortedByTime();
@@ -29,6 +34,8 @@ private:
void SetItemYFromKeyframeValue(NodeKeyframe* key, KeyframeViewItem* item);
QPointF ScalePoint(const QPointF& point);
void AdjustLines();
int text_padding_;
@@ -39,9 +46,15 @@ private:
QList<QGraphicsLineItem*> lines_;
QList<BezierControlPointItem*> bezier_control_points_;
private slots:
void KeyframeValueChanged();
void SelectionChanged();
void BezierControlPointDestroyed();
};
#endif // CURVEVIEW_H
+15 -8
View File
@@ -9,7 +9,6 @@
#include "common/timecodefunctions.h"
#include "node/node.h"
#include "widget/keyframeview/keyframeviewundo.h"
#include "widget/nodeparamview/nodeparamviewkeyframecontrol.h"
CurveWidget::CurveWidget(QWidget *parent) :
QWidget(parent),
@@ -20,12 +19,9 @@ CurveWidget::CurveWidget(QWidget *parent) :
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);
key_control_ = new NodeParamViewKeyframeControl(false);
connect(key_control_, &NodeParamViewKeyframeControl::RequestSetTime, this, &CurveWidget::KeyControlRequestedTimeChanged);
top_controls->addWidget(key_control_);
top_controls->addStretch();
@@ -83,7 +79,7 @@ CurveWidget::CurveWidget(QWidget *parent) :
CurveWidget::~CurveWidget()
{
// Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after the buttons have been destroyed
// Quick way to avoid segfault when QGraphicsScene::selectionChanged is emitted after other memebers have been destroyed
view_->Clear();
}
@@ -105,6 +101,7 @@ void CurveWidget::SetInput(NodeInput *input)
view_->Clear();
input_ = input;
key_control_->SetInput(input_);
if (input_) {
bridge_ = new NodeParamViewWidgetBridge(input_, this);
@@ -195,6 +192,7 @@ void CurveWidget::UpdateBridgeTime(const int64_t &timestamp)
rational time = Timecode::timestamp_to_time(timestamp, view_->timebase());
bridge_->SetTime(time);
key_control_->SetTime(time);
}
void CurveWidget::SelectionChanged()
@@ -265,3 +263,12 @@ void CurveWidget::KeyframeTypeButtonTriggered(bool checked)
Core::instance()->undo_stack()->push(command);
}
void CurveWidget::KeyControlRequestedTimeChanged(const rational &time)
{
int64_t timestamp = Timecode::time_to_timestamp(time, view_->timebase());
SetTime(timestamp);
emit TimeChanged(timestamp);
}
+5
View File
@@ -7,6 +7,7 @@
#include "curveview.h"
#include "node/input.h"
#include "widget/nodeparamview/nodeparamviewkeyframecontrol.h"
#include "widget/nodeparamview/nodeparamviewwidgetbridge.h"
#include "widget/timeruler/timeruler.h"
@@ -60,6 +61,8 @@ private:
NodeParamViewWidgetBridge* bridge_;
NodeParamViewKeyframeControl* key_control_;
private slots:
void UpdateBridgeTime(const int64_t& timestamp);
@@ -67,6 +70,8 @@ private slots:
void KeyframeTypeButtonTriggered(bool checked);
void KeyControlRequestedTimeChanged(const rational& time);
};
#endif // CURVEWIDGET_H
+126 -30
View File
@@ -9,7 +9,8 @@
#include "widget/nodeparamview/nodeparamviewundo.h"
KeyframeViewBase::KeyframeViewBase(QWidget *parent) :
TimelineViewBase(parent)
TimelineViewBase(parent),
dragging_bezier_point_(nullptr)
{
setDragMode(RubberBandDrag);
setContextMenuPolicy(Qt::CustomContextMenu);
@@ -62,16 +63,25 @@ void KeyframeViewBase::mousePressEvent(QMouseEvent *event)
QGraphicsItem* item_under_cursor = itemAt(event->pos());
if (item_under_cursor) {
QList<QGraphicsItem*> selected_items = scene()->selectedItems();
drag_start_ = event->pos();
selected_keys_.resize(selected_items.size());
// Determine what type of item is under the cursor
dragging_bezier_point_ = dynamic_cast<BezierControlPointItem*>(item_under_cursor);
for (int i=0;i<selected_items.size();i++) {
KeyframeViewItem* key = static_cast<KeyframeViewItem*>(selected_items.at(i));
if (dragging_bezier_point_) {
dragging_bezier_point_start_ = dragging_bezier_point_->GetCorrespondingKeyframeHandle();
dragging_bezier_point_opposing_start_ = dragging_bezier_point_->key()->bezier_control(NodeKeyframe::get_opposing_bezier_type(dragging_bezier_point_->mode()));
} else {
QList<QGraphicsItem*> selected_items = scene()->selectedItems();
selected_keys_.replace(i, {key, key->x(), key->key()->time()});
selected_keys_.resize(selected_items.size());
for (int i=0;i<selected_items.size();i++) {
KeyframeViewItem* key = static_cast<KeyframeViewItem*>(selected_items.at(i));
selected_keys_.replace(i, {key, key->x(), key->key()->time()});
}
}
}
}
@@ -87,13 +97,19 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
if (event->buttons() & Qt::LeftButton) {
QGraphicsView::mouseMoveEvent(event);
if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) {
int x_diff = event->pos().x() - drag_start_.x();
double x_diff_scaled = static_cast<double>(x_diff) / scale_;
if (active_tool_ == Tool::kPointer) {
// Calculate cursor difference and scale it
QPointF mouse_diff_scaled = GetScaledCursorPos(event->pos() - drag_start_);
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
// FIXME: Find some way to do single frame updates as the NodeParamViewWidgetBridge does?
keypair.key->key()->set_time(CalculateNewTimeFromScreen(keypair.time, x_diff_scaled));
if (dragging_bezier_point_) {
ProcessBezierDrag(mouse_diff_scaled,
!(event->modifiers() & Qt::ControlModifier),
false);
} else if (!selected_keys_.isEmpty()) {
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
// FIXME: Find some way to do single frame updates as the NodeParamViewWidgetBridge does?
keypair.key->key()->set_time(CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()));
}
}
}
}
@@ -108,29 +124,38 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
if (event->button() == Qt::LeftButton) {
QGraphicsView::mouseReleaseEvent(event);
if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) {
QUndoCommand* command = new QUndoCommand();
if (active_tool_ == Tool::kPointer) {
QPoint mouse_diff = event->pos() - drag_start_;
QPointF mouse_diff_scaled = GetScaledCursorPos(mouse_diff);
// Calculate X movement and scaling to timeline time
int x_diff = event->pos().x() - drag_start_.x();
double x_diff_scaled = static_cast<double>(x_diff) / scale_;
if (!mouse_diff.isNull()) {
if (dragging_bezier_point_) {
ProcessBezierDrag(mouse_diff_scaled,
!(event->modifiers() & Qt::ControlModifier),
true);
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
KeyframeViewItem* item = keypair.key;
dragging_bezier_point_ = nullptr;
} else if (!selected_keys_.isEmpty()) {
QUndoCommand* command = new QUndoCommand();
// Calculate the new time for this keyframe
rational new_time = CalculateNewTimeFromScreen(keypair.time, x_diff_scaled);
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
KeyframeViewItem* item = keypair.key;
// Commit movement
new NodeParamSetKeyframeTimeCommand(item->key(),
new_time,
keypair.time,
command);
// Calculate the new time for this keyframe
rational new_time = CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x());
// Commit movement
new NodeParamSetKeyframeTimeCommand(item->key(),
new_time,
keypair.time,
command);
}
Core::instance()->undo_stack()->push(command);
selected_keys_.clear();
}
}
Core::instance()->undo_stack()->push(command);
selected_keys_.clear();
}
}
}
@@ -158,6 +183,77 @@ rational KeyframeViewBase::CalculateNewTimeFromScreen(const rational &old_time,
return rational::fromDouble(old_time.toDouble() + cursor_diff);
}
QPointF KeyframeViewBase::GenerateBezierControlPosition(const NodeKeyframe::BezierType mode, const QPointF &start_point, const QPointF &scaled_cursor_diff)
{
QPointF new_bezier_pos = start_point;
new_bezier_pos += scaled_cursor_diff;
// LIMIT bezier handles from overlapping each other
if (mode == NodeKeyframe::kInHandle) {
if (new_bezier_pos.x() > 0) {
new_bezier_pos.setX(0);
}
} else {
if (new_bezier_pos.x() < 0) {
new_bezier_pos.setX(0);
}
}
return new_bezier_pos;
}
void KeyframeViewBase::ProcessBezierDrag(const QPointF& mouse_diff_scaled, bool include_opposing, bool undoable)
{
QPointF new_bezier_pos = GenerateBezierControlPosition(dragging_bezier_point_->mode(),
dragging_bezier_point_start_,
mouse_diff_scaled);
// If the user is NOT holding control, we set the other handle to the exact negative of this handle
QPointF new_opposing_pos;
NodeKeyframe::BezierType opposing_type = NodeKeyframe::get_opposing_bezier_type(dragging_bezier_point_->mode());
if (include_opposing) {
new_opposing_pos = GenerateBezierControlPosition(opposing_type,
dragging_bezier_point_opposing_start_,
-mouse_diff_scaled);
} else {
new_opposing_pos = dragging_bezier_point_opposing_start_;
}
dragging_bezier_point_->key()->set_bezier_control(dragging_bezier_point_->mode(),
new_bezier_pos);
dragging_bezier_point_->key()->set_bezier_control(opposing_type,
new_opposing_pos);
if (undoable) {
QUndoCommand* command = new QUndoCommand();
new KeyframeSetBezierControlPoint(dragging_bezier_point_->key(),
dragging_bezier_point_->mode(),
new_bezier_pos,
dragging_bezier_point_start_,
command);
if (include_opposing) {
new KeyframeSetBezierControlPoint(dragging_bezier_point_->key(),
opposing_type,
new_opposing_pos,
dragging_bezier_point_opposing_start_,
command);
}
Core::instance()->undo_stack()->push(command);
}
}
QPointF KeyframeViewBase::GetScaledCursorPos(const QPoint &cursor_pos)
{
return QPointF (static_cast<double>(cursor_pos.x()) / scale_,
cursor_pos.y());;
}
void KeyframeViewBase::ShowContextMenu()
{
Menu m;
@@ -4,6 +4,7 @@
#include "core.h"
#include "keyframeviewitem.h"
#include "node/keyframe.h"
#include "widget/curvewidget/beziercontrolpointitem.h"
#include "widget/timelinewidget/view/timelineviewbase.h"
class KeyframeViewBase : public TimelineViewBase
@@ -33,6 +34,14 @@ protected:
private:
rational CalculateNewTimeFromScreen(const rational& old_time, double cursor_diff);
static QPointF GenerateBezierControlPosition(const NodeKeyframe::BezierType mode,
const QPointF& start_point,
const QPointF& scaled_cursor_diff);
void ProcessBezierDrag(const QPointF& mouse_diff_scaled, bool include_opposing, bool undoable);
QPointF GetScaledCursorPos(const QPoint& cursor_pos);
struct KeyframeItemAndTime {
KeyframeViewItem* key;
qreal item_x;
@@ -45,6 +54,10 @@ private:
QPoint drag_start_;
BezierControlPointItem* dragging_bezier_point_;
QPointF dragging_bezier_point_start_;
QPointF dragging_bezier_point_opposing_start_;
QVector<KeyframeItemAndTime> selected_keys_;
private slots:
+4 -8
View File
@@ -13,13 +13,14 @@ KeyframeViewItem::KeyframeViewItem(NodeKeyframePtr key, QGraphicsItem *parent) :
scale_(1.0),
vert_center_(0)
{
keyframe_size_ = QFontMetricsWidth(qApp->fontMetrics(), "Oi");
setFlag(QGraphicsItem::ItemIsSelectable);
connect(key.get(), &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdatePos);
connect(key.get(), &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw);
setRect(0, 0, keyframe_size_, keyframe_size_);
int keyframe_size = QFontMetricsWidth(qApp->fontMetrics(), "Oi");
int half_sz = keyframe_size/2;
setRect(-half_sz, -half_sz, keyframe_size, keyframe_size);
UpdatePos();
}
@@ -41,11 +42,6 @@ NodeKeyframePtr KeyframeViewItem::key() const
return key_;
}
QPointF KeyframeViewItem::center_pos() const
{
return pos() + rect().center();
}
void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setPen(Qt::black);
@@ -82,7 +78,7 @@ void KeyframeViewItem::UpdatePos()
{
double x_center = key_->time().toDouble() * scale_;
setPos(x_center - keyframe_size_/2, vert_center_ - keyframe_size_/2);
setPos(x_center, vert_center_);
}
void KeyframeViewItem::Redraw()
@@ -17,8 +17,6 @@ public:
NodeKeyframePtr key() const;
QPointF center_pos() const;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
@@ -29,8 +27,6 @@ private:
qreal vert_center_;
int keyframe_size_;
private slots:
void UpdatePos();
@@ -17,3 +17,31 @@ void KeyframeSetTypeCommand::undo()
{
key_->set_type(old_type_);
}
KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand *parent) :
QUndoCommand(parent),
key_(key),
mode_(mode),
old_point_(key->bezier_control(mode_)),
new_point_(point)
{
}
KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF &new_point, const QPointF &old_point, QUndoCommand *parent) :
QUndoCommand(parent),
key_(key),
mode_(mode),
old_point_(old_point),
new_point_(new_point)
{
}
void KeyframeSetBezierControlPoint::redo()
{
key_->set_bezier_control(mode_, new_point_);
}
void KeyframeSetBezierControlPoint::undo()
{
key_->set_bezier_control(mode_, old_point_);
}
@@ -21,4 +21,23 @@ private:
};
class KeyframeSetBezierControlPoint : public QUndoCommand {
public:
KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& point, QUndoCommand* parent = nullptr);
KeyframeSetBezierControlPoint(NodeKeyframePtr key, NodeKeyframe::BezierType mode, const QPointF& new_point, const QPointF& old_point, QUndoCommand* parent = nullptr);
virtual void redo() override;
virtual void undo() override;
private:
NodeKeyframePtr key_;
NodeKeyframe::BezierType mode_;
QPointF old_point_;
QPointF new_point_;
};
#endif // KEYFRAMEVIEWUNDO_H
+2 -128
View File
@@ -23,7 +23,6 @@
#include <QCheckBox>
#include <QDebug>
#include <QEvent>
#include <QMessageBox>
#include <QPainter>
#include "core.h"
@@ -84,7 +83,7 @@ void NodeParamViewItem::SetTime(const rational &time)
}
foreach (NodeParamViewKeyframeControl* key_control, key_control_list_) {
UpdateKeyframeControl(key_control);
key_control->SetTime(time_);
}
}
@@ -121,9 +120,6 @@ void NodeParamViewItem::InputAddedKeyframeInternal(NodeInput *input, NodeKeyfram
// Find global position
lbl_center = lbl->mapToGlobal(lbl_center);
// Update keyframe control widget
UpdateKeyframeControl(KeyframeControlFromInput(input));
emit KeyframeAdded(keyframe, lbl_center.y());
}
@@ -163,10 +159,7 @@ void NodeParamViewItem::SetupUI()
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);
connect(key_control, &NodeParamViewKeyframeControl::GoToNextKey, this, &NodeParamViewItem::GoToNextKey);
connect(key_control, &NodeParamViewKeyframeControl::KeyframeToggled, this, &NodeParamViewItem::UserToggledKeyframe);
connect(key_control, &NodeParamViewKeyframeControl::RequestSetTime, this, &NodeParamViewItem::RequestSetTime);
key_control_list_.append(key_control);
connect(input, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewItem::InputKeyframeEnableChanged);
@@ -199,16 +192,6 @@ void NodeParamViewItem::Retranslate()
}
}
void NodeParamViewItem::UpdateKeyframeControl(NodeParamViewKeyframeControl *key_control)
{
NodeInput* input = key_control->GetConnectedInput();
// Update UI based on time
key_control->SetPreviousButtonEnabled(!input->keyframes().isEmpty() && time_ > input->keyframes().first()->time());
key_control->SetNextButtonEnabled(!input->keyframes().isEmpty() && time_ < input->keyframes().last()->time());
key_control->SetToggleButtonChecked(input->has_keyframe_at_time(time_));
}
NodeParamViewKeyframeControl *NodeParamViewItem::KeyframeControlFromInput(NodeInput *input) const
{
foreach (NodeParamViewKeyframeControl* key_control, key_control_list_) {
@@ -233,83 +216,6 @@ void NodeParamViewItem::SetExpanded(bool e)
}
}
void NodeParamViewItem::UserChangedKeyframeEnable(bool e)
{
NodeParamViewKeyframeControl* control = static_cast<NodeParamViewKeyframeControl*>(sender());
NodeInput* input = control->GetConnectedInput();
if (e == input->is_keyframing()) {
// No-op
return;
}
QUndoCommand* command = new QUndoCommand();
if (e) {
// Enable keyframing
new NodeParamSetKeyframingCommand(input, true, command);
// NodeInputs already have one keyframe by default, we move it to the current time here
NodeKeyframePtr key = std::make_shared<NodeKeyframe>(time_, input->get_standard_value(), NodeKeyframe::kDefaultType);
new NodeParamInsertKeyframeCommand(input, key, 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) {
// Store value at this time, we'll set this as the persistent value later
QVariant stored_val = input->get_value_at_time(time_);
// Delete all keyframes
for (int i=input->keyframes().size()-1;i>=0;i--) {
new NodeParamRemoveKeyframeCommand(input, input->keyframes().at(i), command);
}
// Update standard value
new NodeParamSetStandardValueCommand(input, stored_val, command);
// Disable keyframing
new NodeParamSetKeyframingCommand(input, false, command);
} else {
// Disable action has effectively been ignored
control->SetKeyframeEnabled(true);
}
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void NodeParamViewItem::UserToggledKeyframe(bool e)
{
NodeParamViewKeyframeControl* control = static_cast<NodeParamViewKeyframeControl*>(sender());
NodeInput* input = control->GetConnectedInput();
NodeKeyframePtr key = input->get_keyframe_at_time(time_);
QUndoCommand* command = new QUndoCommand();
if (e && !key) {
// Add a keyframe here
key = std::make_shared<NodeKeyframe>(time_,
input->get_value_at_time(time_),
input->get_best_keyframe_type_for_time(time_));
new NodeParamInsertKeyframeCommand(input, key, command);
} else if (!e && key) {
// Remove a keyframe here
new NodeParamRemoveKeyframeCommand(input, key, command);
// If this was the last keyframe, we'll set the standard value to the value at this time too
if (input->keyframes().size() == 1) {
new NodeParamSetStandardValueCommand(input, key->value(), command);
}
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void NodeParamViewItem::InputKeyframeEnableChanged(bool e)
{
NodeInput* input = static_cast<NodeInput*>(sender());
@@ -333,38 +239,6 @@ void NodeParamViewItem::InputAddedKeyframe(NodeKeyframePtr key)
InputAddedKeyframeInternal(input, key);
}
void NodeParamViewItem::GoToPreviousKey()
{
NodeParamViewKeyframeControl* key_control = static_cast<NodeParamViewKeyframeControl*>(sender());
NodeInput* input = key_control->GetConnectedInput();
for (int i=input->keyframes().size()-1;i>=0;i--) {
// Find closest keyframe that is before this time
const rational& this_key_time = input->keyframes().at(i)->time();
if (this_key_time < time_) {
emit RequestSetTime(this_key_time);
break;
}
}
}
void NodeParamViewItem::GoToNextKey()
{
NodeParamViewKeyframeControl* key_control = static_cast<NodeParamViewKeyframeControl*>(sender());
NodeInput* input = key_control->GetConnectedInput();
for (int i=0;i<input->keyframes().size();i++) {
// Find closest keyframe that is before this time
const rational& this_key_time = input->keyframes().at(i)->time();
if (this_key_time > time_) {
emit RequestSetTime(this_key_time);
break;
}
}
}
void NodeParamViewItem::LabelClicked()
{
ClickableLabel* lbl = static_cast<ClickableLabel*>(sender());
@@ -70,8 +70,6 @@ private:
void Retranslate();
void UpdateKeyframeControl(NodeParamViewKeyframeControl* key_control);
NodeParamViewKeyframeControl* KeyframeControlFromInput(NodeInput* input) const;
bool expanded_;
@@ -101,18 +99,10 @@ private:
private slots:
void SetExpanded(bool e);
void UserChangedKeyframeEnable(bool e);
void UserToggledKeyframe(bool e);
void InputKeyframeEnableChanged(bool e);
void InputAddedKeyframe(NodeKeyframePtr key);
void GoToPreviousKey();
void GoToNextKey();
void LabelClicked();
};
@@ -1,7 +1,10 @@
#include "nodeparamviewkeyframecontrol.h"
#include <QHBoxLayout>
#include <QMessageBox>
#include "core.h"
#include "nodeparamviewundo.h"
#include "ui/icons/icons.h"
NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(bool right_align, QWidget *parent) :
@@ -37,9 +40,13 @@ NodeParamViewKeyframeControl::NodeParamViewKeyframeControl(bool right_align, QWi
connect(prev_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::GoToPreviousKey);
connect(next_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::GoToNextKey);
connect(toggle_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::KeyframeToggled);
connect(toggle_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::ToggleKeyframe);
connect(enable_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable);
connect(enable_key_btn_, &QPushButton::toggled, this, &NodeParamViewKeyframeControl::KeyframeEnableChanged);
connect(enable_key_btn_, &QPushButton::clicked, this, &NodeParamViewKeyframeControl::KeyframeEnableChanged);
// Set defaults
SetInput(nullptr);
ShowButtonsFromKeyframeEnable(false);
}
NodeInput *NodeParamViewKeyframeControl::GetConnectedInput() const
@@ -47,60 +54,35 @@ NodeInput *NodeParamViewKeyframeControl::GetConnectedInput() const
return input_;
}
void NodeParamViewKeyframeControl::SetPreviousButtonEnabled(bool enabled)
{
prev_key_btn_->setEnabled(enabled);
}
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
blockSignals(true);
toggle_key_btn_->setChecked(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);
disconnect(input_, &NodeInput::KeyframeEnableChanged, enable_key_btn_, &QPushButton::setChecked);
disconnect(input_, &NodeInput::KeyframeAdded, this, &NodeParamViewKeyframeControl::UpdateState);
disconnect(input_, &NodeInput::KeyframeRemoved, this, &NodeParamViewKeyframeControl::UpdateState);
}
input_ = input;
SetButtonsEnabled(input_);
// Pick up keyframing value
enable_key_btn_->setChecked(input_ && input_->is_keyframing());
// Update buttons
UpdateState();
if (input_ != nullptr) {
connect(input_, &NodeInput::KeyframeEnableChanged, this, &NodeParamViewKeyframeControl::SetKeyframeEnabled);
// Pick up keyframing value
ShowButtonsFromKeyframeEnable(input_->is_keyframing());
connect(input_, &NodeInput::KeyframeEnableChanged, enable_key_btn_, &QPushButton::setChecked);
connect(input_, &NodeInput::KeyframeAdded, this, &NodeParamViewKeyframeControl::UpdateState);
connect(input_, &NodeInput::KeyframeRemoved, this, &NodeParamViewKeyframeControl::UpdateState);
}
}
void NodeParamViewKeyframeControl::SetKeyframeEnabled(bool e)
void NodeParamViewKeyframeControl::SetTime(const rational &time)
{
// Suppress KeyframeEnableChanged() signal from this object
blockSignals(true);
time_ = time;
enable_key_btn_->setChecked(e);
blockSignals(false);
UpdateState();
}
QPushButton *NodeParamViewKeyframeControl::CreateNewToolButton(const QIcon& icon) const
@@ -112,9 +94,126 @@ QPushButton *NodeParamViewKeyframeControl::CreateNewToolButton(const QIcon& icon
return btn;
}
void NodeParamViewKeyframeControl::SetButtonsEnabled(bool e)
{
prev_key_btn_->setEnabled(e);
toggle_key_btn_->setEnabled(e);
next_key_btn_->setEnabled(e);
enable_key_btn_->setEnabled(e);
}
void NodeParamViewKeyframeControl::ShowButtonsFromKeyframeEnable(bool e)
{
prev_key_btn_->setVisible(e);
toggle_key_btn_->setVisible(e);
next_key_btn_->setVisible(e);
}
void NodeParamViewKeyframeControl::ToggleKeyframe(bool e)
{
NodeKeyframePtr key = input_->get_keyframe_at_time(time_);
QUndoCommand* command = new QUndoCommand();
if (e && !key) {
// Add a keyframe here
key = NodeKeyframe::Create(time_,
input_->get_value_at_time(time_),
input_->get_best_keyframe_type_for_time(time_));
new NodeParamInsertKeyframeCommand(input_, key, command);
} else if (!e && key) {
// Remove a keyframe here
new NodeParamRemoveKeyframeCommand(input_, key, command);
// If this was the last keyframe, we'll set the standard value to the value at this time too
if (input_->keyframes().size() == 1) {
new NodeParamSetStandardValueCommand(input_, key->value(), command);
}
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void NodeParamViewKeyframeControl::UpdateState()
{
if (!input_) {
return;
}
prev_key_btn_->setEnabled(!input_->keyframes().isEmpty() && time_ > input_->keyframes().first()->time());
next_key_btn_->setEnabled(!input_->keyframes().isEmpty() && time_ < input_->keyframes().last()->time());
toggle_key_btn_->setChecked(input_->has_keyframe_at_time(time_));
}
void NodeParamViewKeyframeControl::GoToPreviousKey()
{
for (int i=input_->keyframes().size()-1;i>=0;i--) {
// Find closest keyframe that is before this time
const rational& this_key_time = input_->keyframes().at(i)->time();
if (this_key_time < time_) {
emit RequestSetTime(this_key_time);
break;
}
}
}
void NodeParamViewKeyframeControl::GoToNextKey()
{
for (int i=0;i<input_->keyframes().size();i++) {
// Find closest keyframe that is before this time
const rational& this_key_time = input_->keyframes().at(i)->time();
if (this_key_time > time_) {
emit RequestSetTime(this_key_time);
break;
}
}
}
void NodeParamViewKeyframeControl::KeyframeEnableChanged(bool e)
{
if (e == input_->is_keyframing()) {
// No-op
return;
}
QUndoCommand* command = new QUndoCommand();
if (e) {
// Enable keyframing
new NodeParamSetKeyframingCommand(input_, true, command);
// NodeInputs already have one keyframe by default, we move it to the current time here
NodeKeyframePtr key = NodeKeyframe::Create(time_, input_->get_standard_value(), NodeKeyframe::kDefaultType);
new NodeParamInsertKeyframeCommand(input_, key, 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) {
// Store value at this time, we'll set this as the persistent value later
QVariant stored_val = input_->get_value_at_time(time_);
// Delete all keyframes
for (int i=input_->keyframes().size()-1;i>=0;i--) {
new NodeParamRemoveKeyframeCommand(input_, input_->keyframes().at(i), command);
}
// Update standard value
new NodeParamSetStandardValueCommand(input_, stored_val, command);
// Disable keyframing
new NodeParamSetKeyframingCommand(input_, false, command);
} else {
// Disable action has effectively been ignored
enable_key_btn_->setChecked(true);
}
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
@@ -14,28 +14,18 @@ public:
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);
void SetTime(const rational& time);
signals:
void KeyframeEnableChanged(bool);
void GoToPreviousKey();
void GoToNextKey();
void KeyframeToggled(bool);
void RequestSetTime(const rational& time);
private:
QPushButton* CreateNewToolButton(const QIcon &icon) const;
void SetButtonsEnabled(bool e);
QPushButton* prev_key_btn_;
QPushButton* toggle_key_btn_;
QPushButton* next_key_btn_;
@@ -43,8 +33,21 @@ private:
NodeInput* input_;
rational time_;
private slots:
void ShowButtonsFromKeyframeEnable(bool e);
void ToggleKeyframe(bool e);
void UpdateState();
void GoToPreviousKey();
void GoToNextKey();
void KeyframeEnableChanged(bool e);
};
#endif // NODEPARAMVIEWKEYFRAMECONTROL_H
@@ -262,9 +262,9 @@ void NodeParamViewWidgetBridge::SetInputValue(const QVariant &value)
new NodeParamSetKeyframeValueCommand(existing_key, value, command);
} else {
// No existing key, create a new one
NodeKeyframePtr new_key = std::make_shared<NodeKeyframe>(time_,
value,
input_->get_best_keyframe_type_for_time(time_));
NodeKeyframePtr new_key = NodeKeyframe::Create(time_,
value,
input_->get_best_keyframe_type_for_time(time_));
new NodeParamInsertKeyframeCommand(input_, new_key, command);
}
@@ -295,9 +295,9 @@ void NodeParamViewWidgetBridge::ProcessSlider(SliderBase *slider, const QVariant
drag_created_keyframe_ = !dragging_keyframe_;
if (drag_created_keyframe_) {
dragging_keyframe_ = std::make_shared<NodeKeyframe>(time_,
value,
input_->get_best_keyframe_type_for_time(time_));
dragging_keyframe_ = NodeKeyframe::Create(time_,
value,
input_->get_best_keyframe_type_for_time(time_));
input_->insert_keyframe(dragging_keyframe_);
+2 -1
View File
@@ -30,6 +30,7 @@
#include "ui/style/style.h"
#include "undo/undostack.h"
#include "widget/menu/menushared.h"
#include "mainwindow.h"
MainMenu::MainMenu(QMainWindow *parent) :
QMenuBar(parent)
@@ -207,7 +208,7 @@ MainMenu::MainMenu(QMainWindow *parent) :
window_lock_layout_item_ = window_menu_->AddItem("lockpanels", PanelManager::instance(), SLOT(SetPanelsLocked(bool)));
window_lock_layout_item_->setCheckable(true);
window_menu_->addSeparator();
window_reset_layout_item_ = window_menu_->AddItem("resetdefaultlayout", nullptr, nullptr);
window_reset_layout_item_ = window_menu_->AddItem("resetdefaultlayout", Core::instance()->main_window(), SLOT(SetDefaultLayout()));
//
// TOOLS MENU
+2 -3
View File
@@ -48,6 +48,8 @@ public slots:
void SetFullscreen(bool fullscreen);
void ToggleMaximizedPanel();
void SetDefaultLayout();
protected:
virtual void closeEvent(QCloseEvent* e) override;
@@ -65,9 +67,6 @@ private:
TaskManagerPanel* task_man_panel_;
CurvePanel* curve_panel_;
private slots:
void SetDefaultLayout();
};
#endif