reworked much of keyframeview for new architecture

This commit is contained in:
itsmattkc
2021-12-13 14:12:30 -08:00
parent 090fbb09d0
commit 7d82d56f31
25 changed files with 852 additions and 754 deletions
+210 -231
View File
@@ -24,6 +24,7 @@
#include <QToolTip>
#include <QVBoxLayout>
#include "common/qtutils.h"
#include "dialog/keyframeproperties/keyframeproperties.h"
#include "keyframeviewundo.h"
#include "node/node.h"
@@ -33,201 +34,144 @@
namespace olive {
#define super TimeBasedView
KeyframeViewBase::KeyframeViewBase(QWidget *parent) :
TimeBasedView(parent),
super(parent),
dragging_bezier_point_(nullptr),
currently_autoselecting_(false),
dragging_(false)
dragging_(false),
selection_manager_(this)
{
SetDefaultDragMode(RubberBandDrag);
setContextMenuPolicy(Qt::CustomContextMenu);
connect(this, &KeyframeViewBase::customContextMenuRequested, this, &KeyframeViewBase::ShowContextMenu);
connect(scene(), &QGraphicsScene::selectionChanged, this, &KeyframeViewBase::AutoSelectKeyTimeNeighbors);
}
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::DeleteSelected()
{
MultiUndoCommand* command = new MultiUndoCommand();
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator i;
for (i=item_map_.constBegin(); i!=item_map_.constEnd(); i++) {
if (i.value()->isSelected()) {
command->add_child(new NodeParamRemoveKeyframeCommand(i.key()));
}
foreach (NodeKeyframe *key, GetSelectedKeyframes()) {
command->add_child(new NodeParamRemoveKeyframeCommand(key));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
}
void KeyframeViewBase::AddKeyframesOfNode(Node *n)
KeyframeViewBase::NodeConnections KeyframeViewBase::AddKeyframesOfNode(Node *n)
{
NodeConnections map;
foreach (const QString& i, n->inputs()) {
AddKeyframesOfInput(n, i);
map.insert(i, AddKeyframesOfInput(n, i));
}
return map;
}
void KeyframeViewBase::AddKeyframesOfInput(Node* n, const QString& input)
KeyframeViewBase::InputConnections KeyframeViewBase::AddKeyframesOfInput(Node* n, const QString& input)
{
if (!n->IsInputKeyframable(input)) {
return;
InputConnections vec;
if (n->IsInputKeyframable(input)) {
int arr_sz = n->InputArraySize(input);
vec.resize(arr_sz + 1);
for (int i=-1; i<arr_sz; i++) {
vec[i+1] = AddKeyframesOfElement(NodeInput(n, input, i));
}
}
int arr_sz = n->InputArraySize(input);
for (int i=-1; i<arr_sz; i++) {
AddKeyframesOfElement(NodeInput(n, input, i));
}
return vec;
}
void KeyframeViewBase::AddKeyframesOfElement(const NodeInput& input)
KeyframeViewBase::ElementConnections KeyframeViewBase::AddKeyframesOfElement(const NodeInput& input)
{
const QVector<NodeKeyframeTrack>& tracks = input.node()->GetKeyframeTracks(input);
ElementConnections vec(tracks.size());
for (int i=0; i<tracks.size(); i++) {
AddKeyframesOfTrack(NodeKeyframeTrackReference(input, i));
vec[i] = AddKeyframesOfTrack(NodeKeyframeTrackReference(input, i));
}
return vec;
}
void KeyframeViewBase::AddKeyframesOfTrack(const NodeKeyframeTrackReference& ref)
KeyframeViewInputConnection *KeyframeViewBase::AddKeyframesOfTrack(const NodeKeyframeTrackReference& ref)
{
const QVector<NodeKeyframeTrack>& tracks = ref.input().node()->GetKeyframeTracks(ref.input());
const NodeKeyframeTrack& t = tracks.at(ref.track());
foreach (NodeKeyframe* key, t) {
AddKeyframe(key);
}
KeyframeViewInputConnection *track = new KeyframeViewInputConnection(ref, this);
connect(track, &KeyframeViewInputConnection::RequireUpdate, this, &KeyframeViewBase::Redraw);
tracks_.append(track);
Redraw();
return track;
}
void KeyframeViewBase::RemoveKeyframesOfNode(Node *n)
void KeyframeViewBase::RemoveKeyframesOfTrack(KeyframeViewInputConnection *connection)
{
foreach (const QString& i, n->inputs()) {
RemoveKeyframesOfInput(n, i);
}
}
void KeyframeViewBase::RemoveKeyframesOfInput(Node* n, const QString& input)
{
if (!n->IsInputKeyframable(input)) {
return;
}
int arr_sz = n->InputArraySize(input);
for (int i=-1; i<arr_sz; i++) {
RemoveKeyframesOfElement(NodeInput(n, input, i));
}
}
void KeyframeViewBase::RemoveKeyframesOfElement(const NodeInput& input)
{
const QVector<NodeKeyframeTrack>& tracks = input.node()->GetKeyframeTracks(input);
for (int i=0; i<tracks.size(); i++) {
RemoveKeyframesOfTrack(NodeKeyframeTrackReference(input, i));
}
}
void KeyframeViewBase::RemoveKeyframesOfTrack(const NodeKeyframeTrackReference& ref)
{
const QVector<NodeKeyframeTrack>& tracks = ref.input().node()->GetKeyframeTracks(ref.input());
const NodeKeyframeTrack& t = tracks.at(ref.track());
foreach (NodeKeyframe* key, t) {
RemoveKeyframe(key);
if (tracks_.removeOne(connection)) {
delete connection;
Redraw();
}
}
void KeyframeViewBase::SelectAll()
{
for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) {
it.value()->setSelected(true);
foreach (KeyframeViewInputConnection *track, tracks_) {
foreach (NodeKeyframe *key, track->GetKeyframes()) {
SelectKeyframe(key);
}
}
}
void KeyframeViewBase::DeselectAll()
{
for (auto it=item_map_.cbegin(); it!=item_map_.cend(); it++) {
it.value()->setSelected(false);
}
selection_manager_.ClearSelection();
Redraw();
}
void KeyframeViewBase::RemoveKeyframe(NodeKeyframe* key)
void KeyframeViewBase::Clear()
{
KeyframeAboutToBeRemoved(key);
delete item_map_.take(key);
}
KeyframeViewItem *KeyframeViewBase::AddKeyframe(NodeKeyframe* key)
{
KeyframeViewItem* item = item_map_.value(key);
if (!item) {
item = new KeyframeViewItem(key);
item->SetTimeTarget(GetTimeTarget());
item->SetScale(GetScale());
item_map_.insert(key, item);
scene()->addItem(item);
if (!tracks_.isEmpty()) {
qDeleteAll(tracks_);
tracks_.clear();
Redraw();
}
return item;
}
void KeyframeViewBase::mousePressEvent(QMouseEvent *event)
{
QGraphicsItem* item_under_cursor = itemAt(event->pos());
NodeKeyframe *key_under_cursor = selection_manager_.MousePress(event);
if (key_under_cursor) {
AutoSelectKeyTimeNeighbors();
}
if (HandPress(event) || (!item_under_cursor && PlayheadPress(event))) {
BezierControlPointItem *bezier_under_cursor = dynamic_cast<BezierControlPointItem*>(itemAt(event->pos()));
Redraw();
if (HandPress(event) || (!bezier_under_cursor && !key_under_cursor && PlayheadPress(event))) {
return;
}
active_tool_ = Core::instance()->tool();
if (event->button() == Qt::LeftButton) {
QGraphicsView::mousePressEvent(event);
if (key_under_cursor || bezier_under_cursor) {
dragging_ = true;
drag_start_ = mapToScene(event->pos());
if (active_tool_ == Tool::kPointer) {
if (item_under_cursor) {
// Determine what type of item is under the cursor
dragging_bezier_point_ = bezier_under_cursor;
dragging_ = true;
drag_start_ = mapToScene(event->pos());
if (dragging_bezier_point_) {
// Determine what type of item is under the cursor
dragging_bezier_point_ = dynamic_cast<BezierControlPointItem*>(item_under_cursor);
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()));
if (dragging_bezier_point_) {
} else {
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()));
selection_manager_.DragStart(key_under_cursor, event);
} else {
QList<QGraphicsItem*> selected_items = scene()->selectedItems();
selected_keys_.resize(selected_items.size());
initial_drag_item_ = static_cast<KeyframeViewItem*>(item_under_cursor);
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(),
GetAdjustedTime(key->key()->parent(), GetTimeTarget(), key->key()->time(), false),
key->key()->value().toDouble()});
}
}
}
}
}
@@ -240,11 +184,10 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
}
if (event->buttons() & Qt::LeftButton) {
QGraphicsView::mouseMoveEvent(event);
if (dragging_) {
// Calculate cursor difference and scale it
QPointF mouse_diff_scaled = GetScaledCursorPos(mapToScene(event->pos()) - drag_start_);
QPointF scene_pos = mapToScene(event->pos());
QPointF mouse_diff_scaled = GetScaledCursorPos(scene_pos - drag_start_);
if (event->modifiers() & Qt::ShiftModifier) {
// If holding shift, only move one axis
@@ -284,15 +227,19 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
QPointF bezier_pos = dragging_bezier_point_->pos() + dragging_bezier_point_->parentItem()->pos();
emit Dragged(qRound(bezier_pos.x()), qRound(bezier_pos.y()));
} else if (!selected_keys_.isEmpty()) {
} else if (selection_manager_.IsDragging()) {
QString tip;
/*
// Validate movement - ensure no keyframe goes above its max point or below its min point
FloatSlider::DisplayType display_type = FloatSlider::kNormal;
if (IsYAxisEnabled()) {
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
Node* node = keypair.key->key()->parent();
const QString& input = keypair.key->key()->input();
foreach (const KeyframeItemAndTime& keypair, dragging_keyframes_) {
NodeKeyframe *key = keypair.key;
Node* node = key->parent();
const QString& input = key->input();
double new_val = keypair.value - mouse_diff_scaled.y();
double limited = new_val;
@@ -309,48 +256,37 @@ void KeyframeViewBase::mouseMoveEvent(QMouseEvent *event)
}
}
Node* initial_drag_input = initial_drag_item_->key()->parent();
const QString& initial_drag_input_id = initial_drag_item_->key()->input();
Node* initial_drag_input = initial_drag_item_->parent();
const QString& initial_drag_input_id = initial_drag_item_->input();
if (initial_drag_input->HasInputProperty(initial_drag_input_id, QStringLiteral("view"))) {
display_type = static_cast<FloatSlider::DisplayType>(initial_drag_input->GetInputProperty(initial_drag_input_id, QStringLiteral("view")).toInt());
}
}
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
rational node_time = GetAdjustedTime(GetTimeTarget(),
keypair.key->key()->parent(),
CalculateNewTimeFromScreen(keypair.time, mouse_diff_scaled.x()),
true);
keypair.key->key()->set_time(node_time);
foreach (const KeyframeItemAndTime& keypair, dragging_keyframes_) {
if (IsYAxisEnabled()) {
keypair.key->key()->set_value(keypair.value - mouse_diff_scaled.y());
key->set_value(keypair.value - mouse_diff_scaled.y());
}
}
// Show information about this keyframe
QString tip = Timecode::time_to_timecode(initial_drag_item_->key()->time(), timebase(),
Core::instance()->GetTimecodeDisplay(), false);
if (IsYAxisEnabled()) {
bool ok;
double num_value = initial_drag_item_->key()->value().toDouble(&ok);
double num_value = initial_drag_item_->value().toDouble(&ok);
if (ok) {
tip.append('\n');
tip = QStringLiteral("%1\n");
tip.append(FloatSlider::ValueToString(num_value, display_type, 2, true));
}
// Force viewport to update since Qt might try to optimize it out if the keyframe is
// offscreen
viewport()->update();
}
*/
QToolTip::hideText();
QToolTip::showText(QCursor::pos(), tip);
selection_manager_.DragMove(event, tip);
emit Dragged(qRound(initial_drag_item_->x()), qRound(initial_drag_item_->y()));
Redraw();
emit Dragged(scene_pos.x(), scene_pos.y());
}
}
@@ -364,8 +300,6 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
}
if (event->button() == Qt::LeftButton) {
QGraphicsView::mouseReleaseEvent(event);
if (dragging_) {
if (dragging_bezier_point_) {
MultiUndoCommand* command = new MultiUndoCommand();
@@ -388,30 +322,19 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
dragging_bezier_point_ = nullptr;
Core::instance()->undo_stack()->push(command);
} else if (!selected_keys_.isEmpty()) {
} else if (selection_manager_.IsDragging()) {
MultiUndoCommand* command = new MultiUndoCommand();
foreach (const KeyframeItemAndTime& keypair, selected_keys_) {
NodeKeyframe* item = keypair.key->key();
// Commit movement
command->add_child(new NodeParamSetKeyframeTimeCommand(item,
item->time(),
keypair.time));
// Commit value if we're setting a value
if (IsYAxisEnabled()) {
command->add_child(new NodeParamSetKeyframeValueCommand(item,
item->value(),
keypair.value));
}
}
selection_manager_.DragStop(command);
/*if (IsYAxisEnabled()) {
command->add_child(new NodeParamSetKeyframeValueCommand(item,
item->value(),
keypair.value));
}*/
Core::instance()->undo_stack()->push(command);
}
selected_keys_.clear();
dragging_ = false;
QToolTip::hideText();
@@ -419,31 +342,77 @@ void KeyframeViewBase::mouseReleaseEvent(QMouseEvent *event)
}
}
void KeyframeViewBase::drawForeground(QPainter *painter, const QRectF &rect)
{
int key_sz = QtUtils::QFontMetricsWidth(fontMetrics(), "Oi");
int key_rad = key_sz/2;
selection_manager_.ClearDrawnObjects();
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::black);
foreach (KeyframeViewInputConnection *track, tracks_) {
foreach (NodeKeyframe *key, track->GetKeyframes()) {
QRectF key_rect(-key_rad, -key_rad, key_sz, key_sz);
key_rect.translate(GetKeyframeSceneX(key), mapFromGlobal(QPoint(0, track->GetKeyframeY())).y());
if (!rect.intersects(key_rect)) {
continue;
}
if (IsKeyframeSelected(key)) {
painter->setBrush(palette().highlight());
} else {
painter->setBrush(track->GetBrush());
}
selection_manager_.DeclareDrawnObject(key, key_rect);
switch (key->type()) {
case NodeKeyframe::kLinear:
{
QPointF points[] = {
QPointF(key_rect.center().x(), key_rect.top()),
QPointF(key_rect.right(), key_rect.center().y()),
QPointF(key_rect.center().x(), key_rect.bottom()),
QPointF(key_rect.left(), key_rect.center().y())
};
painter->drawPolygon(points, 4);
break;
}
case NodeKeyframe::kBezier:
painter->drawEllipse(key_rect);
break;
case NodeKeyframe::kHold:
painter->drawRect(key_rect);
break;
}
}
}
super::drawForeground(painter, rect);
}
void KeyframeViewBase::ScaleChangedEvent(const double &scale)
{
TimeBasedView::ScaleChangedEvent(scale);
super::ScaleChangedEvent(scale);
for (auto 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 *)
{
Redraw();
}
void KeyframeViewBase::TimeTargetChangedEvent(Node *target)
{
QMap<NodeKeyframe*, KeyframeViewItem*>::const_iterator i;
Redraw();
}
for (i=item_map_.begin();i!=item_map_.end();i++) {
i.value()->SetTimeTarget(target);
}
void KeyframeViewBase::TimebaseChangedEvent(const rational &timebase)
{
super::TimebaseChangedEvent(timebase);
selection_manager_.SetTimebase(timebase);
}
void KeyframeViewBase::ContextMenuEvent(Menu& m)
@@ -451,6 +420,30 @@ void KeyframeViewBase::ContextMenuEvent(Menu& m)
Q_UNUSED(m)
}
void KeyframeViewBase::SelectKeyframe(NodeKeyframe *key)
{
if (selection_manager_.Select(key)) {
Redraw();
}
}
void KeyframeViewBase::DeselectKeyframe(NodeKeyframe *key)
{
if (selection_manager_.Deselect(key)) {
Redraw();
}
}
rational KeyframeViewBase::GetAdjustedKeyframeTime(NodeKeyframe *key)
{
return GetAdjustedTime(key->parent(), GetTimeTarget(), key->time(), false);
}
double KeyframeViewBase::GetKeyframeSceneX(NodeKeyframe *key)
{
return TimeToScene(GetAdjustedKeyframeTime(key));
}
rational KeyframeViewBase::CalculateNewTimeFromScreen(const rational &old_time, double cursor_diff)
{
return rational::fromDouble(old_time.toDouble() + cursor_diff);
@@ -492,16 +485,15 @@ void KeyframeViewBase::ShowContextMenu()
QAction* bezier_key_action = nullptr;
QAction* hold_key_action = nullptr;
QList<QGraphicsItem*> items = scene()->selectedItems();
if (!items.isEmpty()) {
if (!GetSelectedKeyframes().isEmpty()) {
bool all_keys_are_same_type = true;
NodeKeyframe::Type type = static_cast<KeyframeViewItem*>(items.first())->key()->type();
NodeKeyframe::Type type = GetSelectedKeyframes().first()->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));
for (int i=1;i<GetSelectedKeyframes().size();i++) {
NodeKeyframe* key_item = GetSelectedKeyframes().at(i);
NodeKeyframe* prev_item = GetSelectedKeyframes().at(i-1);
if (key_item->key()->type() != prev_item->key()->type()) {
if (key_item->type() != prev_item->type()) {
all_keys_are_same_type = false;
break;
}
@@ -536,7 +528,7 @@ void KeyframeViewBase::ShowContextMenu()
ContextMenuEvent(m);
if (!items.isEmpty()) {
if (!GetSelectedKeyframes().isEmpty()) {
m.addSeparator();
QAction* properties_action = m.addAction(tr("P&roperties"));
@@ -546,7 +538,7 @@ void KeyframeViewBase::ShowContextMenu()
QAction* selected = m.exec(QCursor::pos());
// Process keyframe type changes
if (!items.isEmpty()) {
if (selected) {
if (selected == linear_key_action
|| selected == bezier_key_action
|| selected == hold_key_action) {
@@ -561,26 +553,18 @@ void KeyframeViewBase::ShowContextMenu()
}
MultiUndoCommand* command = new MultiUndoCommand();
foreach (QGraphicsItem* item, items) {
command->add_child(new KeyframeSetTypeCommand(static_cast<KeyframeViewItem*>(item)->key(),
new_type));
foreach (NodeKeyframe* item, GetSelectedKeyframes()) {
command->add_child(new KeyframeSetTypeCommand(item, new_type));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
Core::instance()->undo_stack()->push(command);
}
}
}
void KeyframeViewBase::ShowKeyframePropertiesDialog()
{
QList<QGraphicsItem*> items = scene()->selectedItems();
QVector<NodeKeyframe*> keys;
foreach (QGraphicsItem* item, items) {
keys.append(static_cast<KeyframeViewItem*>(item)->key());
}
if (!keys.isEmpty()) {
KeyframePropertiesDialog kd(keys, timebase(), this);
if (!GetSelectedKeyframes().isEmpty()) {
KeyframePropertiesDialog kd(GetSelectedKeyframes(), timebase(), this);
kd.exec();
}
}
@@ -594,25 +578,15 @@ void KeyframeViewBase::AutoSelectKeyTimeNeighbors()
// Prevents infinite loop
currently_autoselecting_ = true;
QList<QGraphicsItem*> selected_items = scene()->selectedItems();
QVector<NodeKeyframe*> copy = GetSelectedKeyframes();
foreach (NodeKeyframe *key, copy) {
rational key_time = key->time();
foreach (QGraphicsItem* g, selected_items) {
KeyframeViewItem* key_item = static_cast<KeyframeViewItem*>(g);
rational key_time = key_item->key()->time();
QVector<NodeKeyframe*> keys = key_item->key()->parent()->GetKeyframesAtTime(key_item->key()->input(), key_time, key_item->key()->element());
QVector<NodeKeyframe*> keys = key->parent()->GetKeyframesAtTime(key->input(), key_time, key->element());
foreach (NodeKeyframe* k, keys) {
if (k == key_item->key()) {
continue;
}
// Ensure this key is not already selected
KeyframeViewItem* item = item_map_.value(k);
if (item) {
item->setSelected(true);
if (k != key) {
SelectKeyframe(k);
}
}
}
@@ -620,4 +594,9 @@ void KeyframeViewBase::AutoSelectKeyTimeNeighbors()
currently_autoselecting_ = false;
}
void KeyframeViewBase::Redraw()
{
viewport()->update();
}
}