moved timeline undoable commands to using the new NodeAddCommand
Previous iteration used some "magic code" that added clips automatically to the timeline. This was functional but ultimately outside of the undo commands' control meaning nodes could be infinitely added and abandoned. This makes the add process part of the undo command which means it's all undoable as the user would expect.
This commit is contained in:
@@ -47,6 +47,7 @@ NodeViewItem::NodeViewItem(QGraphicsItem *parent) :
|
||||
// Set flags for this widget
|
||||
setFlag(QGraphicsItem::ItemIsMovable);
|
||||
setFlag(QGraphicsItem::ItemIsSelectable);
|
||||
setFlag(QGraphicsItem::ItemSendsGeometryChanges);
|
||||
|
||||
//
|
||||
// We use font metrics to set all the UI measurements for DPI-awareness
|
||||
@@ -77,6 +78,8 @@ void NodeViewItem::SetNode(Node *n)
|
||||
{
|
||||
node_ = n;
|
||||
|
||||
setPos(node_->GetPosition());
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -256,8 +259,6 @@ void NodeViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti
|
||||
}
|
||||
}
|
||||
|
||||
#include "node/block/block.h"
|
||||
|
||||
void NodeViewItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
// We override standard mouse behavior in some cases. In these cases, we don't want the standard "move" and "release"
|
||||
@@ -470,3 +471,12 @@ void NodeViewItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||
QGraphicsRectItem::mouseReleaseEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant NodeViewItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
|
||||
{
|
||||
if (change == ItemPositionHasChanged && node_) {
|
||||
node_->SetPosition(value.toPointF());
|
||||
}
|
||||
|
||||
return QGraphicsItem::itemChange(change, value);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,8 @@ protected:
|
||||
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
|
||||
virtual QVariant itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) override;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Get the relative position to draw text for a parameter at a certain index
|
||||
|
||||
@@ -70,8 +70,8 @@ NodeAddCommand::NodeAddCommand(NodeGraph *graph, Node *node, QUndoCommand *paren
|
||||
graph_(graph),
|
||||
node_(node)
|
||||
{
|
||||
// Ensures that when this command is destroyed, if redo() hasn't been called, the node will be destroyed too
|
||||
node->setParent(&memory_manager_);
|
||||
// Ensures that when this command is destroyed, if redo() is never called again, the node will be destroyed too
|
||||
node_->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
void NodeAddCommand::redo()
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "node/graph.h"
|
||||
#include "node/node.h"
|
||||
#include "nodeviewitem.h"
|
||||
|
||||
/**
|
||||
* @brief An undoable commnd for connecting two NodeParams together
|
||||
@@ -62,7 +63,9 @@ private:
|
||||
|
||||
class NodeRemoveCommand : public QUndoCommand {
|
||||
public:
|
||||
NodeRemoveCommand(NodeGraph* graph, const QList<Node*>& nodes, QUndoCommand* parent = nullptr);
|
||||
NodeRemoveCommand(NodeGraph* graph,
|
||||
const QList<Node*>& nodes,
|
||||
QUndoCommand* parent = nullptr);
|
||||
|
||||
virtual void redo() override;
|
||||
virtual void undo() override;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "common/timecodefunctions.h"
|
||||
#include "tool/tool.h"
|
||||
#include "trackview/trackview.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
TimelineWidget::TimelineWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
@@ -382,6 +383,18 @@ void TimelineWidget::SplitAtPlayhead()
|
||||
}
|
||||
}
|
||||
|
||||
void TimelineWidget::DeleteSelected()
|
||||
{
|
||||
QList<TimelineViewBlockItem *> list = GetSelectedBlocks();
|
||||
|
||||
// No-op if nothing is selected
|
||||
if (list.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
QList<TimelineViewBlockItem *> TimelineWidget::GetSelectedBlocks()
|
||||
{
|
||||
QList<TimelineViewBlockItem *> list;
|
||||
@@ -440,14 +453,19 @@ void TimelineWidget::RippleEditTo(olive::timeline::MovementMode mode, bool inser
|
||||
rational ripple_length = out_ripple - in_ripple;
|
||||
|
||||
foreach (TrackOutput* track, timeline_node_->Tracks()) {
|
||||
GapBlock* gap = nullptr;
|
||||
if (insert_gaps) {
|
||||
gap = new GapBlock();
|
||||
gap->set_length(ripple_length);
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(track->parent()), gap, command);
|
||||
}
|
||||
|
||||
TrackRippleRemoveAreaCommand* ripple_command = new TrackRippleRemoveAreaCommand(track,
|
||||
in_ripple,
|
||||
out_ripple,
|
||||
command);
|
||||
|
||||
if (insert_gaps) {
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(ripple_length);
|
||||
ripple_command->SetInsert(gap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,8 @@ public:
|
||||
|
||||
void SplitAtPlayhead();
|
||||
|
||||
void DeleteSelected();
|
||||
|
||||
QList<TimelineViewBlockItem*> GetSelectedBlocks();
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "widget/timelinewidget/timelinewidget.h"
|
||||
|
||||
#include "core.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
TimelineWidget::AddTool::AddTool(TimelineWidget *parent) :
|
||||
Tool(parent),
|
||||
@@ -46,12 +47,21 @@ void TimelineWidget::AddTool::MouseRelease(TimelineViewMouseEvent *event)
|
||||
|
||||
if (ghost_) {
|
||||
if (!ghost_->AdjustedLength().isNull()) {
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
ClipBlock* clip = new ClipBlock();
|
||||
clip->set_length(ghost_->AdjustedLength());
|
||||
olive::undo_stack.push(new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track.type()),
|
||||
track.index(),
|
||||
clip,
|
||||
ghost_->GetAdjustedIn()));
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(parent()->timeline_node_->parent()),
|
||||
clip,
|
||||
command);
|
||||
|
||||
new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track.type()),
|
||||
track.index(),
|
||||
clip,
|
||||
ghost_->GetAdjustedIn(),
|
||||
command);
|
||||
|
||||
olive::undo_stack.push(command);
|
||||
}
|
||||
|
||||
parent()->ClearGhosts();
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "node/color/opacity/opacity.h"
|
||||
#include "node/input/media/audio/audio.h"
|
||||
#include "node/input/media/video/video.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
TrackType TrackTypeFromStreamType(Stream::Type stream_type)
|
||||
{
|
||||
@@ -207,6 +208,7 @@ void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event)
|
||||
{
|
||||
if (parent()->HasGhosts()) {
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
NodeGraph* dst_graph = static_cast<NodeGraph*>(parent()->timeline_node_->parent());
|
||||
|
||||
QVector<Block*> block_items(parent()->ghost_items_.size());
|
||||
|
||||
@@ -218,6 +220,7 @@ void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event)
|
||||
ClipBlock* clip = new ClipBlock();
|
||||
clip->set_length(ghost->Length());
|
||||
clip->set_block_name(footage_stream->footage()->name());
|
||||
new NodeAddCommand(dst_graph, clip, command);
|
||||
|
||||
switch (footage_stream->type()) {
|
||||
case Stream::kVideo:
|
||||
@@ -225,10 +228,12 @@ void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event)
|
||||
{
|
||||
VideoInput* video_input = new VideoInput();
|
||||
video_input->SetFootage(footage_stream);
|
||||
NodeParam::ConnectEdge(video_input->output(), clip->texture_input());
|
||||
new NodeAddCommand(dst_graph, video_input, command);
|
||||
new NodeEdgeAddCommand(video_input->output(), clip->texture_input(), command);
|
||||
|
||||
TransformDistort* transform = new TransformDistort();
|
||||
NodeParam::ConnectEdge(transform->output(), video_input->matrix_input());
|
||||
new NodeAddCommand(dst_graph, transform, command);
|
||||
new NodeEdgeAddCommand(transform->output(), video_input->matrix_input(), command);
|
||||
|
||||
//OpacityNode* opacity = new OpacityNode();
|
||||
//NodeParam::ConnectEdge(opacity->texture_output(), clip->texture_input());
|
||||
@@ -239,7 +244,8 @@ void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event)
|
||||
{
|
||||
AudioInput* audio_input = new AudioInput();
|
||||
audio_input->SetFootage(footage_stream);
|
||||
NodeParam::ConnectEdge(audio_input->output(), clip->texture_input());
|
||||
new NodeAddCommand(dst_graph, audio_input, command);
|
||||
new NodeEdgeAddCommand(audio_input->output(), clip->texture_input(), command);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "config/config.h"
|
||||
#include "core.h"
|
||||
#include "node/block/gap/gap.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
TimelineWidget::PointerTool::PointerTool(TimelineWidget *parent) :
|
||||
Tool(parent),
|
||||
@@ -158,10 +159,6 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
|
||||
// We create a QObject on the stack so that when we allocate objects on the heap, they aren't parent-less and will
|
||||
// get cleaned up if they aren't re-parented by the attached NodeGraph
|
||||
QObject block_memory_manager;
|
||||
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// Since all the ghosts will be leaving their old position in some way, we replace all of them with gaps here so the
|
||||
@@ -171,9 +168,12 @@ void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *e
|
||||
|
||||
// Replace old Block with a new Gap
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->setParent(&block_memory_manager);
|
||||
gap->set_length(b->length());
|
||||
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()),
|
||||
gap,
|
||||
command);
|
||||
|
||||
new TrackReplaceBlockCommand(parent()->GetTrackFromReference(ghost->Track()),
|
||||
b,
|
||||
gap,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "widget/timelinewidget/timelinewidget.h"
|
||||
|
||||
#include "node/block/gap/gap.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
TimelineWidget::RippleTool::RippleTool(TimelineWidget* parent) :
|
||||
PointerTool(parent)
|
||||
@@ -48,13 +49,15 @@ void TimelineWidget::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *ev
|
||||
if (ghost->AdjustedLength() > 0) {
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(ghost->AdjustedLength());
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(parent()->timeline_node_->parent()), gap, command);
|
||||
|
||||
Block* block_to_append_gap_to = Node::ValueToPtr<Block>(ghost->data(TimelineViewGhostItem::kReferenceBlock));
|
||||
|
||||
new TrackInsertBlockBetweenBlocksCommand(parent()->GetTrackFromReference(ghost->Track()),
|
||||
gap,
|
||||
block_to_append_gap_to,
|
||||
block_to_append_gap_to->next());
|
||||
block_to_append_gap_to->next(),
|
||||
command);
|
||||
}
|
||||
} else {
|
||||
// This was a Block that already existed
|
||||
@@ -68,6 +71,8 @@ void TimelineWidget::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *ev
|
||||
} else {
|
||||
// Assumed the Block was a Gap and it was reduced to zero length, remove it here
|
||||
new TrackRippleRemoveBlockCommand(parent()->GetTrackFromReference(ghost->Track()), b, command);
|
||||
|
||||
new NodeRemoveCommand(static_cast<NodeGraph*>(b->parent()), {b}, command);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "widget/timelinewidget/timelinewidget.h"
|
||||
|
||||
#include "node/block/gap/gap.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
TimelineWidget::RollingTool::RollingTool(TimelineWidget* parent) :
|
||||
PointerTool(parent)
|
||||
@@ -43,6 +44,9 @@ void TimelineWidget::RollingTool::MouseReleaseInternal(TimelineViewMouseEvent *e
|
||||
// We'll need to insert a gap here, so we'll do a Place command instead
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(ghost->Length());
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()),
|
||||
gap,
|
||||
command);
|
||||
|
||||
new TrackReplaceBlockCommand(parent()->GetTrackFromReference(ghost->Track()), b, gap, command);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "widget/timelinewidget/timelinewidget.h"
|
||||
|
||||
#include "node/block/gap/gap.h"
|
||||
#include "widget/nodeview/nodeviewundo.h"
|
||||
|
||||
TimelineWidget::SlideTool::SlideTool(TimelineWidget* parent) :
|
||||
PointerTool(parent)
|
||||
@@ -46,6 +47,7 @@ void TimelineWidget::SlideTool::MouseReleaseInternal(TimelineViewMouseEvent *eve
|
||||
} else if (ghost->mode() == olive::timeline::kMove && b->previous() == nullptr) {
|
||||
GapBlock* gap = new GapBlock();
|
||||
gap->set_length(ghost->InAdjustment());
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(b->parent()), gap, command);
|
||||
new TrackPrependBlockCommand(parent()->GetTrackFromReference(ghost->Track()), gap, command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +94,9 @@ void TimelineWidget::TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
|
||||
QUndoCommand* command = new QUndoCommand();
|
||||
|
||||
// Place transition in place
|
||||
new NodeAddCommand(static_cast<NodeGraph*>(parent()->timeline_node_->parent()),
|
||||
transition,
|
||||
command);
|
||||
new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track.type()),
|
||||
track.index(),
|
||||
transition,
|
||||
|
||||
@@ -183,7 +183,7 @@ void TrackRippleRemoveAreaCommand::redo()
|
||||
splice_original_length_ = splice_->length();
|
||||
splice_->set_length(out_ - splice_->in());
|
||||
|
||||
track_->AddBlockToGraph(copy);
|
||||
static_cast<NodeGraph*>(track_->parent())->AddNode(copy);
|
||||
Node::CopyInputs(splice_, copy);
|
||||
|
||||
track_->InsertBlockAfter(copy, splice_);
|
||||
@@ -213,6 +213,8 @@ void TrackRippleRemoveAreaCommand::redo()
|
||||
// Remove all blocks that are flagged for removal
|
||||
foreach (Block* remove_block, removed_blocks_) {
|
||||
track_->RippleRemoveBlock(remove_block);
|
||||
|
||||
// FIXME: Delete blocks from graph and restore them in undo
|
||||
}
|
||||
|
||||
// If we picked up a block to trim the out point of
|
||||
@@ -221,13 +223,12 @@ void TrackRippleRemoveAreaCommand::redo()
|
||||
}
|
||||
|
||||
// If we were given a block to insert, insert it here
|
||||
if (insert_ != nullptr) {
|
||||
track_->AddBlockToGraph(insert_);
|
||||
|
||||
if (trim_out_ == nullptr) {
|
||||
if (insert_) {
|
||||
qDebug() << "Insert is" << insert_ << ", parent is" << insert_->parent();
|
||||
if (!trim_out_) {
|
||||
// This is the start of the Sequence
|
||||
track_->PrependBlock(insert_);
|
||||
} else if (trim_in_ == nullptr) {
|
||||
} else if (!trim_in_) {
|
||||
// This is the end of the Sequence
|
||||
track_->AppendBlock(insert_);
|
||||
} else {
|
||||
@@ -291,7 +292,6 @@ TrackPlaceBlockCommand::TrackPlaceBlockCommand(TrackList *timeline, int track, B
|
||||
gap_(nullptr)
|
||||
{
|
||||
insert_ = block;
|
||||
insert_->setParent(&memory_manager_);
|
||||
}
|
||||
|
||||
void TrackPlaceBlockCommand::redo()
|
||||
@@ -315,6 +315,7 @@ void TrackPlaceBlockCommand::redo()
|
||||
// If so, insert a gap here
|
||||
gap_ = new GapBlock();
|
||||
gap_->set_length(in_ - track_->track_length());
|
||||
static_cast<NodeGraph*>(track_->parent())->AddNode(gap_);
|
||||
track_->AppendBlock(gap_);
|
||||
}
|
||||
|
||||
@@ -331,7 +332,6 @@ void TrackPlaceBlockCommand::undo()
|
||||
{
|
||||
if (append_) {
|
||||
track_->RippleRemoveBlock(insert_);
|
||||
TakeNodeFromParentGraph(insert_, &memory_manager_);
|
||||
|
||||
if (gap_ != nullptr) {
|
||||
track_->RippleRemoveBlock(gap_);
|
||||
@@ -365,7 +365,7 @@ void BlockSplitCommand::redo()
|
||||
|
||||
block_->set_length(new_length_);
|
||||
|
||||
track_->AddBlockToGraph(new_block_);
|
||||
static_cast<NodeGraph*>(block_->parent())->AddNode(new_block_);
|
||||
Node::CopyInputs(block_, new_block_);
|
||||
|
||||
// Will re-parent new_block_ to the track's graph
|
||||
|
||||
Reference in New Issue
Block a user