multicam: finished UI implementation
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
#include "multicamnode.h"
|
||||
|
||||
#include "node/project/sequence/sequence.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
#define super Node
|
||||
|
||||
const QString MultiCamNode::kCurrentInput = QStringLiteral("current_in");
|
||||
const QString MultiCamNode::kSourcesInput = QStringLiteral("sources_in");
|
||||
const QString MultiCamNode::kSequenceInput = QStringLiteral("sequence_in");
|
||||
const QString MultiCamNode::kSequenceTypeInput = QStringLiteral("sequence_type_in");
|
||||
|
||||
MultiCamNode::MultiCamNode()
|
||||
{
|
||||
@@ -17,6 +21,11 @@ MultiCamNode::MultiCamNode()
|
||||
|
||||
AddInput(kSourcesInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable | kInputFlagArray));
|
||||
SetInputProperty(kSourcesInput, QStringLiteral("arraystart"), 1);
|
||||
|
||||
AddInput(kSequenceInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable));
|
||||
AddInput(kSequenceTypeInput, NodeValue::kCombo, InputFlags(kInputFlagStatic | kInputFlagHidden));
|
||||
|
||||
sequence_ = nullptr;
|
||||
}
|
||||
|
||||
QString MultiCamNode::Name() const
|
||||
@@ -43,7 +52,7 @@ Node::ActiveElements MultiCamNode::GetActiveElementsAtTime(const QString &input,
|
||||
{
|
||||
if (input == kSourcesInput) {
|
||||
int src = GetCurrentSource();
|
||||
if (src >= 0 && src < InputArraySize(kSourcesInput)) {
|
||||
if (src >= 0 && src < GetSourceCount()) {
|
||||
Node::ActiveElements a;
|
||||
a.add(src);
|
||||
return a;
|
||||
@@ -71,12 +80,65 @@ void MultiCamNode::IndexToRowCols(int index, int total_rows, int total_cols, int
|
||||
*row = index/total_cols;
|
||||
}
|
||||
|
||||
Node *MultiCamNode::GetConnectedRenderOutput(const QString &input, int element) const
|
||||
{
|
||||
if (sequence_ && input == kSourcesInput && element >= 0 && element < GetSourceCount()) {
|
||||
return GetTrackList()->GetTrackAt(element);
|
||||
} else {
|
||||
return Node::GetConnectedRenderOutput(input, element);
|
||||
}
|
||||
}
|
||||
|
||||
bool MultiCamNode::IsInputConnectedForRender(const QString &input, int element) const
|
||||
{
|
||||
if (sequence_ && input == kSourcesInput && element >= 0 && element < GetSourceCount()) {
|
||||
return true;
|
||||
} else {
|
||||
return Node::IsInputConnectedForRender(input, element);
|
||||
}
|
||||
}
|
||||
|
||||
void MultiCamNode::InputConnectedEvent(const QString &input, int element, Node *output)
|
||||
{
|
||||
if (input == kSequenceInput) {
|
||||
if (Sequence *s = dynamic_cast<Sequence*>(output)) {
|
||||
SetInputFlags(kSequenceTypeInput, GetInputFlags(kSequenceTypeInput) & InputFlag(~kInputFlagHidden));
|
||||
sequence_ = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MultiCamNode::InputDisconnectedEvent(const QString &input, int element, Node *output)
|
||||
{
|
||||
if (input == kSequenceInput) {
|
||||
SetInputFlags(kSequenceTypeInput, GetInputFlags(kSequenceTypeInput) | kInputFlagHidden);
|
||||
sequence_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
TrackList *MultiCamNode::GetTrackList() const
|
||||
{
|
||||
return sequence_->track_list(static_cast<Track::Type>(GetStandardValue(kSequenceTypeInput).toInt()));
|
||||
}
|
||||
|
||||
void MultiCamNode::Retranslate()
|
||||
{
|
||||
super::Retranslate();
|
||||
|
||||
SetInputName(kCurrentInput, tr("Current"));
|
||||
SetInputName(kSourcesInput, tr("Sources"));
|
||||
SetInputName(kSequenceInput, tr("Sequence"));
|
||||
SetInputName(kSequenceTypeInput, tr("Sequence Type"));
|
||||
SetComboBoxStrings(kSequenceTypeInput, {tr("Video"), tr("Audio")});
|
||||
}
|
||||
|
||||
int MultiCamNode::GetSourceCount() const
|
||||
{
|
||||
if (sequence_) {
|
||||
return GetTrackList()->GetTrackCount();
|
||||
} else {
|
||||
return InputArraySize(kSourcesInput);
|
||||
}
|
||||
}
|
||||
|
||||
void MultiCamNode::GetRowsAndColumns(int sources, int *rows_in, int *cols_in)
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
#define MULTICAMNODE_H
|
||||
|
||||
#include "node/node.h"
|
||||
#include "node/output/track/tracklist.h"
|
||||
|
||||
namespace olive {
|
||||
|
||||
class Sequence;
|
||||
|
||||
class MultiCamNode : public Node
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -26,16 +29,15 @@ public:
|
||||
|
||||
static const QString kCurrentInput;
|
||||
static const QString kSourcesInput;
|
||||
static const QString kSequenceInput;
|
||||
static const QString kSequenceTypeInput;
|
||||
|
||||
int GetCurrentSource() const
|
||||
{
|
||||
return GetStandardValue(kCurrentInput).toInt();
|
||||
}
|
||||
|
||||
int GetSourceCount() const
|
||||
{
|
||||
return InputArraySize(kSourcesInput);
|
||||
}
|
||||
int GetSourceCount() const;
|
||||
|
||||
static void GetRowsAndColumns(int sources, int *rows, int *cols);
|
||||
void GetRowsAndColumns(int *rows, int *cols) const
|
||||
@@ -43,6 +45,11 @@ public:
|
||||
return GetRowsAndColumns(GetSourceCount(), rows, cols);
|
||||
}
|
||||
|
||||
void SetSequenceType(Track::Type t)
|
||||
{
|
||||
SetStandardValue(kSequenceTypeInput, t);
|
||||
}
|
||||
|
||||
static void IndexToRowCols(int index, int total_rows, int total_cols, int *row, int *col);
|
||||
|
||||
static int RowsColsToIndex(int row, int col, int total_rows, int total_cols)
|
||||
@@ -50,6 +57,18 @@ public:
|
||||
return col + row * total_cols;
|
||||
}
|
||||
|
||||
virtual Node *GetConnectedRenderOutput(const QString& input, int element = -1) const override;
|
||||
virtual bool IsInputConnectedForRender(const QString& input, int element = -1) const override;
|
||||
|
||||
protected:
|
||||
virtual void InputConnectedEvent(const QString &input, int element, Node *output) override;
|
||||
virtual void InputDisconnectedEvent(const QString &input, int element, Node *output) override;
|
||||
|
||||
private:
|
||||
TrackList *GetTrackList() const;
|
||||
|
||||
Sequence *sequence_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1287,6 +1287,26 @@ int Node::GetInternalInputArraySize(const QString &input)
|
||||
return array_immediates_.value(input).size();
|
||||
}
|
||||
|
||||
void FindWaysNodeArrivesHereRecursively(const Node *output, const Node *input, QVector<NodeInput> &v)
|
||||
{
|
||||
for (auto it=input->input_connections().cbegin(); it!=input->input_connections().cend(); it++) {
|
||||
if (it->second == output) {
|
||||
v.append(it->first);
|
||||
} else {
|
||||
FindWaysNodeArrivesHereRecursively(output, it->second, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVector<NodeInput> Node::FindWaysNodeArrivesHere(const Node *output) const
|
||||
{
|
||||
QVector<NodeInput> v;
|
||||
|
||||
FindWaysNodeArrivesHereRecursively(output, this, v);
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
void Node::SetInputName(const QString &id, const QString &name)
|
||||
{
|
||||
Input* i = GetInternalInputData(id);
|
||||
|
||||
+113
-85
@@ -418,6 +418,15 @@ public:
|
||||
return IsInputConnected(input.input(), input.element());
|
||||
}
|
||||
|
||||
virtual bool IsInputConnectedForRender(const QString& input, int element = -1) const
|
||||
{
|
||||
return IsInputConnected(input, element);
|
||||
}
|
||||
bool IsInputConnectedForRender(const NodeInput& input) const
|
||||
{
|
||||
return IsInputConnectedForRender(input.input(), input.element());
|
||||
}
|
||||
|
||||
bool IsInputStatic(const QString& input, int element = -1) const
|
||||
{
|
||||
return !IsInputConnected(input, element) && !IsInputKeyframing(input, element);
|
||||
@@ -435,6 +444,16 @@ public:
|
||||
return GetConnectedOutput(input.input(), input.element());
|
||||
}
|
||||
|
||||
virtual Node *GetConnectedRenderOutput(const QString& input, int element = -1) const
|
||||
{
|
||||
return GetConnectedOutput(input, element);
|
||||
}
|
||||
|
||||
Node *GetConnectedRenderOutput(const NodeInput& input) const
|
||||
{
|
||||
return GetConnectedRenderOutput(input.input(), input.element());
|
||||
}
|
||||
|
||||
bool IsUsingStandardValue(const QString& input, int track, int element = -1) const;
|
||||
|
||||
NodeValue::Type GetInputDataType(const QString& id) const;
|
||||
@@ -796,6 +815,15 @@ public:
|
||||
*/
|
||||
bool InputsFrom(const QString& id, bool recursively) const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Find inputs that `output` outputs to in order to arrive at this node
|
||||
*
|
||||
* Traverse this node's inputs recursively looking for `output`, and return a list of
|
||||
* edges that `output` uses to get to `this` node.
|
||||
*/
|
||||
QVector<NodeInput> FindWaysNodeArrivesHere(const Node *output) const;
|
||||
|
||||
/**
|
||||
* @brief Determines how many paths go from this node out to another node
|
||||
*/
|
||||
@@ -967,6 +995,90 @@ public:
|
||||
folder_ = folder;
|
||||
}
|
||||
|
||||
class ArrayInsertCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
ArrayInsertCommand(Node* node, const QString& input, int index) :
|
||||
node_(node),
|
||||
input_(input),
|
||||
index_(index)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
node_->InputArrayInsert(input_, index_, false);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
node_->InputArrayRemove(input_, index_, false);
|
||||
}
|
||||
|
||||
private:
|
||||
Node* node_;
|
||||
QString input_;
|
||||
int index_;
|
||||
|
||||
};
|
||||
|
||||
class ArrayResizeCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
ArrayResizeCommand(Node* node, const QString& input, int size) :
|
||||
node_(node),
|
||||
input_(input),
|
||||
size_(size)
|
||||
{}
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
old_size_ = node_->InputArraySize(input_);
|
||||
|
||||
if (old_size_ > size_) {
|
||||
// Decreasing in size, disconnect any extraneous edges
|
||||
for (int i=size_; i<old_size_; i++) {
|
||||
|
||||
try {
|
||||
NodeInput input(node_, input_, i);
|
||||
Node *output = node_->input_connections().at(input);
|
||||
|
||||
removed_connections_[input] = output;
|
||||
|
||||
DisconnectEdge(output, input);
|
||||
} catch (std::out_of_range&) {}
|
||||
}
|
||||
}
|
||||
|
||||
node_->ArrayResizeInternal(input_, size_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
for (auto it=removed_connections_.cbegin(); it!=removed_connections_.cend(); it++) {
|
||||
ConnectEdge(it->second, it->first);
|
||||
}
|
||||
removed_connections_.clear();
|
||||
|
||||
node_->ArrayResizeInternal(input_, old_size_);
|
||||
}
|
||||
|
||||
private:
|
||||
Node* node_;
|
||||
QString input_;
|
||||
int size_;
|
||||
int old_size_;
|
||||
|
||||
InputConnections removed_connections_;
|
||||
|
||||
};
|
||||
|
||||
class ArrayRemoveCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
@@ -1203,90 +1315,6 @@ signals:
|
||||
void InputFlagsChanged(const QString &input, const InputFlags &flags);
|
||||
|
||||
private:
|
||||
class ArrayInsertCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
ArrayInsertCommand(Node* node, const QString& input, int index) :
|
||||
node_(node),
|
||||
input_(input),
|
||||
index_(index)
|
||||
{
|
||||
}
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
node_->InputArrayInsert(input_, index_, false);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
node_->InputArrayRemove(input_, index_, false);
|
||||
}
|
||||
|
||||
private:
|
||||
Node* node_;
|
||||
QString input_;
|
||||
int index_;
|
||||
|
||||
};
|
||||
|
||||
class ArrayResizeCommand : public UndoCommand
|
||||
{
|
||||
public:
|
||||
ArrayResizeCommand(Node* node, const QString& input, int size) :
|
||||
node_(node),
|
||||
input_(input),
|
||||
size_(size)
|
||||
{}
|
||||
|
||||
virtual Project* GetRelevantProject() const override;
|
||||
|
||||
protected:
|
||||
virtual void redo() override
|
||||
{
|
||||
old_size_ = node_->InputArraySize(input_);
|
||||
|
||||
if (old_size_ > size_) {
|
||||
// Decreasing in size, disconnect any extraneous edges
|
||||
for (int i=size_; i<old_size_; i++) {
|
||||
|
||||
try {
|
||||
NodeInput input(node_, input_, i);
|
||||
Node *output = node_->input_connections().at(input);
|
||||
|
||||
removed_connections_[input] = output;
|
||||
|
||||
DisconnectEdge(output, input);
|
||||
} catch (std::out_of_range&) {}
|
||||
}
|
||||
}
|
||||
|
||||
node_->ArrayResizeInternal(input_, size_);
|
||||
}
|
||||
|
||||
virtual void undo() override
|
||||
{
|
||||
for (auto it=removed_connections_.cbegin(); it!=removed_connections_.cend(); it++) {
|
||||
ConnectEdge(it->second, it->first);
|
||||
}
|
||||
removed_connections_.clear();
|
||||
|
||||
node_->ArrayResizeInternal(input_, old_size_);
|
||||
}
|
||||
|
||||
private:
|
||||
Node* node_;
|
||||
QString input_;
|
||||
int size_;
|
||||
int old_size_;
|
||||
|
||||
InputConnections removed_connections_;
|
||||
|
||||
};
|
||||
|
||||
struct Input {
|
||||
NodeValue::Type type;
|
||||
InputFlags flags;
|
||||
@@ -1540,7 +1568,7 @@ void Node::FindOutputNodeInternal(const Node* n, QVector<T *>& list)
|
||||
list.append(cast_test);
|
||||
}
|
||||
|
||||
FindOutputNodeInternal<T>(connected);
|
||||
FindOutputNodeInternal<T>(connected, list);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -187,12 +187,12 @@ NodeGlobals NodeTraverser::GenerateGlobals(const VideoParams &vparams, const Aud
|
||||
NodeValueTable NodeTraverser::ProcessInput(const Node* node, const QString& input, const TimeRange& range)
|
||||
{
|
||||
// If input is connected, retrieve value directly
|
||||
if (node->IsInputConnected(input)) {
|
||||
if (node->IsInputConnectedForRender(input)) {
|
||||
|
||||
TimeRange adjusted_range = node->InputTimeAdjustment(input, -1, range);
|
||||
|
||||
// Value will equal something from the connected node, follow it
|
||||
Node *output = node->GetConnectedOutput(input);
|
||||
Node *output = node->GetConnectedRenderOutput(input);
|
||||
NodeValueTable table = GenerateTable(output, adjusted_range, node);
|
||||
return table;
|
||||
|
||||
@@ -242,8 +242,8 @@ void NodeTraverser::ProcessInputElement(NodeValueTableArray &array_tbl, const No
|
||||
NodeValueTable& sub_tbl = array_tbl[element];
|
||||
TimeRange adjusted_range = node->InputTimeAdjustment(input, element, range);
|
||||
|
||||
if (node->IsInputConnected(input, element)) {
|
||||
Node *output = node->GetConnectedOutput(input, element);
|
||||
if (node->IsInputConnectedForRender(input, element)) {
|
||||
Node *output = node->GetConnectedRenderOutput(input, element);
|
||||
sub_tbl = GenerateTable(output, adjusted_range, node);
|
||||
} else {
|
||||
QVariant input_value = node->GetValueAtTime(input, adjusted_range.in(), element);
|
||||
|
||||
@@ -41,6 +41,7 @@ PreviewAutoCacher::PreviewAutoCacher(QObject *parent) :
|
||||
viewer_node_(nullptr),
|
||||
use_custom_range_(false),
|
||||
pause_renders_(false),
|
||||
pause_thumbnails_(false),
|
||||
single_frame_render_(nullptr),
|
||||
display_color_processor_(nullptr),
|
||||
multicam_(nullptr),
|
||||
@@ -583,6 +584,14 @@ void PreviewAutoCacher::SetRendersPaused(bool e)
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::SetThumbnailsPaused(bool e)
|
||||
{
|
||||
pause_thumbnails_ = e;
|
||||
if (!e) {
|
||||
TryRender();
|
||||
}
|
||||
}
|
||||
|
||||
void PreviewAutoCacher::NodeAdded(Node *node)
|
||||
{
|
||||
graph_update_queue_.push_back({QueuedJob::kNodeAdded, node, NodeInput(), nullptr});
|
||||
@@ -663,29 +672,31 @@ void PreviewAutoCacher::TryRender()
|
||||
const int max_tasks = 4;
|
||||
|
||||
// Handle video tasks
|
||||
while (!pending_video_jobs_.empty()) {
|
||||
VideoJob &d = pending_video_jobs_.front();
|
||||
if (!pause_thumbnails_) {
|
||||
while (!pending_video_jobs_.empty()) {
|
||||
VideoJob &d = pending_video_jobs_.front();
|
||||
|
||||
if (Node *copy = copy_map_.value(d.node)) {
|
||||
// Queue next frames
|
||||
rational t;
|
||||
while (running_video_tasks_.size() < max_tasks && d.iterator.GetNext(&t)) {
|
||||
RenderFrame(copy, t, d.cache, false);
|
||||
if (Node *copy = copy_map_.value(d.node)) {
|
||||
// Queue next frames
|
||||
rational t;
|
||||
while (running_video_tasks_.size() < max_tasks && d.iterator.GetNext(&t)) {
|
||||
RenderFrame(copy, t, d.cache, false);
|
||||
|
||||
emit SignalCacheProxyTaskProgress(double(d.iterator.frame_index()) / double(d.iterator.size()));
|
||||
emit SignalCacheProxyTaskProgress(double(d.iterator.frame_index()) / double(d.iterator.size()));
|
||||
|
||||
if (!d.iterator.HasNext()) {
|
||||
emit StopCacheProxyTasks();
|
||||
if (!d.iterator.HasNext()) {
|
||||
emit StopCacheProxyTasks();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qCritical() << "Failed to find node copy for video job";
|
||||
}
|
||||
} else {
|
||||
qCritical() << "Failed to find node copy for video job";
|
||||
}
|
||||
|
||||
if (d.iterator.HasNext()) {
|
||||
break;
|
||||
} else {
|
||||
pending_video_jobs_.pop_front();
|
||||
if (d.iterator.HasNext()) {
|
||||
break;
|
||||
} else {
|
||||
pending_video_jobs_.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,6 +89,7 @@ public:
|
||||
bool IsRenderingCustomRange() const;
|
||||
|
||||
void SetRendersPaused(bool e);
|
||||
void SetThumbnailsPaused(bool e);
|
||||
|
||||
void SetMulticamNode(MultiCamNode *n) { multicam_ = n; }
|
||||
|
||||
@@ -178,6 +179,7 @@ private:
|
||||
TimeRange custom_autocache_range_;
|
||||
|
||||
bool pause_renders_;
|
||||
bool pause_thumbnails_;
|
||||
|
||||
RenderTicketPtr single_frame_render_;
|
||||
QMap<RenderTicketWatcher*, QVector<RenderTicketPtr> > video_immediate_passthroughs_;
|
||||
|
||||
@@ -300,13 +300,11 @@ NodeValueDatabase RenderProcessor::GenerateDatabase(const Node *node, const Time
|
||||
|
||||
if (const MultiCamNode *multicam = dynamic_cast<const MultiCamNode*>(node)) {
|
||||
if (Node::ValueToPtr<MultiCamNode>(ticket_->property("multicam")) == multicam) {
|
||||
int sz = multicam->InputArraySize(multicam->kSourcesInput);
|
||||
NodeValueTableArray arr;
|
||||
int sz = multicam->GetSourceCount();
|
||||
QVector<TexturePtr> multicam_tex(sz);
|
||||
for (int i=0; i<sz; i++) {
|
||||
ProcessInputElement(arr, multicam, multicam->kSourcesInput, i, range);
|
||||
|
||||
NodeValue val = GenerateRowValueElement(multicam, multicam->kSourcesInput, i, &arr.at(i), range);
|
||||
NodeValueTable t = GenerateTable(multicam->GetConnectedRenderOutput(multicam->kSourcesInput, i), range, multicam);
|
||||
NodeValue val = GenerateRowValueElement(multicam, multicam->kSourcesInput, i, &t, range);
|
||||
ResolveJobs(val);
|
||||
|
||||
multicam_tex[i] = val.toTexture();
|
||||
|
||||
@@ -58,10 +58,18 @@ MulticamWidget::MulticamWidget(QWidget *parent) :
|
||||
|
||||
void MulticamWidget::SetMulticamNodeInternal(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip)
|
||||
{
|
||||
ConnectViewerNode(viewer);
|
||||
node_ = n;
|
||||
display_->SetMulticamNode(n);
|
||||
clip_ = clip;
|
||||
if (GetConnectedNode() != viewer) {
|
||||
ConnectViewerNode(viewer);
|
||||
}
|
||||
|
||||
if (node_ != n) {
|
||||
node_ = n;
|
||||
display_->SetMulticamNode(n);
|
||||
}
|
||||
|
||||
if (clip_ != clip) {
|
||||
clip_ = clip;
|
||||
}
|
||||
}
|
||||
|
||||
void MulticamWidget::SetMulticamNode(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip, const rational &time)
|
||||
@@ -145,6 +153,8 @@ void MulticamWidget::Switch(int source, bool split_clip)
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
|
||||
display_->update();
|
||||
|
||||
emit Switched();
|
||||
}
|
||||
|
||||
void MulticamWidget::DisplayClicked(const QPoint &p)
|
||||
|
||||
@@ -42,6 +42,9 @@ protected:
|
||||
virtual void DisconnectNodeEvent(ViewerOutput *n) override;
|
||||
virtual void TimeChangedEvent(const rational &t) override;
|
||||
|
||||
signals:
|
||||
void Switched();
|
||||
|
||||
private:
|
||||
void SetMulticamNodeInternal(ViewerOutput *viewer, MultiCamNode *n, ClipBlock *clip);
|
||||
|
||||
|
||||
@@ -1235,30 +1235,23 @@ void TimelineWidget::ShowContextMenu()
|
||||
reveal_in_project->setData(reinterpret_cast<quintptr>(clip->connected_viewer()));
|
||||
connect(reveal_in_project, &QAction::triggered, this, &TimelineWidget::RevealInProject);
|
||||
|
||||
/*if (Sequence *sequence = dynamic_cast<Sequence*>(clip->connected_viewer())) {
|
||||
Menu *multicam_menu = new Menu(tr("Multi-Cam"), &menu);
|
||||
menu.addMenu(multicam_menu);
|
||||
|
||||
QAction *multicam_enabled = multicam_menu->addAction(tr("Enabled"));
|
||||
if (Sequence *sequence = dynamic_cast<Sequence*>(clip->connected_viewer())) {
|
||||
QAction *multicam_enabled = menu.addAction(tr("Multi-Cam"));
|
||||
multicam_enabled->setCheckable(true);
|
||||
|
||||
auto mcn = sequence->FindOutputNode<MultiCamNode>();
|
||||
multicam_enabled->setChecked(!mcn.empty());
|
||||
MultiCamNode *mcn = nullptr;
|
||||
auto paths = clip->FindWaysNodeArrivesHere(sequence);
|
||||
|
||||
multicam_menu->addSeparator();
|
||||
|
||||
QAction *multicam_update = multicam_menu->addAction(tr("Update"));
|
||||
multicam_update->setEnabled(!mcn.empty());
|
||||
|
||||
if (!mcn.empty()) {
|
||||
auto n = mcn.first();
|
||||
multicam_enabled->setProperty("multicam", Node::PtrToValue(n));
|
||||
multicam_update->setProperty("multicam", Node::PtrToValue(n));
|
||||
for (const NodeInput &i : paths) {
|
||||
if ((mcn = dynamic_cast<MultiCamNode*>(i.node()))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
multicam_enabled->setChecked(mcn);
|
||||
|
||||
connect(multicam_enabled, &QAction::triggered, this, &TimelineWidget::MulticamEnabledTriggered);
|
||||
connect(multicam_update, &QAction::triggered, this, &TimelineWidget::MulticamUpdateTriggered);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1492,16 +1485,57 @@ void TimelineWidget::CacheDiscard()
|
||||
|
||||
void TimelineWidget::MulticamEnabledTriggered(bool e)
|
||||
{
|
||||
if (e) {
|
||||
// Add multicam node
|
||||
} else if (MultiCamNode *m = Node::ValueToPtr<MultiCamNode>(sender()->property("multicam"))) {
|
||||
// Remove multicam node
|
||||
}
|
||||
}
|
||||
MultiUndoCommand *command = new MultiUndoCommand();
|
||||
|
||||
void TimelineWidget::MulticamUpdateTriggered()
|
||||
{
|
||||
// Update multicam node
|
||||
for (Block *b : qAsConst(selected_blocks_)) {
|
||||
if (ClipBlock *c = dynamic_cast<ClipBlock*>(b)) {
|
||||
if (Sequence *s = dynamic_cast<Sequence*>(c->connected_viewer())) {
|
||||
if (e) {
|
||||
|
||||
// Adding multicams
|
||||
// Create multicam node and add it to the graph
|
||||
MultiCamNode *n = new MultiCamNode();
|
||||
n->SetSequenceType(c->GetTrackType());
|
||||
command->add_child(new NodeAddCommand(s->parent(), n));
|
||||
|
||||
|
||||
// For each output the sequence has to this clip, disconnect it and
|
||||
// connect to the multicam instead
|
||||
QVector<NodeInput> inputs = c->FindWaysNodeArrivesHere(s);
|
||||
for (const NodeInput &i : inputs) {
|
||||
command->add_child(new NodeEdgeRemoveCommand(s, i));
|
||||
command->add_child(new NodeEdgeAddCommand(n, i));
|
||||
}
|
||||
|
||||
command->add_child(new NodeEdgeAddCommand(s, NodeInput(n, n->kSequenceInput)));
|
||||
|
||||
// Move sequence node one unit back, and place multicam in sequence's spot
|
||||
QPointF sequence_pos = c->GetNodePositionInContext(s);
|
||||
command->add_child(new NodeSetPositionCommand(s, c, sequence_pos - QPointF(1, 0)));
|
||||
command->add_child(new NodeSetPositionCommand(n, c, sequence_pos));
|
||||
|
||||
} else {
|
||||
|
||||
// Removing multicams
|
||||
// Locate first multicam that specifically ends up at this clip
|
||||
QVector<NodeInput> inputs = c->FindWaysNodeArrivesHere(s);
|
||||
for (const NodeInput &i : inputs) {
|
||||
if (MultiCamNode *mcn = dynamic_cast<MultiCamNode*>(i.node())) {
|
||||
for (auto it=mcn->output_connections().cbegin(); it!=mcn->output_connections().cend(); it++) {
|
||||
command->add_child(new NodeEdgeRemoveCommand(it->first, it->second));
|
||||
command->add_child(new NodeEdgeAddCommand(s, it->second));
|
||||
}
|
||||
|
||||
command->add_child(new NodeRemoveAndDisconnectCommand(mcn));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Core::instance()->undo_stack()->pushIfHasChildren(command);
|
||||
}
|
||||
|
||||
void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost)
|
||||
|
||||
@@ -447,7 +447,6 @@ private slots:
|
||||
void CacheDiscard();
|
||||
|
||||
void MulticamEnabledTriggered(bool e);
|
||||
void MulticamUpdateTriggered();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -427,7 +427,15 @@ void ViewerWidget::StartCapture(TimelineWidget *source, const TimeRange &time, c
|
||||
|
||||
void ViewerWidget::ConnectMulticamWidget(MulticamWidget *p)
|
||||
{
|
||||
if (multicam_panel_) {
|
||||
disconnect(multicam_panel_, &MulticamWidget::Switched, this, &ViewerWidget::DetectMulticamNodeNow);
|
||||
}
|
||||
|
||||
multicam_panel_ = p;
|
||||
|
||||
if (multicam_panel_) {
|
||||
connect(multicam_panel_, &MulticamWidget::Switched, this, &ViewerWidget::DetectMulticamNodeNow);
|
||||
}
|
||||
}
|
||||
|
||||
FramePtr ViewerWidget::DecodeCachedImage(const QString &cache_path, const QUuid &cache_id, const int64_t& time)
|
||||
@@ -607,6 +615,11 @@ void ViewerWidget::SaveFrameAsImage()
|
||||
Core::instance()->OpenExportDialogForViewer(GetConnectedNode(), GetTime(), true);
|
||||
}
|
||||
|
||||
void ViewerWidget::DetectMulticamNodeNow()
|
||||
{
|
||||
DetectMulticamNode(GetTime());
|
||||
}
|
||||
|
||||
void ViewerWidget::CloseAudioProcessor()
|
||||
{
|
||||
audio_processor_.Close();
|
||||
@@ -903,7 +916,7 @@ void ViewerWidget::PlayInternal(int speed, bool in_to_out_only)
|
||||
if (viewer != this) {
|
||||
viewer->PauseInternal();
|
||||
}
|
||||
viewer->auto_cacher_->SetRendersPaused(true);
|
||||
viewer->auto_cacher_->SetThumbnailsPaused(true);
|
||||
}
|
||||
|
||||
RenderManager::instance()->SetAggressiveGarbageCollection(true);
|
||||
@@ -1005,7 +1018,7 @@ void ViewerWidget::PauseInternal()
|
||||
UpdateAudioProcessor();
|
||||
|
||||
foreach (ViewerWidget* viewer, instances_) {
|
||||
viewer->auto_cacher_->SetRendersPaused(false);
|
||||
viewer->auto_cacher_->SetThumbnailsPaused(false);
|
||||
}
|
||||
|
||||
UpdateTextureFromNode();
|
||||
@@ -1796,7 +1809,7 @@ void ViewerWidget::SetZoomFromMenu(QAction *action)
|
||||
void ViewerWidget::ViewerInvalidatedVideoRange(const TimeRange &range)
|
||||
{
|
||||
// If our current frame is within this range, we need to update
|
||||
if (GetTime() >= range.in() && (GetTime() < range.out() || range.in() == range.out())) {
|
||||
if (!IsPlaying() && GetTime() >= range.in() && (GetTime() < range.out() || range.in() == range.out())) {
|
||||
QMetaObject::invokeMethod(this, &ViewerWidget::UpdateTextureFromNode, Qt::QueuedConnection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
|
||||
if (!IsPlaying()) {
|
||||
// If is playing, this will happen by the next frame automatically
|
||||
DetectMulticamNode(GetTime());
|
||||
DetectMulticamNodeNow();
|
||||
UpdateTextureFromNode();
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
|
||||
if (!IsPlaying()) {
|
||||
// If is playing, this will happen by the next frame automatically
|
||||
DetectMulticamNode(GetTime());
|
||||
DetectMulticamNodeNow();
|
||||
UpdateTextureFromNode();
|
||||
}
|
||||
}
|
||||
@@ -421,6 +421,8 @@ private slots:
|
||||
|
||||
void SaveFrameAsImage();
|
||||
|
||||
void DetectMulticamNodeNow();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user