merged KeyframeView and CurveView to use the same base class
These classes had a ton of similarities, so they've now been modified to use a common base class.
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
#include "common/qtversionabstraction.h"
|
||||
|
||||
CurveView::CurveView(QWidget *parent) :
|
||||
TimelineViewBase(parent),
|
||||
KeyframeViewBase(parent),
|
||||
y_scale_(1.0)
|
||||
{
|
||||
setAlignment(Qt::AlignLeft | Qt::AlignBottom);
|
||||
@@ -19,25 +19,15 @@ CurveView::CurveView(QWidget *parent) :
|
||||
|
||||
void CurveView::Clear()
|
||||
{
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
|
||||
|
||||
for (iterator=key_item_map_.begin();iterator!=key_item_map_.end();iterator++) {
|
||||
delete iterator.value();
|
||||
}
|
||||
KeyframeViewBase::Clear();
|
||||
|
||||
foreach (QGraphicsLineItem* line, lines_) {
|
||||
delete line;
|
||||
}
|
||||
|
||||
key_item_map_.clear();
|
||||
lines_.clear();
|
||||
}
|
||||
|
||||
void CurveView::SetXScale(const double& x_scale)
|
||||
{
|
||||
SetScale(x_scale);
|
||||
}
|
||||
|
||||
void CurveView::SetYScale(const double &y_scale)
|
||||
{
|
||||
y_scale_ = y_scale;
|
||||
@@ -99,7 +89,7 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
|
||||
QVector<QLineF> keyframe_lines;
|
||||
|
||||
// Draw straight line leading to first keyframe
|
||||
QPointF first_key_pos = key_item_map_.value(keys.first())->center_pos();
|
||||
QPointF first_key_pos = item_map().value(keys.first())->center_pos();
|
||||
keyframe_lines.append(QLineF(QPointF(scene_bottom_left.x(), first_key_pos.y()), first_key_pos));
|
||||
|
||||
// Draw lines between each keyframe
|
||||
@@ -107,8 +97,8 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
|
||||
NodeKeyframe* before = keys.at(i-1);
|
||||
NodeKeyframe* after = keys.at(i);
|
||||
|
||||
KeyframeViewItem* before_item = key_item_map_.value(before);
|
||||
KeyframeViewItem* after_item = key_item_map_.value(after);
|
||||
KeyframeViewItem* before_item = item_map().value(before);
|
||||
KeyframeViewItem* after_item = item_map().value(after);
|
||||
|
||||
if (before->type() == NodeKeyframe::kHold) {
|
||||
// Draw a hold keyframe (basically a right angle)
|
||||
@@ -131,20 +121,25 @@ void CurveView::drawBackground(QPainter *painter, const QRectF &rect)
|
||||
}
|
||||
|
||||
// Draw straight line leading from end keyframe
|
||||
QPointF last_key_pos = key_item_map_.value(keys.last())->center_pos();
|
||||
QPointF last_key_pos = item_map().value(keys.last())->center_pos();
|
||||
keyframe_lines.append(QLineF(last_key_pos, QPointF(scene_top_right.x(), last_key_pos.y())));
|
||||
|
||||
painter->drawLines(keyframe_lines);
|
||||
}
|
||||
}
|
||||
|
||||
void CurveView::KeyframeAboutToBeRemoved(NodeKeyframe *key)
|
||||
{
|
||||
disconnect(key, &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
|
||||
}
|
||||
|
||||
QList<NodeKeyframe *> CurveView::GetKeyframesSortedByTime()
|
||||
{
|
||||
QList<NodeKeyframe *> sorted;
|
||||
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
|
||||
|
||||
for (iterator=key_item_map_.begin();iterator!=key_item_map_.end();iterator++) {
|
||||
for (iterator=item_map().begin();iterator!=item_map().end();iterator++) {
|
||||
NodeKeyframe* key = iterator.key();
|
||||
bool inserted = false;
|
||||
|
||||
@@ -177,25 +172,15 @@ void CurveView::SetItemYFromKeyframeValue(NodeKeyframe *key, KeyframeViewItem *i
|
||||
void CurveView::KeyframeValueChanged()
|
||||
{
|
||||
NodeKeyframe* key = static_cast<NodeKeyframe*>(sender());
|
||||
KeyframeViewItem* item = key_item_map_.value(key);
|
||||
KeyframeViewItem* item = item_map().value(key);
|
||||
|
||||
SetItemYFromKeyframeValue(key, item);
|
||||
}
|
||||
|
||||
void CurveView::AddKeyframe(NodeKeyframePtr key)
|
||||
{
|
||||
KeyframeViewItem* item = new KeyframeViewItem(key);
|
||||
KeyframeViewItem* item = AddKeyframeInternal(key);
|
||||
SetItemYFromKeyframeValue(key.get(), item);
|
||||
item->SetScale(scale_);
|
||||
scene()->addItem(item);
|
||||
key_item_map_.insert(key.get(), item);
|
||||
|
||||
connect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
|
||||
}
|
||||
|
||||
void CurveView::RemoveKeyframe(NodeKeyframePtr key)
|
||||
{
|
||||
disconnect(key.get(), &NodeKeyframe::ValueChanged, this, &CurveView::KeyframeValueChanged);
|
||||
|
||||
delete key_item_map_.take(key.get());
|
||||
}
|
||||
|
||||
@@ -2,28 +2,26 @@
|
||||
#define CURVEVIEW_H
|
||||
|
||||
#include "node/keyframe.h"
|
||||
#include "widget/keyframeview/keyframeview.h"
|
||||
#include "widget/keyframeview/keyframeviewitem.h"
|
||||
#include "widget/timelinewidget/view/timelineviewbase.h"
|
||||
|
||||
class CurveView : public TimelineViewBase
|
||||
class CurveView : public KeyframeViewBase
|
||||
{
|
||||
public:
|
||||
CurveView(QWidget* parent = nullptr);
|
||||
|
||||
void Clear();
|
||||
|
||||
void SetXScale(const double& x_scale);
|
||||
virtual void Clear() override;
|
||||
|
||||
void SetYScale(const double& y_scale);
|
||||
|
||||
public slots:
|
||||
void AddKeyframe(NodeKeyframePtr key);
|
||||
|
||||
void RemoveKeyframe(NodeKeyframePtr key);
|
||||
|
||||
protected:
|
||||
virtual void drawBackground(QPainter* painter, const QRectF& rect) override;
|
||||
|
||||
virtual void KeyframeAboutToBeRemoved(NodeKeyframe *key) override;
|
||||
|
||||
private:
|
||||
QList<NodeKeyframe*> GetKeyframesSortedByTime();
|
||||
|
||||
@@ -39,8 +37,6 @@ private:
|
||||
|
||||
int minimum_grid_space_;
|
||||
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*> key_item_map_;
|
||||
|
||||
QList<QGraphicsLineItem*> lines_;
|
||||
|
||||
private slots:
|
||||
|
||||
@@ -146,7 +146,7 @@ const double &CurveWidget::GetScale()
|
||||
void CurveWidget::SetScale(const double &scale)
|
||||
{
|
||||
ruler_->SetScale(scale);
|
||||
view_->SetXScale(scale);
|
||||
view_->SetScale(scale);
|
||||
}
|
||||
|
||||
void CurveWidget::changeEvent(QEvent *e)
|
||||
|
||||
@@ -18,6 +18,8 @@ set(OLIVE_SOURCES
|
||||
${OLIVE_SOURCES}
|
||||
widget/keyframeview/keyframeview.h
|
||||
widget/keyframeview/keyframeview.cpp
|
||||
widget/keyframeview/keyframeviewbase.h
|
||||
widget/keyframeview/keyframeviewbase.cpp
|
||||
widget/keyframeview/keyframeviewitem.h
|
||||
widget/keyframeview/keyframeviewitem.cpp
|
||||
widget/keyframeview/keyframeviewundo.h
|
||||
|
||||
@@ -1,34 +1,9 @@
|
||||
#include "keyframeview.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "keyframeviewundo.h"
|
||||
#include "widget/menu/menu.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
#include "widget/nodeparamview/nodeparamviewundo.h"
|
||||
|
||||
KeyframeView::KeyframeView(QWidget *parent) :
|
||||
TimelineViewBase(parent)
|
||||
KeyframeViewBase(parent)
|
||||
{
|
||||
setBackgroundRole(QPalette::Base);
|
||||
setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||
setDragMode(RubberBandDrag);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(this, &KeyframeView::customContextMenuRequested, this, &KeyframeView::ShowContextMenu);
|
||||
connect(Core::instance(), &Core::ToolChanged, this, &KeyframeView::ApplicationToolChanged);
|
||||
}
|
||||
|
||||
void KeyframeView::Clear()
|
||||
{
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::iterator iterator;
|
||||
|
||||
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
|
||||
delete iterator.value();
|
||||
}
|
||||
|
||||
item_map_.clear();
|
||||
}
|
||||
|
||||
void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y)
|
||||
@@ -37,199 +12,6 @@ void KeyframeView::AddKeyframe(NodeKeyframePtr key, int y)
|
||||
QPoint local_pt = mapFromGlobal(global_pt);
|
||||
QPointF scene_pt = mapToScene(local_pt);
|
||||
|
||||
KeyframeViewItem* item = new KeyframeViewItem(key);
|
||||
KeyframeViewItem* item = AddKeyframeInternal(key);
|
||||
item->SetOverrideY(scene_pt.y());
|
||||
item->SetScale(scale_);
|
||||
item_map_.insert(key.get(), item);
|
||||
scene()->addItem(item);
|
||||
}
|
||||
|
||||
void KeyframeView::RemoveKeyframe(NodeKeyframePtr key)
|
||||
{
|
||||
delete item_map_.take(key.get());
|
||||
}
|
||||
|
||||
void KeyframeView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (PlayheadPress(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
active_tool_ = Core::instance()->tool();
|
||||
|
||||
rubberBandSelectionMode();
|
||||
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
QGraphicsView::mousePressEvent(event);
|
||||
|
||||
if (active_tool_ == Tool::kPointer) {
|
||||
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());
|
||||
|
||||
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()});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (PlayheadMove(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
|
||||
KeyframeViewItem* item = keypair.key;
|
||||
|
||||
item->setX(keypair.item_x + x_diff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (PlayheadRelease(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
QGraphicsView::mouseReleaseEvent(event);
|
||||
|
||||
if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) {
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// 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_;
|
||||
|
||||
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
|
||||
KeyframeViewItem* item = keypair.key;
|
||||
|
||||
// Calculate the new time for this keyframe
|
||||
double position = keypair.time.toDouble();
|
||||
position += x_diff_scaled;
|
||||
|
||||
// Commit movement
|
||||
qDebug() << "Moving key to" << rational::fromDouble(position);
|
||||
|
||||
new NodeParamSetKeyframeTimeCommand(item->key(),
|
||||
rational::fromDouble(position),
|
||||
keypair.time,
|
||||
command);
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
|
||||
selected_keys_.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeView::ScaleChangedEvent(double scale)
|
||||
{
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
|
||||
|
||||
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
|
||||
iterator.value()->SetScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeView::ShowContextMenu()
|
||||
{
|
||||
Menu m;
|
||||
|
||||
MenuShared::instance()->AddItemsForEditMenu(&m);
|
||||
|
||||
QAction* linear_key_action;
|
||||
QAction* bezier_key_action;
|
||||
QAction* hold_key_action;
|
||||
|
||||
QList<QGraphicsItem*> items = scene()->selectedItems();
|
||||
if (!items.isEmpty()) {
|
||||
bool all_keys_are_same_type = true;
|
||||
NodeKeyframe::Type type = static_cast<KeyframeViewItem*>(items.first())->key()->type();
|
||||
|
||||
for (int i=1;i<items.size();i++) {
|
||||
KeyframeViewItem* key_item = static_cast<KeyframeViewItem*>(items.at(i));
|
||||
KeyframeViewItem* prev_item = static_cast<KeyframeViewItem*>(items.at(i-1));
|
||||
|
||||
if (key_item->key()->type() != prev_item->key()->type()) {
|
||||
all_keys_are_same_type = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
linear_key_action = m.addAction(tr("Linear"));
|
||||
bezier_key_action = m.addAction(tr("Bezier"));
|
||||
hold_key_action = m.addAction(tr("Hold"));
|
||||
|
||||
if (all_keys_are_same_type) {
|
||||
switch (type) {
|
||||
case NodeKeyframe::kLinear:
|
||||
linear_key_action->setChecked(true);
|
||||
break;
|
||||
case NodeKeyframe::kBezier:
|
||||
bezier_key_action->setChecked(true);
|
||||
break;
|
||||
case NodeKeyframe::kHold:
|
||||
hold_key_action->setChecked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QAction* selected = m.exec(QCursor::pos());
|
||||
|
||||
// Process keyframe type changes
|
||||
if (!items.isEmpty()) {
|
||||
if (selected == linear_key_action
|
||||
|| selected == bezier_key_action
|
||||
|| selected == hold_key_action) {
|
||||
NodeKeyframe::Type new_type;
|
||||
|
||||
if (selected == hold_key_action) {
|
||||
new_type = NodeKeyframe::kHold;
|
||||
} else if (selected == bezier_key_action) {
|
||||
new_type = NodeKeyframe::kBezier;
|
||||
} else {
|
||||
new_type = NodeKeyframe::kLinear;
|
||||
}
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
foreach (QGraphicsItem* item, items) {
|
||||
new KeyframeSetTypeCommand(static_cast<KeyframeViewItem*>(item)->key(),
|
||||
new_type,
|
||||
command);
|
||||
}
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeView::ApplicationToolChanged(Tool::Item tool)
|
||||
{
|
||||
if (tool == Tool::kHand) {
|
||||
setDragMode(ScrollHandDrag);
|
||||
} else {
|
||||
setDragMode(RubberBandDrag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,53 +1,17 @@
|
||||
#ifndef KEYFRAMEVIEW_H
|
||||
#define KEYFRAMEVIEW_H
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include "keyframeviewbase.h"
|
||||
|
||||
#include "common/rational.h"
|
||||
#include "core.h"
|
||||
#include "keyframeviewitem.h"
|
||||
#include "widget/timelinewidget/view/timelineviewbase.h"
|
||||
|
||||
class KeyframeView : public TimelineViewBase
|
||||
class KeyframeView : public KeyframeViewBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KeyframeView(QWidget* parent = nullptr);
|
||||
|
||||
void Clear();
|
||||
|
||||
public slots:
|
||||
void AddKeyframe(NodeKeyframePtr key, int y);
|
||||
|
||||
void RemoveKeyframe(NodeKeyframePtr key);
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
virtual void ScaleChangedEvent(double scale) override;
|
||||
|
||||
private:
|
||||
struct KeyframeItemAndTime {
|
||||
KeyframeViewItem* key;
|
||||
qreal item_x;
|
||||
rational time;
|
||||
};
|
||||
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*> item_map_;
|
||||
|
||||
Tool::Item active_tool_;
|
||||
|
||||
QPoint drag_start_;
|
||||
|
||||
QVector<KeyframeItemAndTime> selected_keys_;
|
||||
|
||||
private slots:
|
||||
void ShowContextMenu();
|
||||
|
||||
void ApplicationToolChanged(Tool::Item tool);
|
||||
|
||||
};
|
||||
|
||||
#endif // KEYFRAMEVIEW_H
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
#include "keyframeviewbase.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "keyframeviewundo.h"
|
||||
#include "widget/menu/menu.h"
|
||||
#include "widget/menu/menushared.h"
|
||||
#include "widget/nodeparamview/nodeparamviewundo.h"
|
||||
|
||||
KeyframeViewBase::KeyframeViewBase(QWidget *parent) :
|
||||
TimelineViewBase(parent)
|
||||
{
|
||||
setDragMode(RubberBandDrag);
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(this, &KeyframeViewBase::customContextMenuRequested, this, &KeyframeViewBase::ShowContextMenu);
|
||||
connect(Core::instance(), &Core::ToolChanged, this, &KeyframeViewBase::ApplicationToolChanged);
|
||||
}
|
||||
|
||||
void KeyframeViewBase::Clear()
|
||||
{
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::iterator iterator;
|
||||
|
||||
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
|
||||
delete iterator.value();
|
||||
}
|
||||
|
||||
item_map_.clear();
|
||||
}
|
||||
|
||||
void KeyframeViewBase::RemoveKeyframe(NodeKeyframePtr key)
|
||||
{
|
||||
KeyframeAboutToBeRemoved(key.get());
|
||||
|
||||
delete item_map_.take(key.get());
|
||||
}
|
||||
|
||||
KeyframeViewItem *KeyframeViewBase::AddKeyframeInternal(NodeKeyframePtr key)
|
||||
{
|
||||
KeyframeViewItem* item = new KeyframeViewItem(key);
|
||||
item->SetScale(scale_);
|
||||
item_map_.insert(key.get(), item);
|
||||
scene()->addItem(item);
|
||||
return item;
|
||||
}
|
||||
|
||||
void KeyframeViewBase::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (PlayheadPress(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
active_tool_ = Core::instance()->tool();
|
||||
|
||||
rubberBandSelectionMode();
|
||||
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
QGraphicsView::mousePressEvent(event);
|
||||
|
||||
if (active_tool_ == Tool::kPointer) {
|
||||
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());
|
||||
|
||||
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()});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
if (PlayheadMove(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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_;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (PlayheadRelease(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
QGraphicsView::mouseReleaseEvent(event);
|
||||
|
||||
if (active_tool_ == Tool::kPointer && !selected_keys_.isEmpty()) {
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// 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_;
|
||||
|
||||
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
|
||||
KeyframeViewItem* item = keypair.key;
|
||||
|
||||
// Calculate the new time for this keyframe
|
||||
rational new_time = CalculateNewTimeFromScreen(keypair.time, x_diff_scaled);
|
||||
|
||||
// Commit movement
|
||||
new NodeParamSetKeyframeTimeCommand(item->key(),
|
||||
new_time,
|
||||
keypair.time,
|
||||
command);
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
|
||||
selected_keys_.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewBase::ScaleChangedEvent(double scale)
|
||||
{
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator iterator;
|
||||
|
||||
for (iterator=item_map_.begin();iterator!=item_map_.end();iterator++) {
|
||||
iterator.value()->SetScale(scale);
|
||||
}
|
||||
}
|
||||
|
||||
const QMap<NodeKeyframe *, KeyframeViewItem *> &KeyframeViewBase::item_map() const
|
||||
{
|
||||
return item_map_;
|
||||
}
|
||||
|
||||
void KeyframeViewBase::KeyframeAboutToBeRemoved(NodeKeyframe *)
|
||||
{
|
||||
}
|
||||
|
||||
rational KeyframeViewBase::CalculateNewTimeFromScreen(const rational &old_time, double cursor_diff)
|
||||
{
|
||||
return rational::fromDouble(old_time.toDouble() + cursor_diff);
|
||||
}
|
||||
|
||||
void KeyframeViewBase::ShowContextMenu()
|
||||
{
|
||||
Menu m;
|
||||
|
||||
MenuShared::instance()->AddItemsForEditMenu(&m);
|
||||
|
||||
QAction* linear_key_action;
|
||||
QAction* bezier_key_action;
|
||||
QAction* hold_key_action;
|
||||
|
||||
QList<QGraphicsItem*> items = scene()->selectedItems();
|
||||
if (!items.isEmpty()) {
|
||||
bool all_keys_are_same_type = true;
|
||||
NodeKeyframe::Type type = static_cast<KeyframeViewItem*>(items.first())->key()->type();
|
||||
|
||||
for (int i=1;i<items.size();i++) {
|
||||
KeyframeViewItem* key_item = static_cast<KeyframeViewItem*>(items.at(i));
|
||||
KeyframeViewItem* prev_item = static_cast<KeyframeViewItem*>(items.at(i-1));
|
||||
|
||||
if (key_item->key()->type() != prev_item->key()->type()) {
|
||||
all_keys_are_same_type = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m.addSeparator();
|
||||
|
||||
linear_key_action = m.addAction(tr("Linear"));
|
||||
bezier_key_action = m.addAction(tr("Bezier"));
|
||||
hold_key_action = m.addAction(tr("Hold"));
|
||||
|
||||
if (all_keys_are_same_type) {
|
||||
switch (type) {
|
||||
case NodeKeyframe::kLinear:
|
||||
linear_key_action->setChecked(true);
|
||||
break;
|
||||
case NodeKeyframe::kBezier:
|
||||
bezier_key_action->setChecked(true);
|
||||
break;
|
||||
case NodeKeyframe::kHold:
|
||||
hold_key_action->setChecked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QAction* selected = m.exec(QCursor::pos());
|
||||
|
||||
// Process keyframe type changes
|
||||
if (!items.isEmpty()) {
|
||||
if (selected == linear_key_action
|
||||
|| selected == bezier_key_action
|
||||
|| selected == hold_key_action) {
|
||||
NodeKeyframe::Type new_type;
|
||||
|
||||
if (selected == hold_key_action) {
|
||||
new_type = NodeKeyframe::kHold;
|
||||
} else if (selected == bezier_key_action) {
|
||||
new_type = NodeKeyframe::kBezier;
|
||||
} else {
|
||||
new_type = NodeKeyframe::kLinear;
|
||||
}
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
foreach (QGraphicsItem* item, items) {
|
||||
new KeyframeSetTypeCommand(static_cast<KeyframeViewItem*>(item)->key(),
|
||||
new_type,
|
||||
command);
|
||||
}
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyframeViewBase::ApplicationToolChanged(Tool::Item tool)
|
||||
{
|
||||
if (tool == Tool::kHand) {
|
||||
setDragMode(ScrollHandDrag);
|
||||
} else {
|
||||
setDragMode(RubberBandDrag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef KEYFRAMEVIEWBASE_H
|
||||
#define KEYFRAMEVIEWBASE_H
|
||||
|
||||
#include "core.h"
|
||||
#include "keyframeviewitem.h"
|
||||
#include "node/keyframe.h"
|
||||
#include "widget/timelinewidget/view/timelineviewbase.h"
|
||||
|
||||
class KeyframeViewBase : public TimelineViewBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
KeyframeViewBase(QWidget* parent = nullptr);
|
||||
|
||||
virtual void Clear();
|
||||
|
||||
public slots:
|
||||
void RemoveKeyframe(NodeKeyframePtr key);
|
||||
|
||||
protected:
|
||||
virtual KeyframeViewItem* AddKeyframeInternal(NodeKeyframePtr key);
|
||||
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
|
||||
virtual void ScaleChangedEvent(double scale) override;
|
||||
|
||||
const QMap<NodeKeyframe*, KeyframeViewItem*>& item_map() const;
|
||||
|
||||
virtual void KeyframeAboutToBeRemoved(NodeKeyframe* key);
|
||||
|
||||
private:
|
||||
rational CalculateNewTimeFromScreen(const rational& old_time, double cursor_diff);
|
||||
|
||||
struct KeyframeItemAndTime {
|
||||
KeyframeViewItem* key;
|
||||
qreal item_x;
|
||||
rational time;
|
||||
};
|
||||
|
||||
QMap<NodeKeyframe*, KeyframeViewItem*> item_map_;
|
||||
|
||||
Tool::Item active_tool_;
|
||||
|
||||
QPoint drag_start_;
|
||||
|
||||
QVector<KeyframeItemAndTime> selected_keys_;
|
||||
|
||||
private slots:
|
||||
void ShowContextMenu();
|
||||
|
||||
void ApplicationToolChanged(Tool::Item tool);
|
||||
|
||||
};
|
||||
|
||||
#endif // KEYFRAMEVIEWBASE_H
|
||||
Reference in New Issue
Block a user