diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index 787cf5442..13a62e8a1 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -541,4 +541,14 @@ TimeRange ClipBlock::media_range() const return InputTimeAdjustment(kBufferIn, -1, TimeRange(0, length())); } +MultiCamNode *ClipBlock::FindMulticam() +{ + auto v = FindInputNodesConnectedToInput(NodeInput(this, kBufferIn)); + if (v.empty()) { + return nullptr; + } else { + return v.first(); + } +} + } diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 5c84a1eca..15cadcfb7 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -24,6 +24,7 @@ #include "audio/audiovisualwaveform.h" #include "codec/decoder.h" #include "node/block/block.h" +#include "node/input/multicam/multicamnode.h" #include "node/output/track/track.h" namespace olive { @@ -197,6 +198,8 @@ public: SetStandardValue(kLoopModeInput, int(l)); } + MultiCamNode *FindMulticam(); + static const QString kBufferIn; static const QString kMediaInInput; static const QString kSpeedInput; diff --git a/app/panel/multicam/multicampanel.h b/app/panel/multicam/multicampanel.h index b8634bbfc..ac271aedb 100644 --- a/app/panel/multicam/multicampanel.h +++ b/app/panel/multicam/multicampanel.h @@ -17,6 +17,11 @@ public: widget_->SetMulticamNode(n); } + void SetClip(ClipBlock* clip) + { + widget_->SetClip(clip); + } + protected: virtual void Retranslate() override; diff --git a/app/widget/multicam/multicamwidget.cpp b/app/widget/multicam/multicamwidget.cpp index 3ff424011..bca0c8db5 100644 --- a/app/widget/multicam/multicamwidget.cpp +++ b/app/widget/multicam/multicamwidget.cpp @@ -20,6 +20,7 @@ #include "multicamwidget.h" #include "widget/nodeparamview/nodeparamviewundo.h" +#include "widget/timelinewidget/undo/timelineundosplit.h" namespace olive { @@ -27,7 +28,8 @@ namespace olive { MulticamWidget::MulticamWidget(QWidget *parent) : super{new MulticamDisplay(), parent}, - node_(nullptr) + node_(nullptr), + clip_(nullptr) { auto_cacher()->SetMulticamMode(true); auto_cacher()->SetIgnoreCacheRequests(true); @@ -41,6 +43,11 @@ void MulticamWidget::SetMulticamNode(MultiCamNode *n) static_cast(display_widget())->SetMulticamNode(n); } +void MulticamWidget::SetClip(ClipBlock *clip) +{ + clip_ = clip; +} + RenderTicketPtr MulticamWidget::GetSingleFrame(const rational &t, bool dry) { if (node_) { @@ -73,8 +80,36 @@ void MulticamWidget::DisplayClicked(const QPoint &p) int r = click.y() / (height/multi); MultiUndoCommand *command = new MultiUndoCommand(); - command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(NodeInput(node_, node_->kCurrentInput)), node_->RowsColsToIndex(r, c, rows, cols))); + + const bool enable_split = true; + + MultiCamNode *cam = node_; + ClipBlock *clip = clip_; + + if (clip_ && enable_split && clip_->in() < GetTime() && clip_->out() > GetTime()) { + QVector blocks; + + blocks.append(clip_); + blocks.append(clip_->block_links()); + + auto split = new BlockSplitPreservingLinksCommand(blocks, {GetTime()}); + split->redo_now(); + command->add_child(split); + + clip = static_cast(split->GetSplit(clip_, 0)); + + cam = clip->FindMulticam(); + } + + command->add_child(new NodeParamSetStandardValueCommand(NodeKeyframeTrackReference(NodeInput(cam, cam->kCurrentInput)), cam->RowsColsToIndex(r, c, rows, cols))); Core::instance()->undo_stack()->push(command); + + if (cam != node_) { + SetMulticamNode(cam); + } + if (clip != clip_) { + SetClip(clip); + } } } diff --git a/app/widget/multicam/multicamwidget.h b/app/widget/multicam/multicamwidget.h index b80414c97..b32fce9e8 100644 --- a/app/widget/multicam/multicamwidget.h +++ b/app/widget/multicam/multicamwidget.h @@ -35,12 +35,16 @@ public: void SetMulticamNode(MultiCamNode *n); + void SetClip(ClipBlock *clip); + protected: virtual RenderTicketPtr GetSingleFrame(const rational &t, bool dry = false) override; private: MultiCamNode *node_; + ClipBlock *clip_; + private slots: void DisplayClicked(const QPoint &p); diff --git a/app/widget/timelinewidget/undo/timelineundosplit.cpp b/app/widget/timelinewidget/undo/timelineundosplit.cpp index da810f321..8386f6387 100644 --- a/app/widget/timelinewidget/undo/timelineundosplit.cpp +++ b/app/widget/timelinewidget/undo/timelineundosplit.cpp @@ -97,62 +97,68 @@ void BlockSplitCommand::undo() // // BlockSplitPreservingLinksCommand // -void BlockSplitPreservingLinksCommand::redo() +Block *BlockSplitPreservingLinksCommand::GetSplit(Block *original, int time_index) const { - if (commands_.isEmpty()) { - QVector< QVector > split_blocks(times_.size()); - - for (int i=0;i times_.at(i-1)); - - QVector splits(blocks_.size()); - - for (int j=0;jin() < time && b->out() > time) { - BlockSplitCommand* split_command = new BlockSplitCommand(b, time); - split_command->redo_now(); - splits.replace(j, split_command->new_block()); - commands_.append(split_command); - } else { - splits.replace(j, nullptr); - } - } - - split_blocks.replace(i, splits); + if (time_index >= 0 && time_index < times_.size()) { + int original_index = blocks_.indexOf(original); + if (original_index != -1) { + return splits_.at(time_index).at(original_index); } + } - // Now that we've determined all the splits, we can relink everything - for (int i=0;i times_.at(i-1)); - foreach (const QVector& split_list, split_blocks) { - NodeLinkCommand* blc = new NodeLinkCommand(split_list.at(i), split_list.at(j), true); - blc->redo_now(); - commands_.append(blc); - } - } + QVector splits(blocks_.size()); + + for (int j=0;jin() < time && b->out() > time) { + BlockSplitCommand* split_command = new BlockSplitCommand(b, time); + split_command->redo_now(); + splits.replace(j, split_command->new_block()); + commands_.append(split_command); + } else { + splits.replace(j, nullptr); } } - } else { - for (int i=0; iredo_now(); + + splits_.replace(i, splits); + } + + // Now that we've determined all the splits, we can relink everything + for (int i=0;i& split_list, splits_) { + NodeLinkCommand* blc = new NodeLinkCommand(split_list.at(i), split_list.at(j), true); + blc->redo_now(); + commands_.append(blc); + } + } } } } diff --git a/app/widget/timelinewidget/undo/timelineundosplit.h b/app/widget/timelinewidget/undo/timelineundosplit.h index 1fe9f9122..f7014d0e9 100644 --- a/app/widget/timelinewidget/undo/timelineundosplit.h +++ b/app/widget/timelinewidget/undo/timelineundosplit.h @@ -91,8 +91,17 @@ public: return blocks_.first()->project(); } + Block *GetSplit(Block *original, int time_index) const; + protected: - virtual void redo() override; + virtual void prepare() override; + + virtual void redo() override + { + for (int i=0; iredo_now(); + } + } virtual void undo() override { @@ -108,6 +117,8 @@ private: QVector commands_; + QVector< QVector > splits_; + }; class TrackSplitAtTimeCommand : public UndoCommand { diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index a4aefc1b6..184b847f4 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -498,11 +498,12 @@ void MainWindow::TimelinePanelSelectionChanged(const QVector &blocks) if (PanelManager::instance()->CurrentlyFocused(false) == panel) { UpdateNodePanelContextFromTimelinePanel(panel); + ClipBlock *clip = nullptr; MultiCamNode *multicam = nullptr; for (Block *b : blocks) { - if (ClipBlock *c = dynamic_cast(b)) { - if ((multicam = dynamic_cast(c->GetConnectedOutput(c->kBufferIn)))) { + if ((clip = dynamic_cast(b))) { + if ((multicam = clip->FindMulticam())) { break; } } @@ -510,10 +511,12 @@ void MainWindow::TimelinePanelSelectionChanged(const QVector &blocks) if (multicam) { multicam_panel_->SetMulticamNode(multicam); + multicam_panel_->SetClip(clip); multicam_panel_->ConnectViewerNode(panel->GetConnectedViewer()); } else { multicam_panel_->ConnectViewerNode(nullptr); multicam_panel_->SetMulticamNode(nullptr); + multicam_panel_->SetClip(nullptr); } } }