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:
itsmattkc
2019-12-28 18:47:54 +11:00
parent 26cafa7936
commit 4cd5e103b8
8 changed files with 326 additions and 297 deletions
+2
View File
@@ -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
+2 -220
View File
@@ -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);
}
}
+2 -38
View File
@@ -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