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
+5 -5
View File
@@ -16,13 +16,13 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/keyframeview/keyframeview.h
widget/keyframeview/keyframeview.cpp
widget/keyframeview/keyframeviewbase.h
widget/keyframeview/keyframeview.h
widget/keyframeview/keyframeviewbase.cpp
widget/keyframeview/keyframeviewitem.h
widget/keyframeview/keyframeviewitem.cpp
widget/keyframeview/keyframeviewundo.h
widget/keyframeview/keyframeviewbase.h
widget/keyframeview/keyframeviewinputconnection.cpp
widget/keyframeview/keyframeviewinputconnection.h
widget/keyframeview/keyframeviewundo.cpp
widget/keyframeview/keyframeviewundo.h
PARENT_SCOPE
)
-19
View File
@@ -31,29 +31,10 @@ KeyframeView::KeyframeView(QWidget *parent) :
setAlignment(Qt::AlignLeft | Qt::AlignTop);
}
void KeyframeView::SetElementY(const NodeInput &c, int y)
{
qreal scene_y = mapToScene(mapFromGlobal(QPoint(0, y))).y();
element_y_.insert(c, scene_y);
for (auto it=item_map().cbegin(); it!=item_map().cend(); it++) {
if (it.key()->key_track_ref().input() == c) {
it.value()->SetOverrideY(scene_y);
}
}
}
void KeyframeView::SceneRectUpdateEvent(QRectF &rect)
{
rect.setY(0);
rect.setHeight(max_scroll_);
}
KeyframeViewItem* KeyframeView::AddKeyframe(NodeKeyframe* key)
{
KeyframeViewItem* item = super::AddKeyframe(key);
item->SetOverrideY(element_y_.value(key->key_track_ref().input()));
return item;
}
}
+1 -7
View File
@@ -34,19 +34,13 @@ public:
void SetMaxScroll(int i)
{
max_scroll_ = i;
UpdateSceneRect();
}
void SetElementY(const NodeInput& c, int y);
protected:
virtual void SceneRectUpdateEvent(QRectF& rect) override;
public slots:
virtual KeyframeViewItem* AddKeyframe(NodeKeyframe* key) override;
private:
QHash<NodeInput, qreal> element_y_;
int max_scroll_;
};
+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();
}
}
+39 -36
View File
@@ -21,11 +21,12 @@
#ifndef KEYFRAMEVIEWBASE_H
#define KEYFRAMEVIEWBASE_H
#include "keyframeviewitem.h"
#include "keyframeviewinputconnection.h"
#include "node/keyframe.h"
#include "widget/curvewidget/beziercontrolpointitem.h"
#include "widget/menu/menu.h"
#include "widget/timebased/timebasedview.h"
#include "widget/timebased/timebasedviewselectionmanager.h"
#include "widget/timetarget/timetarget.h"
namespace olive {
@@ -36,51 +37,49 @@ class KeyframeViewBase : public TimeBasedView, public TimeTargetObject
public:
KeyframeViewBase(QWidget* parent = nullptr);
virtual void Clear();
void DeleteSelected();
void AddKeyframesOfNode(Node* n);
using ElementConnections = QVector<KeyframeViewInputConnection *>;
using InputConnections = QVector<ElementConnections>;
using NodeConnections = QMap<QString, InputConnections>;
void AddKeyframesOfInput(Node *n, const QString &input);
NodeConnections AddKeyframesOfNode(Node* n);
void AddKeyframesOfElement(const NodeInput &input);
InputConnections AddKeyframesOfInput(Node *n, const QString &input);
void AddKeyframesOfTrack(const NodeKeyframeTrackReference &ref);
ElementConnections AddKeyframesOfElement(const NodeInput &input);
void RemoveKeyframesOfNode(Node* n);
KeyframeViewInputConnection *AddKeyframesOfTrack(const NodeKeyframeTrackReference &ref);
void RemoveKeyframesOfInput(Node *n, const QString &input);
void RemoveKeyframesOfElement(const NodeInput &input);
void RemoveKeyframesOfTrack(const NodeKeyframeTrackReference &ref);
void RemoveKeyframesOfTrack(KeyframeViewInputConnection *connection);
void SelectAll();
void DeselectAll();
void Clear();
const QVector<NodeKeyframe*> &GetSelectedKeyframes() const
{
return selection_manager_.GetSelectedObjects();
}
signals:
void Dragged(int current_x, int current_y);
public slots:
virtual KeyframeViewItem* AddKeyframe(NodeKeyframe* key);
void RemoveKeyframe(NodeKeyframe* key);
protected:
virtual void mousePressEvent(QMouseEvent *event) override;
virtual void mouseMoveEvent(QMouseEvent *event) override;
virtual void mouseReleaseEvent(QMouseEvent *event) override;
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
virtual void ScaleChangedEvent(const double& scale) override;
const QMap<NodeKeyframe*, KeyframeViewItem*>& item_map() const;
virtual void KeyframeAboutToBeRemoved(NodeKeyframe* key);
virtual void TimeTargetChangedEvent(Node*) override;
virtual void TimebaseChangedEvent(const rational &timebase) override;
virtual void ContextMenuEvent(Menu &m);
bool IsDragging() const
@@ -88,6 +87,19 @@ protected:
return dragging_;
}
void SelectKeyframe(NodeKeyframe *key);
void DeselectKeyframe(NodeKeyframe *key);
bool IsKeyframeSelected(NodeKeyframe *key) const
{
return selection_manager_.IsSelected(key);
}
rational GetAdjustedKeyframeTime(NodeKeyframe *key);
double GetKeyframeSceneX(NodeKeyframe *key);
private:
rational CalculateNewTimeFromScreen(const rational& old_time, double cursor_diff);
@@ -97,31 +109,20 @@ private:
QPointF GetScaledCursorPos(const QPointF &cursor_pos);
struct KeyframeItemAndTime {
KeyframeViewItem* key;
qreal item_x;
rational time;
double value;
};
QMap<NodeKeyframe*, KeyframeViewItem*> item_map_;
Tool::Item active_tool_;
QPointF drag_start_;
BezierControlPointItem* dragging_bezier_point_;
QPointF dragging_bezier_point_start_;
QPointF dragging_bezier_point_opposing_start_;
KeyframeViewItem* initial_drag_item_;
QVector<KeyframeItemAndTime> selected_keys_;
QVector<KeyframeViewInputConnection*> tracks_;
bool currently_autoselecting_;
bool dragging_;
TimeBasedViewSelectionManager<NodeKeyframe> selection_manager_;
private slots:
void ShowContextMenu();
@@ -129,6 +130,8 @@ private slots:
void AutoSelectKeyTimeNeighbors();
void Redraw();
};
}
@@ -0,0 +1,83 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "keyframeviewinputconnection.h"
#include "keyframeview.h"
namespace olive {
KeyframeViewInputConnection::KeyframeViewInputConnection(const NodeKeyframeTrackReference &input, KeyframeViewBase *parent) :
QObject(parent),
keyframe_view_(parent),
input_(input),
y_(0),
y_behavior_(kSingleRow),
brush_(Qt::white)
{
Node *n = input.input().node();
connect(n, &Node::KeyframeAdded, this, &KeyframeViewInputConnection::AddKeyframe);
connect(n, &Node::KeyframeRemoved, this, &KeyframeViewInputConnection::RemoveKeyframe);
connect(n, &Node::KeyframeTimeChanged, this, &KeyframeViewInputConnection::RequireUpdate);
}
void KeyframeViewInputConnection::SetKeyframeY(int y)
{
if (y_ != y) {
y_ = y;
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::SetYBehavior(YBehavior e)
{
if (y_behavior_ != e) {
y_behavior_ = e;
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::SetBrush(const QBrush &brush)
{
if (brush_ != brush) {
brush_ = brush;
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::AddKeyframe(NodeKeyframe *key)
{
if (key->key_track_ref() == input_) {
emit RequireUpdate();
}
}
void KeyframeViewInputConnection::RemoveKeyframe(NodeKeyframe *key)
{
if (key->key_track_ref() == input_) {
emit RequireUpdate();
}
}
}
@@ -0,0 +1,88 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef KEYFRAMEVIEWINPUTCONNECTION_H
#define KEYFRAMEVIEWINPUTCONNECTION_H
#include <QObject>
#include "node/node.h"
#include "node/param.h"
namespace olive {
class KeyframeViewBase;
class KeyframeViewInputConnection : public QObject
{
Q_OBJECT
public:
KeyframeViewInputConnection(const NodeKeyframeTrackReference &input, KeyframeViewBase *parent);
const int &GetKeyframeY() const
{
return y_;
}
void SetKeyframeY(int y);
enum YBehavior {
kSingleRow,
kValueIsHeight
};
void SetYBehavior(YBehavior e);
const QVector<NodeKeyframe*> GetKeyframes() const
{
return input_.input().node()->GetKeyframeTracks(input_.input()).at(input_.track());
}
const QBrush &GetBrush() const
{
return brush_;
}
void SetBrush(const QBrush &brush);
signals:
void RequireUpdate();
private:
KeyframeViewBase *keyframe_view_;
NodeKeyframeTrackReference input_;
int y_;
YBehavior y_behavior_;
QBrush brush_;
private slots:
void AddKeyframe(NodeKeyframe *key);
void RemoveKeyframe(NodeKeyframe *key);
};
}
#endif // KEYFRAMEVIEWINPUTCONNECTION_H
@@ -1,129 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#include "keyframeviewitem.h"
#include <QApplication>
#include <QPainter>
#include <QStyleOptionGraphicsItem>
#include <QWidget>
#include "common/qtutils.h"
namespace olive {
KeyframeViewItem::KeyframeViewItem(NodeKeyframe* key, QGraphicsItem *parent) :
QGraphicsRectItem(parent),
key_(key),
scale_(1.0),
vert_center_(0),
use_custom_brush_(false)
{
setFlag(QGraphicsItem::ItemIsSelectable);
connect(key, &NodeKeyframe::TimeChanged, this, &KeyframeViewItem::UpdatePos);
connect(key, &NodeKeyframe::TypeChanged, this, &KeyframeViewItem::Redraw);
int keyframe_size = QtUtils::QFontMetricsWidth(qApp->fontMetrics(), "Oi");
int half_sz = keyframe_size/2;
setRect(-half_sz, -half_sz, keyframe_size, keyframe_size);
UpdatePos();
// Set default brush
}
void KeyframeViewItem::SetOverrideY(qreal vertical_center)
{
vert_center_ = vertical_center;
UpdatePos();
}
void KeyframeViewItem::SetScale(double scale)
{
scale_ = scale;
UpdatePos();
}
void KeyframeViewItem::SetOverrideBrush(const QBrush &b)
{
use_custom_brush_ = true;
setBrush(b);
}
NodeKeyframe* KeyframeViewItem::key() const
{
return key_;
}
void KeyframeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setRenderHint(QPainter::Antialiasing);
painter->setPen(Qt::black);
if (option->state & QStyle::State_Selected) {
painter->setBrush(widget->palette().highlight());
} else if (use_custom_brush_) {
painter->setBrush(brush());
} else {
painter->setBrush(widget->palette().text());
}
switch (key_->type()) {
case NodeKeyframe::kLinear:
{
QPointF points[] = {
QPointF(rect().center().x(), rect().top()),
QPointF(rect().right(), rect().center().y()),
QPointF(rect().center().x(), rect().bottom()),
QPointF(rect().left(), rect().center().y())
};
painter->drawPolygon(points, 4);
break;
}
case NodeKeyframe::kBezier:
painter->drawEllipse(rect());
break;
case NodeKeyframe::kHold:
painter->drawRect(rect());
break;
}
}
void KeyframeViewItem::TimeTargetChangedEvent(Node *)
{
UpdatePos();
}
void KeyframeViewItem::UpdatePos()
{
rational adjusted = GetAdjustedTime(key_->parent(), GetTimeTarget(), key_->time(), false);
setPos(adjusted.toDouble() * scale_, vert_center_);
}
void KeyframeViewItem::Redraw()
{
QGraphicsItem::update();
}
}
@@ -1,68 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2021 Olive Team
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
***/
#ifndef KEYFRAMEVIEWITEM_H
#define KEYFRAMEVIEWITEM_H
#include <QGraphicsRectItem>
#include "node/keyframe.h"
#include "widget/timetarget/timetarget.h"
namespace olive {
class KeyframeViewItem : public QObject, public QGraphicsRectItem, public TimeTargetObject
{
Q_OBJECT
public:
KeyframeViewItem(NodeKeyframe* key, QGraphicsItem *parent = nullptr);
void SetOverrideY(qreal vertical_center);
void SetScale(double scale);
void SetOverrideBrush(const QBrush& b);
NodeKeyframe* key() const;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
virtual void TimeTargetChangedEvent(Node* ) override;
private:
NodeKeyframe* key_;
double scale_;
qreal vert_center_;
bool use_custom_brush_;
private slots:
void UpdatePos();
void Redraw();
};
}
#endif // KEYFRAMEVIEWITEM_H