implement entire project in nodes

Project items are now represented directly in nodes opening up more versatility and possibilities. This is the first iteration of this and will be buggy. Need to test thoroughly.
This commit is contained in:
itsmattkc
2021-02-15 21:31:57 +11:00
parent 155470bec1
commit d7c5ac4b44
174 changed files with 3515 additions and 4658 deletions
+1 -1
View File
@@ -22,9 +22,9 @@ add_subdirectory(colorlabelmenu)
add_subdirectory(colorwheel)
add_subdirectory(columnedgridlayout)
add_subdirectory(curvewidget)
add_subdirectory(filefield)
add_subdirectory(flowlayout)
add_subdirectory(focusablelineedit)
add_subdirectory(footagecombobox)
add_subdirectory(handmovableview)
add_subdirectory(keyframeview)
add_subdirectory(manageddisplay)
+1 -1
View File
@@ -185,7 +185,7 @@ void CurveWidget::TimeTargetChangedEvent(Node *target)
view_->SetTimeTarget(target);
}
void CurveWidget::ConnectedNodeChanged(ViewerOutput *n)
void CurveWidget::ConnectedNodeChanged(Sequence *n)
{
SetTimeTarget(n);
}
+1 -1
View File
@@ -67,7 +67,7 @@ protected:
virtual void TimeTargetChangedEvent(Node* target) override;
virtual void ConnectedNodeChanged(ViewerOutput* n) override;
virtual void ConnectedNodeChanged(Sequence* n) override;
private:
void SetKeyframeButtonEnabled(bool enable);
@@ -16,7 +16,7 @@
set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/footagecombobox/footagecombobox.h
widget/footagecombobox/footagecombobox.cpp
widget/filefield/filefield.cpp
widget/filefield/filefield.h
PARENT_SCOPE
)
+69
View File
@@ -0,0 +1,69 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 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 "filefield.h"
#include <QFileDialog>
#include <QFileInfo>
#include <QHBoxLayout>
#include "ui/icons/icons.h"
namespace olive {
FileField::FileField(QWidget* parent) :
QWidget(parent)
{
QHBoxLayout* layout = new QHBoxLayout(this);
layout->setSpacing(0);
layout->setMargin(0);
line_edit_ = new QLineEdit();
connect(line_edit_, &QLineEdit::textChanged, this, &FileField::LineEditChanged);
layout->addWidget(line_edit_);
browse_btn_ = new QPushButton();
browse_btn_->setIcon(icon::Open);
connect(browse_btn_, &QPushButton::clicked, this, &FileField::BrowseBtnClicked);
layout->addWidget(browse_btn_);
}
void FileField::BrowseBtnClicked()
{
QString s = QFileDialog::getOpenFileName(this, tr("Open File"));
if (!s.isEmpty()) {
line_edit_->setText(s);
}
}
void FileField::LineEditChanged(const QString& text)
{
if (QFileInfo::exists(text)) {
line_edit_->setStyleSheet(QString());
} else {
line_edit_->setStyleSheet(QStringLiteral("QLineEdit {color: red;}"));
}
emit FilenameChanged(text);
}
}
@@ -18,54 +18,45 @@
***/
#ifndef FOOTAGECOMBOBOX_H
#define FOOTAGECOMBOBOX_H
#ifndef FILEFIELD_H
#define FILEFIELD_H
#include <QComboBox>
#include <QMenu>
#include "project/item/footage/footage.h"
#include "project/project.h"
#include <QLineEdit>
#include <QPushButton>
namespace olive {
class FootageComboBox : public QComboBox
class FileField : public QWidget
{
Q_OBJECT
public:
FootageComboBox(QWidget* parent = nullptr);
FileField(QWidget* parent = nullptr);
virtual void showPopup() override;
void SetRoot(const Folder *p);
void SetOnlyShowReadyFootage(bool e);
Stream* SelectedFootage() const
QString GetFilename() const
{
return footage_;
return line_edit_->text();
}
public slots:
void SetFootage(Stream* f);
void SetFilename(const QString& s)
{
line_edit_->setText(s);
}
signals:
void FootageChanged(Stream* f);
void FilenameChanged(const QString& filename);
private:
void TraverseFolder(const Folder *f, QMenu* m) const;
QLineEdit* line_edit_;
void UpdateText();
QPushButton* browse_btn_;
static QString FootageToString(Stream* f);
private slots:
void BrowseBtnClicked();
const Folder* root_;
void LineEditChanged(const QString &text);
Stream* footage_;
bool only_show_ready_footage_;
};
}
#endif // FOOTAGECOMBOBOX_H
#endif // FILEFIELD_H
@@ -1,127 +0,0 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 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 "footagecombobox.h"
#include <QAction>
#include <QDebug>
#include "ui/icons/icons.h"
#include "widget/menu/menu.h"
namespace olive {
FootageComboBox::FootageComboBox(QWidget *parent) :
QComboBox(parent),
root_(nullptr),
footage_(nullptr),
only_show_ready_footage_(true)
{
}
void FootageComboBox::showPopup()
{
if (root_ == nullptr || root_->item_child_count() == 0) {
return;
}
Menu menu;
menu.setMinimumWidth(width());
TraverseFolder(root_, &menu);
QAction* selected = menu.exec(parentWidget()->mapToGlobal(pos()));
if (selected != nullptr) {
SetFootage(Node::ValueToPtr<Stream>(selected->data()));
emit FootageChanged(footage_);
}
}
void FootageComboBox::SetRoot(const Folder *p)
{
root_ = p;
clear();
}
void FootageComboBox::SetOnlyShowReadyFootage(bool e)
{
only_show_ready_footage_ = e;
}
void FootageComboBox::SetFootage(Stream *f)
{
// Remove existing single item used to show the footage name
footage_ = f;
UpdateText();
}
void FootageComboBox::TraverseFolder(const Folder *f, QMenu *m) const
{
foreach (Item* child, f->children()) {
if (child->CanHaveChildren()) {
Menu* sub = new Menu(child->name(), m);
m->addMenu(sub);
TraverseFolder(static_cast<Folder*>(child), sub);
} else if (child->type() == Item::kFootage) {
Footage* footage = static_cast<Footage*>(child);
if (footage->IsValid() || !only_show_ready_footage_) {
Menu* stream_menu = new Menu(footage->name(), m);
m->addMenu(stream_menu);
foreach (Stream* stream, footage->streams()) {
QAction* stream_action = stream_menu->addAction(FootageToString(stream));
stream_action->setData(Node::PtrToValue(stream));
stream_action->setIcon(stream->icon());
}
}
}
}
}
void FootageComboBox::UpdateText()
{
// Use combobox functions to show the footage name
clear();
if (footage_) {
// Use combobox functions to show the footage name
addItem(FootageToString(footage_));
}
}
QString FootageComboBox::FootageToString(Stream *f)
{
return f->description();
}
}
+2 -2
View File
@@ -34,7 +34,7 @@ KeyframeSetTypeCommand::KeyframeSetTypeCommand(NodeKeyframe* key, NodeKeyframe::
Project *KeyframeSetTypeCommand::GetRelevantProject() const
{
return key_->parent()->parent()->project();
return key_->parent()->project();
}
void KeyframeSetTypeCommand::redo()
@@ -65,7 +65,7 @@ KeyframeSetBezierControlPoint::KeyframeSetBezierControlPoint(NodeKeyframe* key,
Project *KeyframeSetBezierControlPoint::GetRelevantProject() const
{
return key_->parent()->parent()->project();
return key_->parent()->project();
}
void KeyframeSetBezierControlPoint::redo()
+1
View File
@@ -21,6 +21,7 @@
#include "nodecombobox.h"
#include <QAction>
#include <QEvent>
#include <QDebug>
#include "node/factory.h"
+1 -1
View File
@@ -220,7 +220,7 @@ void NodeParamView::TimeChangedEvent(const int64_t &timestamp)
UpdateItemTime(timestamp);
}
void NodeParamView::ConnectedNodeChanged(ViewerOutput *n)
void NodeParamView::ConnectedNodeChanged(Sequence *n)
{
// Set viewer as a time target
keyframe_view_->SetTimeTarget(n);
+1 -1
View File
@@ -96,7 +96,7 @@ protected:
virtual void TimebaseChangedEvent(const rational&) override;
virtual void TimeChangedEvent(const int64_t &) override;
virtual void ConnectedNodeChanged(ViewerOutput* n) override;
virtual void ConnectedNodeChanged(Sequence* n) override;
private:
void UpdateItemTime(const int64_t &timestamp);
@@ -34,7 +34,7 @@ NodeParamSetKeyframingCommand::NodeParamSetKeyframingCommand(const NodeInput &in
Project *NodeParamSetKeyframingCommand::GetRelevantProject() const
{
return input_.node()->parent()->project();
return input_.node()->project();
}
void NodeParamSetKeyframingCommand::redo()
@@ -64,7 +64,7 @@ NodeParamSetKeyframeValueCommand::NodeParamSetKeyframeValueCommand(NodeKeyframe*
Project *NodeParamSetKeyframeValueCommand::GetRelevantProject() const
{
return key_->parent()->parent()->project();
return key_->parent()->project();
}
void NodeParamSetKeyframeValueCommand::redo()
@@ -87,7 +87,7 @@ NodeParamInsertKeyframeCommand::NodeParamInsertKeyframeCommand(Node* node, NodeK
Project *NodeParamInsertKeyframeCommand::GetRelevantProject() const
{
return input_->parent()->project();
return input_->project();
}
void NodeParamInsertKeyframeCommand::redo()
@@ -108,7 +108,7 @@ NodeParamRemoveKeyframeCommand::NodeParamRemoveKeyframeCommand(NodeKeyframe* key
Project *NodeParamRemoveKeyframeCommand::GetRelevantProject() const
{
return input_->parent()->project();
return input_->project();
}
void NodeParamRemoveKeyframeCommand::redo()
@@ -138,7 +138,7 @@ NodeParamSetKeyframeTimeCommand::NodeParamSetKeyframeTimeCommand(NodeKeyframe* k
Project *NodeParamSetKeyframeTimeCommand::GetRelevantProject() const
{
return key_->parent()->parent()->project();
return key_->parent()->project();
}
void NodeParamSetKeyframeTimeCommand::redo()
@@ -167,7 +167,7 @@ NodeParamSetStandardValueCommand::NodeParamSetStandardValueCommand(const NodeKey
Project *NodeParamSetStandardValueCommand::GetRelevantProject() const
{
return ref_.input().node()->parent()->project();
return ref_.input().node()->project();
}
void NodeParamSetStandardValueCommand::redo()
@@ -182,7 +182,7 @@ void NodeParamSetStandardValueCommand::undo()
Project *NodeParamArrayInsertCommand::GetRelevantProject() const
{
return input_.node()->parent()->project();
return input_.node()->project();
}
}
@@ -34,7 +34,7 @@
#include "project/item/sequence/sequence.h"
#include "undo/undostack.h"
#include "widget/colorbutton/colorbutton.h"
#include "widget/footagecombobox/footagecombobox.h"
#include "widget/filefield/filefield.h"
#include "widget/slider/floatslider.h"
#include "widget/slider/integerslider.h"
@@ -77,9 +77,12 @@ void NodeParamViewWidgetBridge::CreateWidgets()
case NodeValue::kMatrix:
case NodeValue::kRational:
case NodeValue::kSamples:
case NodeValue::kFootageJob:
case NodeValue::kShaderJob:
case NodeValue::kSampleJob:
case NodeValue::kGenerateJob:
case NodeValue::kVideoStreamProperties:
case NodeValue::kAudioStreamProperties:
break;
case NodeValue::kInt:
{
@@ -120,12 +123,16 @@ void NodeParamViewWidgetBridge::CreateWidgets()
break;
}
case NodeValue::kFile:
// FIXME: File selector
{
FileField* file_field = new FileField();
widgets_.append(file_field);
connect(file_field, &FileField::FilenameChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeValue::kColor:
{
// NOTE: Very convoluted way to get back to the project's color manager
ColorButton* color_button = new ColorButton(input_.node()->parent()->project()->color_manager());
ColorButton* color_button = new ColorButton(input_.node()->project()->color_manager());
widgets_.append(color_button);
connect(color_button, &ColorButton::ColorChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
@@ -151,17 +158,6 @@ void NodeParamViewWidgetBridge::CreateWidgets()
connect(font_combobox, &QFontComboBox::currentFontChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
break;
}
case NodeValue::kFootage:
{
FootageComboBox* footage_combobox = new FootageComboBox();
footage_combobox->SetRoot(input_.node()->parent()->project()->root());
connect(footage_combobox, &FootageComboBox::FootageChanged, this, &NodeParamViewWidgetBridge::WidgetCallback);
widgets_.append(footage_combobox);
break;
}
}
// Check all properties
@@ -252,9 +248,12 @@ void NodeParamViewWidgetBridge::WidgetCallback()
case NodeValue::kMatrix:
case NodeValue::kSamples:
case NodeValue::kRational:
case NodeValue::kFootageJob:
case NodeValue::kShaderJob:
case NodeValue::kSampleJob:
case NodeValue::kGenerateJob:
case NodeValue::kVideoStreamProperties:
case NodeValue::kAudioStreamProperties:
break;
case NodeValue::kInt:
{
@@ -307,8 +306,10 @@ void NodeParamViewWidgetBridge::WidgetCallback()
break;
}
case NodeValue::kFile:
// FIXME: File selector
{
SetInputValue(static_cast<FileField*>(sender())->GetFilename(), 0);
break;
}
case NodeValue::kColor:
{
// Sender is a ColorButton
@@ -350,12 +351,6 @@ void NodeParamViewWidgetBridge::WidgetCallback()
SetInputValue(static_cast<QFontComboBox*>(sender())->currentFont().family(), 0);
break;
}
case NodeValue::kFootage:
{
// Widget is a FootageComboBox
SetInputValue(Node::PtrToValue(static_cast<FootageComboBox*>(sender())->SelectedFootage()), 0);
break;
}
case NodeValue::kCombo:
{
// Widget is a QComboBox
@@ -403,9 +398,12 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
case NodeValue::kMatrix:
case NodeValue::kRational:
case NodeValue::kSamples:
case NodeValue::kFootageJob:
case NodeValue::kShaderJob:
case NodeValue::kSampleJob:
case NodeValue::kGenerateJob:
case NodeValue::kVideoStreamProperties:
case NodeValue::kAudioStreamProperties:
break;
case NodeValue::kInt:
{
@@ -452,8 +450,13 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
break;
}
case NodeValue::kFile:
// FIXME: File selector
{
FileField* ff = static_cast<FileField*>(widgets_.first());
ff->blockSignals(true);
ff->SetFilename(input_.GetValueAtTime(node_time).toString());
ff->blockSignals(false);
break;
}
case NodeValue::kColor:
{
ManagedColor mc = input_.GetValueAtTime(node_time).value<Color>();
@@ -494,9 +497,6 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues()
cb->blockSignals(false);
break;
}
case NodeValue::kFootage:
static_cast<FootageComboBox*>(widgets_.first())->SetFootage(Node::ValueToPtr<Stream>(input_.GetValueAtTime(node_time)));
break;
}
}
@@ -620,7 +620,7 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString& input, const QStr
}
// ComboBox strings changing
if (data_type & NodeValue::kCombo) {
if (data_type == NodeValue::kCombo) {
QComboBox* cb = static_cast<QComboBox*>(widgets_.first());
int old_index = cb->currentIndex();
@@ -22,21 +22,14 @@
namespace olive {
QVariant NodeTableTraverser::ProcessVideoFootage(VideoStream *video_stream, const rational &input_time)
QVariant NodeTableTraverser::ProcessVideoFootage(const Footage::StreamReference &video_stream, const rational &input_time)
{
return QVariant::fromValue(VideoParams(video_stream->width(),
video_stream->height(),
video_stream->timebase(),
video_stream->format(),
video_stream->channel_count(),
video_stream->pixel_aspect_ratio()));
return QVariant::fromValue(video_stream.video_params());
}
QVariant NodeTableTraverser::ProcessAudioFootage(AudioStream *audio_stream, const TimeRange &input_time)
QVariant NodeTableTraverser::ProcessAudioFootage(const Footage::StreamReference &audio_stream, const TimeRange &input_time)
{
return QVariant::fromValue(AudioParams(audio_stream->sample_rate(),
audio_stream->channel_layout(),
AudioParams::kInternalFormat));
return QVariant::fromValue(audio_stream.audio_params());
}
}
@@ -31,9 +31,9 @@ public:
NodeTableTraverser() = default;
protected:
virtual QVariant ProcessVideoFootage(VideoStream* video_stream, const rational &input_time);
virtual QVariant ProcessVideoFootage(const Footage::StreamReference&video_stream, const rational &input_time);
virtual QVariant ProcessAudioFootage(AudioStream* audio_stream, const TimeRange &input_time);
virtual QVariant ProcessAudioFootage(const Footage::StreamReference& audio_stream, const TimeRange &input_time);
};
+22
View File
@@ -1,5 +1,27 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 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 "nodetreeview.h"
#include <QEvent>
namespace olive {
NodeTreeView::NodeTreeView(QWidget *parent) :
+20
View File
@@ -1,3 +1,23 @@
/***
Olive - Non-Linear Video Editor
Copyright (C) 2020 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 NODETREEVIEW_H
#define NODETREEVIEW_H
+4
View File
@@ -367,6 +367,10 @@ void NodeView::mousePressEvent(QMouseEvent *event)
if (item) {
create_edge_ = new NodeViewEdge();
create_edge_src_ = item;
create_edge_->SetCurved(scene_.GetEdgesAreCurved());
create_edge_->SetFlowDirection(scene_.GetFlowDirection());
scene_.addItem(create_edge_);
return;
}
+3 -1
View File
@@ -154,7 +154,9 @@ void NodeViewEdge::SetFlowDirection(NodeViewCommon::FlowDirection dir)
{
flow_dir_ = dir;
Adjust();
if (from_item_ && to_item_) {
Adjust();
}
}
void NodeViewEdge::SetCurved(bool e)
+33 -3
View File
@@ -61,7 +61,7 @@ void NodeEdgeAddCommand::undo()
Project *NodeEdgeAddCommand::GetRelevantProject() const
{
return output_.node()->parent()->project();
return output_.node()->project();
}
NodeEdgeRemoveCommand::NodeEdgeRemoveCommand(const NodeOutput &output, const NodeInput &input) :
@@ -82,13 +82,17 @@ void NodeEdgeRemoveCommand::undo()
Project *NodeEdgeRemoveCommand::GetRelevantProject() const
{
return output_.node()->parent()->project();
return output_.node()->project();
}
NodeAddCommand::NodeAddCommand(NodeGraph *graph, Node *node) :
graph_(graph),
node_(node)
{
if (memory_manager_.thread() != node->thread()) {
memory_manager_.moveToThread(node_->thread());
}
// Ensures that when this command is destroyed, if redo() is never called again, the node will be destroyed too
node_->setParent(&memory_manager_);
}
@@ -105,7 +109,7 @@ void NodeAddCommand::undo()
Project *NodeAddCommand::GetRelevantProject() const
{
return graph_->project();
return dynamic_cast<Project*>(graph_);
}
NodeCopyInputsCommand::NodeCopyInputsCommand(Node *src, Node *dest, bool include_connections) :
@@ -139,4 +143,30 @@ void NodeRemoveAndDisconnectCommand::prep()
}
}
void NodeRenameCommand::AddNode(Node *node, const QString &new_name)
{
nodes_.append(node);
new_labels_.append(new_name);
old_labels_.append(node->GetLabel());
}
void NodeRenameCommand::redo()
{
for (int i=0; i<nodes_.size(); i++) {
nodes_.at(i)->SetLabel(new_labels_.at(i));
}
}
void NodeRenameCommand::undo()
{
for (int i=0; i<nodes_.size(); i++) {
nodes_.at(i)->SetLabel(old_labels_.at(i));
}
}
Project *NodeRenameCommand::GetRelevantProject() const
{
return nodes_.isEmpty() ? nullptr : nodes_.first()->project();
}
}
+27 -9
View File
@@ -23,6 +23,7 @@
#include "node/graph.h"
#include "node/node.h"
#include "project/project.h"
#include "undo/undocommand.h"
namespace olive {
@@ -104,11 +105,7 @@ public:
virtual Project* GetRelevantProject() const override
{
if (graph_) {
return graph_->project();
} else {
return node_->parent()->project();
}
return dynamic_cast<Project*>(graph_);
}
virtual void redo() override
@@ -165,7 +162,7 @@ public:
if (command_) {
return static_cast<const NodeRemoveAndDisconnectCommand*>(command_->child(0))->GetRelevantProject();
} else {
return node_->parent()->project();
return node_->project();
}
}
@@ -236,7 +233,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return a_->parent()->project();
return a_->project();
}
virtual void redo() override
@@ -276,7 +273,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return node_->parent()->project();
return node_->project();
}
virtual void redo() override
@@ -320,7 +317,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return nodes_.first()->parent()->project();
return nodes_.first()->project();
}
private:
@@ -328,6 +325,27 @@ private:
};
class NodeRenameCommand : public UndoCommand
{
public:
NodeRenameCommand() = default;
void AddNode(Node* node, const QString& new_name);
virtual void redo() override;
virtual void undo() override;
virtual Project * GetRelevantProject() const override;
private:
QVector<Node*> nodes_;
QStringList new_labels_;
QStringList old_labels_;
};
}
#endif // NODEVIEWUNDO_H
+88 -159
View File
@@ -30,7 +30,6 @@
#include "common/define.h"
#include "core.h"
#include "dialog/footageproperties/footageproperties.h"
#include "dialog/sequence/sequence.h"
#include "projectexplorerundo.h"
#include "task/precache/precachetask.h"
@@ -149,7 +148,7 @@ void ProjectExplorer::BrowseToFolder(const QModelIndex &index)
// Set navbar text to folder's name
if (index.isValid()) {
Folder* f = static_cast<Folder*>(sort_model_.mapToSource(index).internalPointer());
nav_bar_->set_text(f->name());
nav_bar_->set_text(f->GetLabel());
} else {
// Or set it to an empty string if the index is valid (which means we're browsing to the root directory)
nav_bar_->set_text(QString());
@@ -202,8 +201,7 @@ void ProjectExplorer::ItemDoubleClickedSlot(const QModelIndex &index)
Item* i = static_cast<Item*>(sort_model_.mapToSource(index).internalPointer());
// If the item is a folder, browse to it
if (i->CanHaveChildren()
&& (view_type() == ProjectToolbar::ListView || view_type() == ProjectToolbar::IconView)) {
if (dynamic_cast<Folder*>(i) && (view_type() == ProjectToolbar::ListView || view_type() == ProjectToolbar::IconView)) {
BrowseToFolder(index);
@@ -273,18 +271,16 @@ void ProjectExplorer::ShowContextMenu()
if (context_menu_items_.size() == 1) {
Item* context_menu_item = context_menu_items_.first();
switch (context_menu_item->type()) {
case Item::kFolder:
{
if (dynamic_cast<Folder*>(context_menu_item)) {
QAction* open_in_new_tab = menu.addAction(tr("Open in New Tab"));
connect(open_in_new_tab, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewTab);
QAction* open_in_new_window = menu.addAction(tr("Open in New Window"));
connect(open_in_new_window, &QAction::triggered, this, &ProjectExplorer::OpenContextMenuItemInNewWindow);
break;
}
case Item::kFootage:
{
} else if (dynamic_cast<Footage*>(context_menu_item)) {
QString reveal_text;
#if defined(Q_OS_WINDOWS)
@@ -297,10 +293,7 @@ void ProjectExplorer::ShowContextMenu()
QAction* reveal_action = menu.addAction(reveal_text);
connect(reveal_action, &QAction::triggered, this, &ProjectExplorer::RevealSelectedFootage);
break;
}
case Item::kSequence:
break;
}
menu.addSeparator();
@@ -311,15 +304,18 @@ void ProjectExplorer::ShowContextMenu()
bool all_items_are_footage_or_sequence = true;
foreach (Item* i, context_menu_items_) {
if (i->type() == Item::kFootage && !static_cast<Footage*>(i)->HasEnabledStreamsOfType(Stream::kVideo)) {
Footage* footage_cast_test = dynamic_cast<Footage*>(i);
Sequence* sequence_cast_test = dynamic_cast<Sequence*>(i);
if (footage_cast_test && !footage_cast_test->HasEnabledStreamsOfType(Stream::kVideo)) {
all_items_have_video_streams = false;
}
if (i->type() != Item::kFootage) {
if (!footage_cast_test) {
all_items_are_footage = false;
}
if (i->type() != Item::kFootage && i->type() != Item::kSequence) {
if (!footage_cast_test && !sequence_cast_test) {
all_items_are_footage_or_sequence = false;
}
}
@@ -328,14 +324,14 @@ void ProjectExplorer::ShowContextMenu()
Menu* proxy_menu = new Menu(tr("Pre-Cache"), &menu);
menu.addMenu(proxy_menu);
QVector<Item*> sequences = project()->get_items_of_type(Item::kSequence);
QVector<Sequence*> sequences = project()->root()->ListOutputsOfType<Sequence>();
if (sequences.isEmpty()) {
QAction* a = proxy_menu->addAction(tr("No sequences exist in project"));
a->setEnabled(false);
} else {
foreach (Item* i, sequences) {
QAction* a = proxy_menu->addAction(tr("For \"%1\"").arg(i->name()));
foreach (Sequence* i, sequences) {
QAction* a = proxy_menu->addAction(tr("For \"%1\"").arg(i->GetLabel()));
a->setData(Node::PtrToValue(i));
}
@@ -360,26 +356,20 @@ void ProjectExplorer::ShowItemPropertiesDialog()
{
Item* sel = context_menu_items_.first();
switch (sel->type()) {
case Item::kFootage:
{
// FIXME: Support for multiple items
FootagePropertiesDialog fpd(this, static_cast<Footage*>(sel));
fpd.exec();
break;
}
case Item::kFolder:
{
// FIXME: Rename dialog probably
break;
}
case Item::kSequence:
{
// FIXME: Support for multiple items
// FIXME: Support for multiple items
if (dynamic_cast<Footage*>(sel)) {
Core::instance()->LabelNodes({static_cast<Footage*>(sel)});
} else if (dynamic_cast<Folder*>(sel)) {
Core::instance()->LabelNodes({static_cast<Folder*>(sel)});
} else if (dynamic_cast<Sequence*>(sel)) {
SequenceDialog sd(static_cast<Sequence*>(sel), SequenceDialog::kExisting, this);
sd.exec();
break;
}
}
}
@@ -410,35 +400,30 @@ void ProjectExplorer::RevealSelectedFootage()
void ProjectExplorer::OpenContextMenuItemInNewTab()
{
Core::instance()->main_window()->FolderOpen(project(), context_menu_items_.first(), false);
Core::instance()->main_window()->FolderOpen(project(), static_cast<Folder*>(context_menu_items_.first()), false);
}
void ProjectExplorer::OpenContextMenuItemInNewWindow()
{
Core::instance()->main_window()->FolderOpen(project(), context_menu_items_.first(), true);
Core::instance()->main_window()->FolderOpen(project(), static_cast<Folder*>(context_menu_items_.first()), true);
}
void ProjectExplorer::ContextMenuStartProxy(QAction *a)
{
QVector<VideoStream*> video_streams;
Sequence* sequence = Node::ValueToPtr<Sequence>(a->data());
// To get here, the `context_menu_items_` must be all kFootage
foreach (Item* i, context_menu_items_) {
Footage* f = static_cast<Footage*>(i);
VideoStream* s = static_cast<VideoStream*>(f->get_first_enabled_stream_of_type(Stream::kVideo));
if (s) {
video_streams.append(s);
QVector<int> video_streams = f->GetStreamIndexesOfType(Stream::kVideo);
foreach (int stream, video_streams) {
// Start a background task for proxying
PreCacheTask* proxy_task = new PreCacheTask(f, stream, sequence);
TaskManager::instance()->AddTask(proxy_task);
}
}
Sequence* sequence = Node::ValueToPtr<Sequence>(a->data());
// Start a background task for proxying
foreach (VideoStream* video_stream, video_streams) {
PreCacheTask* proxy_task = new PreCacheTask(video_stream, sequence);
TaskManager::instance()->AddTask(proxy_task);
}
}
Project *ProjectExplorer::project() const
@@ -456,7 +441,7 @@ QModelIndex ProjectExplorer::get_root_index() const
return tree_view_->rootIndex();
}
void ProjectExplorer::set_root(Item *item)
void ProjectExplorer::set_root(Folder *item)
{
QModelIndex index = sort_model_.mapFromSource(model_.CreateIndexFromItem(item));
@@ -505,10 +490,8 @@ Folder *ProjectExplorer::GetSelectedFolder() const
Item* sel_item = selected_items.at(i);
// If this item is not a folder, presumably it's parent is
if (!sel_item->CanHaveChildren()) {
if (!dynamic_cast<Folder*>(sel_item)) {
sel_item = sel_item->item_parent();
Q_ASSERT(sel_item->CanHaveChildren());
}
if (folder == nullptr) {
@@ -545,28 +528,6 @@ void ProjectExplorer::DeselectAll()
CurrentView()->selectionModel()->clearSelection();
}
QVector<MediaInput *> ProjectExplorer::GetMediaNodesUsingFootage(Footage *item)
{
QVector<MediaInput *> list;
// Get all sequences.
QVector<Item*> sequences = model_.project()->get_items_of_type(Item::kSequence);
// Footage can contain multiple streams, all of which need to be dealt with
foreach (Item* s, sequences) {
const QVector<Node*>& nodes = static_cast<Sequence*>(s)->nodes();
foreach (Node* n, nodes) {
MediaInput* media_node = dynamic_cast<MediaInput*>(n);
if (media_node && media_node->stream()->footage() == item) {
list.append(media_node);
}
}
}
return list;
}
void ProjectExplorer::DeleteSelected()
{
QVector<Item*> selected = SelectedItems();
@@ -577,110 +538,78 @@ void ProjectExplorer::DeleteSelected()
MultiUndoCommand* command = new MultiUndoCommand();
bool dont_confirm_footage_in_use = false;
foreach (Item* item, selected) {
// Verify whether this item is in use anywhere
switch (item->type()) {
case Item::kSequence:
{
// If this is a sequence, check if it's open and close it if necessary
Sequence* s = static_cast<Sequence*>(item);
Footage* footage_cast_test = dynamic_cast<Footage*>(item);
Sequence* sequence_cast_test = dynamic_cast<Sequence*>(item);
if (Core::instance()->main_window()->IsSequenceOpen(s)) {
Core::instance()->main_window()->CloseSequence(s);
bool cleared_to_delete = true;
if (sequence_cast_test) {
if (Core::instance()->main_window()->IsSequenceOpen(sequence_cast_test)) {
Core::instance()->main_window()->CloseSequence(sequence_cast_test);
}
break;
}
case Item::kFootage:
{
// If this is footage, check if it's used anywhere in any sequence
Footage* footage = static_cast<Footage*>(item);
} else if (footage_cast_test) {
if (!footage_cast_test->output_connections().empty() && !dont_confirm_footage_in_use) {
// Footage outputs to other nodes, warn the user
QMessageBox msgbox(this);
msgbox.setWindowTitle(tr("Confirm Footage Deletion"));
msgbox.setIcon(QMessageBox::Warning);
QVector<MediaInput*> footage_nodes = GetMediaNodesUsingFootage(footage);
QStringList connected_nodes;
foreach (const Node::OutputConnection& c, footage_cast_test->output_connections()) {
Node* connected = c.second.node();
if (!footage_nodes.isEmpty()) {
// Footage is in use, show messagebox asking what to do about it
QList<Sequence*> used_in_sequences;
// Compile list of sequences to assist the user in making this decision
foreach (MediaInput* i, footage_nodes) {
Sequence* media_parent = static_cast<Sequence*>(i->parent());
if (!used_in_sequences.contains(media_parent)) {
used_in_sequences.append(media_parent);
if (connected->GetLabel().isEmpty()) {
connected_nodes.append(connected->Name());
} else {
connected_nodes.append(QStringLiteral("%1 (%2)").arg(connected->GetLabel(), connected->Name()));
}
}
QString sequence_list_str;
foreach (Sequence* s, used_in_sequences) {
sequence_list_str.append(QStringLiteral("%1\n").arg(s->name()));
}
msgbox.setText(tr("The footage \"%1\" is currently connected to the following nodes:\n\n"
"%2\n\n"
"Are you sure you wish to delete this footage?")
.arg(footage_cast_test->filename(), connected_nodes.join('\n')));
QMessageBox msgbox(this);
msgbox.setWindowTitle(tr("Confirm Footage Deletion"));
msgbox.setText(tr("The footage \"%1\" is currently used in the following sequence(s):\n\n"
"%2\nWhat would you like to do with these clips?")
.arg(footage->filename(), sequence_list_str));
msgbox.setIcon(QMessageBox::Warning);
// Set up buttons
QPushButton* offline_btn = msgbox.addButton(tr("Offline Footage"), QMessageBox::YesRole);
QPushButton* delete_clip_btn = msgbox.addButton(tr("Delete Clips"), QMessageBox::NoRole);
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::YesToAll);
msgbox.addButton(QMessageBox::No);
msgbox.addButton(QMessageBox::Cancel);
// Run messagebox
msgbox.exec();
int r = msgbox.exec();
if (msgbox.clickedButton() == offline_btn || msgbox.clickedButton() == delete_clip_btn) {
// For safety, even if we're deleting clips, we'll offline the footage nodes too
command->add_child(new OfflineFootageCommand(footage_nodes));
}
if (msgbox.clickedButton() == delete_clip_btn) {
// Delete any blocks that use this footage
QVector<Block*> blocks_to_remove;
foreach (Sequence* s, used_in_sequences) {
foreach (Track* track, s->viewer_output()->GetTracks()) {
foreach (Block* b, track->Blocks()) {
QVector<Node*> deps = b->GetDependencies();
foreach (MediaInput* i, footage_nodes) {
if (deps.contains(i)) {
blocks_to_remove.append(b);
break;
}
}
}
}
}
TimelineWidget::ReplaceBlocksWithGaps(blocks_to_remove, true, command);
} else if (msgbox.clickedButton() != offline_btn) {
// Must have cancelled
switch (r) {
case QMessageBox::Cancel:
// Stop this entire function
delete command;
return;
case QMessageBox::No:
cleared_to_delete = false;
break;
case QMessageBox::YesToAll:
dont_confirm_footage_in_use = true;
break;
}
}
// Close footage if currently open in footage panel
FootageViewerPanel* footage_panel = PanelManager::instance()->GetPanelsOfType<FootageViewerPanel>().first();
if (footage_panel->GetSelectedFootage().contains(footage)) {
footage_panel->SetFootage(nullptr);
if (cleared_to_delete) {
// Close footage if currently open in footage panel
FootageViewerPanel* footage_panel = PanelManager::instance()->GetPanelsOfType<FootageViewerPanel>().first();
if (footage_panel->GetSelectedFootage().contains(footage_cast_test)) {
footage_panel->SetFootage(nullptr);
}
}
break;
}
case Item::kFolder:
// Do nothing
break;
}
command->add_child(new ProjectViewModel::RemoveItemCommand(&model_, item));
if (cleared_to_delete) {
command->add_child(new NodeRemoveAndDisconnectCommand(reinterpret_cast<Node*>(item)));
}
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
+1 -7
View File
@@ -26,7 +26,6 @@
#include <QTimer>
#include <QTreeView>
#include "node/input/media/media.h"
#include "project/project.h"
#include "project/projectviewmodel.h"
#include "widget/projectexplorer/projectexplorericonview.h"
@@ -58,7 +57,7 @@ public:
QModelIndex get_root_index() const;
void set_root(Item* item);
void set_root(Folder *item);
QVector<Item *> SelectedItems() const;
@@ -103,11 +102,6 @@ signals:
void DoubleClickedItem(Item* item);
private:
/**
* @brief Check if an item is in use anywhere and return any relevant input nodes
*/
QVector<MediaInput*> GetMediaNodesUsingFootage(Footage* item);
/**
* @brief Get all the blocks that solely rely on an input node
*
@@ -21,51 +21,10 @@
#ifndef PROJECTEXPLORERUNDO_H
#define PROJECTEXPLORERUNDO_H
#include "node/input/media/media.h"
#include "undo/undocommand.h"
namespace olive {
/**
* @brief An undo command for offlining footage when it is deleted from the project explorer
*/
class OfflineFootageCommand : public UndoCommand {
public:
OfflineFootageCommand(const QVector<MediaInput*>& media)
{
foreach (MediaInput* i, media) {
stream_data_.insert(i, i->stream());
}
project_ = media.first()->parent()->project();
}
virtual Project* GetRelevantProject() const override
{
return project_;
}
virtual void redo() override
{
for (auto it=stream_data_.cbegin(); it!=stream_data_.cend(); it++) {
it.key()->SetStream(nullptr);
}
}
virtual void undo() override
{
for (auto it=stream_data_.cbegin(); it!=stream_data_.cend(); it++) {
it.key()->SetStream(it.value());
}
}
private:
QMap<MediaInput*, Stream*> stream_data_;
Project* project_;
};
}
#endif // PROJECTEXPLORERUNDO_H
+15 -9
View File
@@ -68,12 +68,12 @@ const int64_t &TimeBasedWidget::GetTimestamp() const
return ruler_->GetTime();
}
ViewerOutput *TimeBasedWidget::GetConnectedNode() const
Sequence *TimeBasedWidget::GetConnectedNode() const
{
return viewer_node_;
}
void TimeBasedWidget::ConnectViewerNode(ViewerOutput *node)
void TimeBasedWidget::ConnectViewerNode(Sequence *node)
{
if (viewer_node_ == node) {
return;
@@ -244,12 +244,12 @@ void TimeBasedWidget::resizeEvent(QResizeEvent *event)
TimelinePoints *TimeBasedWidget::ConnectTimelinePoints()
{
return static_cast<Sequence*>(viewer_node_->parent());
return viewer_node_->timeline_points();
}
Project *TimeBasedWidget::GetTimelinePointsProject()
{
return static_cast<Sequence*>(viewer_node_->parent())->project();
return viewer_node_->project();
}
TimelinePoints *TimeBasedWidget::GetConnectedTimelinePoints() const
@@ -323,7 +323,10 @@ void TimeBasedWidget::ZoomOut()
void TimeBasedWidget::GoToPrevCut()
{
if (!GetConnectedNode()) {
// Cuts are only possible in sequences
Sequence* sequence = dynamic_cast<Sequence*>(viewer_node_);
if (!sequence) {
return;
}
@@ -333,7 +336,7 @@ void TimeBasedWidget::GoToPrevCut()
int64_t closest_cut = 0;
foreach (Track* track, viewer_node_->GetTracks()) {
foreach (Track* track, sequence->GetTracks()) {
int64_t this_track_closest_cut = 0;
foreach (Block* block, track->Blocks()) {
@@ -354,13 +357,16 @@ void TimeBasedWidget::GoToPrevCut()
void TimeBasedWidget::GoToNextCut()
{
if (!GetConnectedNode()) {
// Cuts are only possible in sequences
Sequence* sequence = dynamic_cast<Sequence*>(viewer_node_);
if (!sequence) {
return;
}
int64_t closest_cut = INT64_MAX;
foreach (Track* track, GetConnectedNode()->GetTracks()) {
foreach (Track* track, sequence->GetTracks()) {
int64_t this_track_closest_cut = Timecode::time_to_timestamp(track->track_length(), timebase());
if (this_track_closest_cut <= GetTimestamp()) {
@@ -573,7 +579,7 @@ void TimeBasedWidget::SetMarker()
}
if (ok) {
Core::instance()->undo_stack()->push(new MarkerAddCommand(static_cast<Sequence*>(GetConnectedNode()->parent())->project(),
Core::instance()->undo_stack()->push(new MarkerAddCommand(GetConnectedNode()->project(),
points_->markers(), TimeRange(GetTime(), GetTime()), marker_name));
}
}
+6 -6
View File
@@ -46,9 +46,9 @@ public:
void ZoomOut();
ViewerOutput* GetConnectedNode() const;
Sequence* GetConnectedNode() const;
void ConnectViewerNode(ViewerOutput *node);
void ConnectViewerNode(Sequence *node);
void SetScaleAndCenterOnPlayhead(const double& scale);
@@ -105,11 +105,11 @@ protected:
virtual void ScaleChangedEvent(const double &) override;
virtual void ConnectedNodeChanged(ViewerOutput*){}
virtual void ConnectedNodeChanged(Sequence*){}
virtual void ConnectNodeInternal(ViewerOutput*){}
virtual void ConnectNodeInternal(Sequence*){}
virtual void DisconnectNodeInternal(ViewerOutput*){}
virtual void DisconnectNodeInternal(Sequence*){}
void SetAutoMaxScrollBar(bool e);
@@ -189,7 +189,7 @@ private:
bool UserIsDraggingPlayhead() const;
ViewerOutput* viewer_node_;
Sequence* viewer_node_;
TimeRuler* ruler_;
+39 -39
View File
@@ -66,7 +66,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return block_->parent()->project();
return block_->project();
}
virtual void redo() override
@@ -97,7 +97,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return block_->parent()->project();
return block_->project();
}
virtual void redo() override
@@ -147,7 +147,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
/**
@@ -371,7 +371,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return block_->parent()->project();
return block_->project();
}
virtual void redo() override
@@ -401,7 +401,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
virtual void redo() override
@@ -434,7 +434,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
virtual void redo() override
@@ -463,7 +463,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return block_->parent()->project();
return block_->project();
}
virtual void redo() override
@@ -500,7 +500,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return block_->parent()->project();
return block_->project();
}
/**
@@ -652,7 +652,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return blocks_.first()->parent()->project();
return blocks_.first()->project();
}
virtual void redo() override
@@ -749,7 +749,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
virtual void redo() override
@@ -815,7 +815,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
/**
@@ -1024,7 +1024,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return static_cast<ViewerOutput*>(list_->parent())->parent()->project();
return list_->parent()->project();
}
virtual void redo() override
@@ -1049,9 +1049,9 @@ public:
// We can optimize here by simply shifting the whole cache forward instead of re-caching
// everything following this time
if (list_->type() == Track::kVideo) {
static_cast<ViewerOutput*>(list_->parent())->ShiftVideoCache(out_, in_);
list_->parent()->ShiftVideoCache(out_, in_);
} else if (list_->type() == Track::kAudio) {
static_cast<ViewerOutput*>(list_->parent())->ShiftAudioCache(out_, in_);
list_->parent()->ShiftAudioCache(out_, in_);
}
foreach (Track* track, working_tracks_) {
@@ -1076,9 +1076,9 @@ public:
// We can optimize here by simply shifting the whole cache forward instead of re-caching
// everything following this time
if (list_->type() == Track::kVideo) {
static_cast<ViewerOutput*>(list_->parent())->ShiftVideoCache(in_, out_);
list_->parent()->ShiftVideoCache(in_, out_);
} else if (list_->type() == Track::kAudio) {
static_cast<ViewerOutput*>(list_->parent())->ShiftAudioCache(in_, out_);
list_->parent()->ShiftAudioCache(in_, out_);
}
foreach (Track* track, working_tracks_) {
@@ -1114,7 +1114,7 @@ private:
class TimelineRippleRemoveAreaCommand : public MultiUndoCommand {
public:
TimelineRippleRemoveAreaCommand(ViewerOutput* timeline, rational in, rational out) :
TimelineRippleRemoveAreaCommand(Sequence* timeline, rational in, rational out) :
timeline_(timeline)
{
for (int i=0; i<Track::kCount; i++) {
@@ -1126,11 +1126,11 @@ public:
virtual Project* GetRelevantProject() const override
{
return timeline_->parent()->project();
return timeline_->project();
}
private:
ViewerOutput* timeline_;
Sequence* timeline_;
};
@@ -1155,7 +1155,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return static_cast<ViewerOutput*>(track_list_->parent())->parent()->project();
return track_list_->parent()->project();
}
virtual void redo() override
@@ -1325,9 +1325,9 @@ private:
if (all_tracks_unlocked_) {
// We rippled all the tracks, so we can shift the whole cache
if (track_list_->type() == Track::kVideo) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftVideoCache(pre_latest_out, post_latest_out);
track_list_->parent()->ShiftVideoCache(pre_latest_out, post_latest_out);
} else if (track_list_->type() == Track::kAudio) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftAudioCache(pre_latest_out, post_latest_out);
track_list_->parent()->ShiftAudioCache(pre_latest_out, post_latest_out);
}
}
}
@@ -1383,7 +1383,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return timeline_->GetParentGraph()->project();
return timeline_->parent()->project();
}
virtual void redo() override
@@ -1419,9 +1419,9 @@ public:
QString relevant_input;
if (timeline_->type() == Track::kVideo) {
relevant_input = ViewerOutput::kTextureInput;
relevant_input = Sequence::kTextureInput;
} else {
relevant_input = ViewerOutput::kSamplesInput;
relevant_input = Sequence::kSamplesInput;
}
if (!timeline_->parent()->IsInputConnected(relevant_input)) {
@@ -1505,7 +1505,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return timeline_->GetParentGraph()->project();
return timeline_->parent()->project();
}
virtual void redo() override
@@ -1604,7 +1604,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
virtual void redo() override
@@ -1637,7 +1637,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return block_->parent()->project();
return block_->project();
}
virtual void redo() override
@@ -1784,7 +1784,7 @@ private:
class TimelineRippleDeleteGapsAtRegionsCommand : public UndoCommand {
public:
TimelineRippleDeleteGapsAtRegionsCommand(ViewerOutput* vo, const TimeRangeList& regions) :
TimelineRippleDeleteGapsAtRegionsCommand(Sequence* vo, const TimeRangeList& regions) :
timeline_(vo),
regions_(regions)
{
@@ -1797,7 +1797,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return timeline_->parent()->project();
return timeline_->project();
}
virtual void redo() override
@@ -1851,7 +1851,7 @@ public:
}
private:
ViewerOutput* timeline_;
Sequence* timeline_;
TimeRangeList regions_;
QVector<UndoCommand*> commands_;
@@ -1941,7 +1941,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return block_->parent()->project();
return block_->project();
}
virtual void redo() override
@@ -1986,7 +1986,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
virtual void redo() override
@@ -2153,7 +2153,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return static_cast<ViewerOutput*>(track_list_->parent())->parent()->project();
return track_list_->parent()->project();
}
virtual void redo() override
@@ -2166,9 +2166,9 @@ public:
if (all_tracks_unlocked_) {
// Optimize by shifting over since we have a constant amount of time being inserted
if (track_list_->type() == Track::kVideo) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftVideoCache(point_, point_ + length_);
track_list_->parent()->ShiftVideoCache(point_, point_ + length_);
} else if (track_list_->type() == Track::kAudio) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftAudioCache(point_, point_ + length_);
track_list_->parent()->ShiftAudioCache(point_, point_ + length_);
}
}
@@ -2205,9 +2205,9 @@ public:
if (all_tracks_unlocked_) {
// Optimize by shifting over since we have a constant amount of time being inserted
if (track_list_->type() == Track::kVideo) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftVideoCache(point_ + length_, point_);
track_list_->parent()->ShiftVideoCache(point_ + length_, point_);
} else if (track_list_->type() == Track::kAudio) {
static_cast<ViewerOutput*>(track_list_->parent())->ShiftAudioCache(point_ + length_, point_);
track_list_->parent()->ShiftAudioCache(point_ + length_, point_);
}
}
@@ -2326,7 +2326,7 @@ public:
virtual Project* GetRelevantProject() const override
{
return track_->parent()->project();
return track_->project();
}
virtual void redo() override
+21 -19
View File
@@ -218,7 +218,7 @@ void TimelineWidget::ScaleChangedEvent(const double &scale)
}
}
void TimelineWidget::ConnectNodeInternal(ViewerOutput *n)
void TimelineWidget::ConnectNodeInternal(Sequence *n)
{
connect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack);
connect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack);
@@ -229,23 +229,24 @@ void TimelineWidget::ConnectNodeInternal(ViewerOutput *n)
SetTimebase(n->video_params().time_base());
for (int i=0;i<views_.size();i++) {
Sequence* s = static_cast<Sequence*>(n);
Track::Type track_type = static_cast<Track::Type>(i);
TimelineView* view = views_.at(i)->view();
TrackList* track_list = n->track_list(track_type);
TrackList* track_list = s->track_list(track_type);
TrackView* track_view = views_.at(i)->track_view();
track_view->ConnectTrackList(track_list);
view->ConnectTrackList(track_list);
// Defer to the track to make all the block UI items necessary
const QVector<Track*> tracks = n->track_list(track_type)->GetTracks();
const QVector<Track*> tracks = s->track_list(track_type)->GetTracks();
foreach (Track* track, tracks) {
AddTrack(track);
}
}
}
void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n)
void TimelineWidget::DisconnectNodeInternal(Sequence *n)
{
disconnect(n, &ViewerOutput::TrackAdded, this, &TimelineWidget::AddTrack);
disconnect(n, &ViewerOutput::TrackRemoved, this, &TimelineWidget::RemoveTrack);
@@ -253,7 +254,8 @@ void TimelineWidget::DisconnectNodeInternal(ViewerOutput *n)
DeselectAll();
foreach (Track* track, n->GetTracks()) {
Sequence* s = static_cast<Sequence*>(n);
foreach (Track* track, s->GetTracks()) {
RemoveTrack(track);
}
@@ -383,7 +385,7 @@ void TimelineWidget::SplitAtPlayhead()
bool some_blocks_are_selected = false;
// Get all blocks at the playhead
foreach (Track* track, GetConnectedNode()->GetTracks()) {
foreach (Track* track, sequence()->GetTracks()) {
Block* b = track->BlockContainingTime(playhead_time);
if (b && b->type() == Block::kClip) {
@@ -488,7 +490,7 @@ void TimelineWidget::DeleteSelected(bool ripple)
range_list.insert(TimeRange(b->in(), b->out()));
}
command->add_child(new TimelineRippleDeleteGapsAtRegionsCommand(GetConnectedNode(), range_list));
command->add_child(new TimelineRippleDeleteGapsAtRegionsCommand(sequence(), range_list));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
@@ -501,7 +503,7 @@ void TimelineWidget::IncreaseTrackHeight()
}
// Increase the height of each track by one "unit"
foreach (Track* t, GetConnectedNode()->GetTracks()) {
foreach (Track* t, sequence()->GetTracks()) {
t->SetTrackHeight(t->GetTrackHeight() + Track::kTrackHeightInterval);
}
}
@@ -513,7 +515,7 @@ void TimelineWidget::DecreaseTrackHeight()
}
// Decrease the height of each track by one "unit"
foreach (Track* t, GetConnectedNode()->GetTracks()) {
foreach (Track* t, sequence()->GetTracks()) {
t->SetTrackHeight(qMax(t->GetTrackHeight() - Track::kTrackHeightInterval, Track::kTrackHeightMinimum));
}
}
@@ -614,7 +616,7 @@ void TimelineWidget::Paste(bool insert)
foreach (const BlockPasteData& bpd, paste_data) {
qDebug() << "Placing" << bpd.block;
command->add_child(new TrackPlaceBlockCommand(GetConnectedNode()->track_list(bpd.track_type),
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(bpd.track_type),
bpd.track_index,
bpd.block,
paste_start + bpd.in));
@@ -635,12 +637,12 @@ void TimelineWidget::DeleteInToOut(bool ripple)
if (ripple) {
command->add_child(new TimelineRippleRemoveAreaCommand(GetConnectedNode(),
command->add_child(new TimelineRippleRemoveAreaCommand(sequence(),
GetConnectedTimelinePoints()->workarea()->in(),
GetConnectedTimelinePoints()->workarea()->out()));
} else {
QVector<Track*> unlocked_tracks = GetConnectedNode()->GetUnlockedTracks();
QVector<Track*> unlocked_tracks = sequence()->GetUnlockedTracks();
foreach (Track* track, unlocked_tracks) {
GapBlock* gap = new GapBlock();
@@ -650,7 +652,7 @@ void TimelineWidget::DeleteInToOut(bool ripple)
command->add_child(new NodeAddCommand(static_cast<NodeGraph*>(track->parent()),
gap));
command->add_child(new TrackPlaceBlockCommand(GetConnectedNode()->track_list(track->type()),
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track->type()),
track->Index(),
gap,
GetConnectedTimelinePoints()->workarea()->in()));
@@ -698,7 +700,7 @@ void TimelineWidget::SetColorLabel(int index)
void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational &insert_length, MultiUndoCommand *command)
{
for (int i=0;i<Track::kCount;i++) {
command->add_child(new TrackListInsertGaps(GetConnectedNode()->track_list(static_cast<Track::Type>(i)),
command->add_child(new TrackListInsertGaps(sequence()->track_list(static_cast<Track::Type>(i)),
earliest_point,
insert_length));
}
@@ -706,7 +708,7 @@ void TimelineWidget::InsertGapsAt(const rational &earliest_point, const rational
Track *TimelineWidget::GetTrackFromReference(const Track::Reference &ref) const
{
return GetConnectedNode()->track_list(ref.type())->GetTrackAt(ref.index());
return sequence()->track_list(ref.type())->GetTrackAt(ref.index());
}
int TimelineWidget::GetTrackY(const Track::Reference &ref)
@@ -970,7 +972,7 @@ void TimelineWidget::ShowSequenceDialog()
return;
}
SequenceDialog sd(static_cast<Sequence*>(GetConnectedNode()->parent()), SequenceDialog::kExisting, this);
SequenceDialog sd(sequence(), SequenceDialog::kExisting, this);
sd.exec();
}
@@ -1127,7 +1129,7 @@ QVector<Timeline::EditToInfo> TimelineWidget::GetEditToInfo(const rational& play
Timeline::MovementMode mode)
{
// Get list of unlocked tracks
QVector<Track*> tracks = GetConnectedNode()->GetUnlockedTracks();
QVector<Track*> tracks = sequence()->GetUnlockedTracks();
// Create list to cache nearest times and the blocks at this point
QVector<Timeline::EditToInfo> info_list(tracks.size());
@@ -1206,7 +1208,7 @@ void TimelineWidget::RippleTo(Timeline::MovementMode mode)
rational in_ripple = qMin(closest_point_to_playhead, playhead_time);
rational out_ripple = qMax(closest_point_to_playhead, playhead_time);
TimelineRippleRemoveAreaCommand* c = new TimelineRippleRemoveAreaCommand(GetConnectedNode(),
TimelineRippleRemoveAreaCommand* c = new TimelineRippleRemoveAreaCommand(sequence(),
in_ripple,
out_ripple);
@@ -1290,7 +1292,7 @@ QVector<Block *> TimelineWidget::GetBlocksInGlobalRect(const QPoint &p1, const Q
mapped_rect = mapped_rect.normalized();
// Get tracks
TrackList* track_list = GetConnectedNode()->track_list(static_cast<Track::Type>(i));
TrackList* track_list = sequence()->track_list(static_cast<Track::Type>(i));
for (int j=0; j<track_list->GetTrackCount(); j++) {
int track_top = view->GetTrackY(j);
+10 -2
View File
@@ -91,6 +91,14 @@ public:
void SetColorLabel(int index);
/**
* @brief Timelines should always be connected to sequences
*/
Sequence* sequence() const
{
return static_cast<Sequence*>(GetConnectedNode());
}
const QVector<Block*>& GetSelectedBlocks() const
{
return selected_blocks_;
@@ -237,8 +245,8 @@ protected:
virtual void TimeChangedEvent(const int64_t &) override;
virtual void ScaleChangedEvent(const double &) override;
virtual void ConnectNodeInternal(ViewerOutput* n) override;
virtual void DisconnectNodeInternal(ViewerOutput* n) override;
virtual void ConnectNodeInternal(Sequence* n) override;
virtual void DisconnectNodeInternal(Sequence* n) override;
virtual void CopyNodesToClipboardInternal(QXmlStreamWriter *writer, void* userdata) override;
virtual void PasteNodesFromClipboardInternal(QXmlStreamReader *reader, XMLNodeData &xml_node_data, void* userdata) override;
+1 -1
View File
@@ -102,7 +102,7 @@ void AddTool::MouseRelease(TimelineViewMouseEvent *event)
command->add_child(new NodeAddCommand(graph,
clip));
command->add_child(new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track.type()),
command->add_child(new TrackPlaceBlockCommand(static_cast<Sequence*>(parent()->GetConnectedNode())->track_list(track.type()),
track.index(),
clip,
ghost_->GetAdjustedIn()));
+32 -36
View File
@@ -32,7 +32,6 @@
#include "node/audio/volume/volume.h"
#include "node/distort/transform/transformdistortnode.h"
#include "node/generator/matrix/matrix.h"
#include "node/input/media/media.h"
#include "node/math/math/math.h"
#include "project/item/sequence/sequence.h"
#include "widget/nodeview/nodeviewundo.h"
@@ -97,7 +96,7 @@ void ImportTool::DragEnter(TimelineViewMouseEvent *event)
Item* item = reinterpret_cast<Item*>(item_ptr);
// Check if Item is Footage
if (item->type() == Item::kFootage) {
if (dynamic_cast<Footage*>(item)) {
Footage* f = static_cast<Footage*>(item);
@@ -225,8 +224,10 @@ void ImportTool::FootageToGhosts(rational ghost_start, const QVector<DraggedFoot
quint64 enabled_streams = footage.streams();
// Loop through all streams in footage
foreach (Stream* stream, footage.footage()->streams()) {
Track::Type track_type = TrackTypeFromStreamType(stream->type());
foreach (const QString& output, footage.footage()->outputs()) {
Footage::StreamReference ref = footage.footage()->GetReferenceFromOutput(output);
Track::Type track_type = TrackTypeFromStreamType(ref.type());
quint64 cached_enabled_streams = enabled_streams;
enabled_streams >>= 1;
@@ -239,8 +240,10 @@ void ImportTool::FootageToGhosts(rational ghost_start, const QVector<DraggedFoot
TimelineViewGhostItem* ghost = new TimelineViewGhostItem();
if (stream->type() == Stream::kVideo
&& static_cast<VideoStream*>(stream)->video_type() == VideoStream::kVideoTypeStill) {
Stream stream = ref.GetStream();
if (ref.type() == Stream::kVideo
&& stream.video_type() == Stream::kVideoTypeStill) {
// Stream is essentially length-less - we may use the default still image length in config,
// or we may use another stream's length depending on the circumstance
contains_image_stream = true;
@@ -251,7 +254,7 @@ void ImportTool::FootageToGhosts(rational ghost_start, const QVector<DraggedFoot
footage_duration = qMax(footage_duration, footage.footage()->workarea()->range().length());
ghost->SetMediaIn(footage.footage()->workarea()->in());
} else {
int64_t stream_duration = Timecode::rescale_timestamp_ceil(stream->duration(), stream->timebase(), dest_tb);
int64_t stream_duration = Timecode::rescale_timestamp_ceil(stream.duration(), stream.timebase(), dest_tb);
footage_duration = qMax(footage_duration, Timecode::timestamp_to_time(stream_duration, dest_tb));
}
}
@@ -261,7 +264,7 @@ void ImportTool::FootageToGhosts(rational ghost_start, const QVector<DraggedFoot
// Increment track count for this track type
track_offsets[track_type]++;
ghost->SetData(TimelineViewGhostItem::kAttachedFootage, Node::PtrToValue(stream));
ghost->SetData(TimelineViewGhostItem::kAttachedFootage, QVariant::fromValue(TimelineViewGhostItem::AttachedFootage({footage.footage(), output})));
ghost->SetMode(Timeline::kMove);
footage_ghosts.append(ghost);
@@ -310,12 +313,12 @@ void ImportTool::DropGhosts(bool insert)
MultiUndoCommand* command = new MultiUndoCommand();
NodeGraph* dst_graph = nullptr;
ViewerOutput* viewer_node = nullptr;
Sequence* open_sequence = nullptr;
Sequence* sequence = nullptr;
bool open_sequence = false;
if (parent()->GetConnectedNode()) {
viewer_node = parent()->GetConnectedNode();
dst_graph = static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent());
sequence = parent()->GetConnectedNode();
dst_graph = parent()->GetConnectedNode()->parent();
} else {
// There's no active timeline here, ask the user what to do
@@ -382,19 +385,18 @@ void ImportTool::DropGhosts(bool insert)
}
if (sequence_is_valid) {
new_sequence->add_default_nodes();
dst_graph = Core::instance()->GetActiveProject();
command->add_child(new ProjectViewModel::AddItemCommand(Core::instance()->GetActiveProjectModel(),
Core::instance()->GetSelectedFolderInActiveProject(),
new_sequence));
command->add_child(new NodeAddCommand(dst_graph, new_sequence));
command->add_child(new NodeEdgeAddCommand(Core::instance()->GetSelectedFolderInActiveProject(), NodeInput(new_sequence, Item::kParentInput)));
new_sequence->add_default_nodes(command);
FootageToGhosts(0, dragged_footage_, new_sequence->video_params().time_base(), 0);
dst_graph = new_sequence;
viewer_node = new_sequence->viewer_output();
sequence = new_sequence;
// Set this as the sequence to open
open_sequence = new_sequence;
open_sequence = true;
} else {
// If the sequence is valid, ownership is passed to AddItemCommand.
// Otherwise, we're responsible for deleting it.
@@ -416,38 +418,32 @@ void ImportTool::DropGhosts(bool insert)
for (int i=0;i<parent()->GetGhostItems().size();i++) {
TimelineViewGhostItem* ghost = parent()->GetGhostItems().at(i);
Stream* footage_stream = Node::ValueToPtr<Stream>(ghost->GetData(TimelineViewGhostItem::kAttachedFootage));
TimelineViewGhostItem::AttachedFootage footage_stream = ghost->GetData(TimelineViewGhostItem::kAttachedFootage).value<TimelineViewGhostItem::AttachedFootage>();
NodeOutput corresponding_output(footage_stream.footage, footage_stream.output);
ClipBlock* clip = new ClipBlock();
clip->set_media_in(ghost->GetMediaIn());
clip->set_length_and_media_out(ghost->GetLength());
clip->SetLabel(footage_stream->footage()->name());
clip->SetLabel(footage_stream.footage->GetLabel());
command->add_child(new NodeAddCommand(dst_graph, clip));
switch (footage_stream->type()) {
switch (footage_stream.footage->GetTypeFromOutput(footage_stream.output)) {
case Stream::kVideo:
{
MediaInput* video_input = new MediaInput();
video_input->SetStream(footage_stream);
command->add_child(new NodeAddCommand(dst_graph, video_input));
TransformDistortNode* transform = new TransformDistortNode();
command->add_child(new NodeAddCommand(dst_graph, transform));
command->add_child(new NodeEdgeAddCommand(video_input, NodeInput(transform, TransformDistortNode::kTextureInput)));
command->add_child(new NodeEdgeAddCommand(corresponding_output, NodeInput(transform, TransformDistortNode::kTextureInput)));
command->add_child(new NodeEdgeAddCommand(transform, NodeInput(clip, ClipBlock::kBufferIn)));
break;
}
case Stream::kAudio:
{
MediaInput* audio_input = new MediaInput();
audio_input->SetStream(footage_stream);
command->add_child(new NodeAddCommand(dst_graph, audio_input));
VolumeNode* volume_node = new VolumeNode();
command->add_child(new NodeAddCommand(dst_graph, volume_node));
command->add_child(new NodeEdgeAddCommand(audio_input, NodeInput(volume_node, VolumeNode::kSamplesInput)));
command->add_child(new NodeEdgeAddCommand(corresponding_output, NodeInput(volume_node, VolumeNode::kSamplesInput)));
command->add_child(new NodeEdgeAddCommand(volume_node, NodeInput(clip, ClipBlock::kBufferIn)));
break;
}
@@ -455,7 +451,7 @@ void ImportTool::DropGhosts(bool insert)
break;
}
command->add_child(new TrackPlaceBlockCommand(viewer_node->track_list(ghost->GetAdjustedTrack().type()),
command->add_child(new TrackPlaceBlockCommand(sequence->track_list(ghost->GetAdjustedTrack().type()),
ghost->GetAdjustedTrack().index(),
clip,
ghost->GetAdjustedIn()));
@@ -464,9 +460,9 @@ void ImportTool::DropGhosts(bool insert)
// Link any clips so far that share the same Footage with this one
for (int j=0;j<i;j++) {
Stream* footage_compare = Node::ValueToPtr<Stream>(parent()->GetGhostItems().at(j)->GetData(TimelineViewGhostItem::kAttachedFootage));
TimelineViewGhostItem::AttachedFootage footage_compare = parent()->GetGhostItems().at(j)->GetData(TimelineViewGhostItem::kAttachedFootage).value<TimelineViewGhostItem::AttachedFootage>();
if (footage_compare->footage() == footage_stream->footage()) {
if (footage_compare.footage == footage_stream.footage) {
Block::Link(block_items.at(j), clip);
}
}
@@ -474,7 +470,7 @@ void ImportTool::DropGhosts(bool insert)
}
if (open_sequence) {
command->add_child(new OpenSequenceCommand(open_sequence));
command->add_child(new OpenSequenceCommand(sequence));
}
Core::instance()->undo_stack()->pushIfHasChildren(command);
+1 -1
View File
@@ -644,7 +644,7 @@ void PointerTool::FinishDrag(TimelineViewMouseEvent *event)
}
const Track::Reference& track_ref = p.ghost->GetAdjustedTrack();
command->add_child(new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track_ref.type()),
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track_ref.type()),
track_ref.index(),
block,
p.ghost->GetAdjustedIn()));
+2 -2
View File
@@ -58,7 +58,7 @@ void RippleTool::InitiateDrag(Block *clicked_item,
}
// For each track that does NOT have a ghost, we need to make one for Gaps
foreach (Track* track, parent()->GetConnectedNode()->GetTracks()) {
foreach (Track* track, sequence()->GetTracks()) {
if (track->IsLocked()) {
continue;
}
@@ -144,7 +144,7 @@ void RippleTool::FinishDrag(TimelineViewMouseEvent *event)
for (int i=0;i<info_list.size();i++) {
if (!info_list.at(i).isEmpty()) {
command->add_child(new TrackListRippleToolCommand(parent()->GetConnectedNode()->track_list(static_cast<Track::Type>(i)),
command->add_child(new TrackListRippleToolCommand(sequence()->track_list(static_cast<Track::Type>(i)),
info_list.at(i),
movement,
drag_movement_mode()));
+5
View File
@@ -39,6 +39,11 @@ TimelineWidget *TimelineTool::parent()
return parent_;
}
Sequence *TimelineTool::sequence()
{
return parent_->sequence();
}
Timeline::MovementMode TimelineTool::FlipTrimMode(const Timeline::MovementMode &trim_mode)
{
if (trim_mode == Timeline::kTrimIn) {
+2
View File
@@ -53,6 +53,8 @@ public:
TimelineWidget* parent();
Sequence* sequence();
static Timeline::MovementMode FlipTrimMode(const Timeline::MovementMode& trim_mode);
static rational SnapMovementToTimebase(const rational& start, rational movement, const rational& timebase);
@@ -126,7 +126,7 @@ void TransitionTool::MouseRelease(TimelineViewMouseEvent *event)
command->add_child(new NodeAddCommand(static_cast<NodeGraph*>(parent()->GetConnectedNode()->parent()),
transition));
command->add_child(new TrackPlaceBlockCommand(parent()->GetConnectedNode()->track_list(track.type()),
command->add_child(new TrackPlaceBlockCommand(sequence()->track_list(track.type()),
track.index(),
transition,
ghost_->GetAdjustedIn()));
@@ -31,7 +31,6 @@
#include "common/flipmodifiers.h"
#include "common/qtutils.h"
#include "common/timecodefunctions.h"
#include "node/input/media/media.h"
#include "project/item/footage/footage.h"
#include "ui/colorcoding.h"
@@ -23,6 +23,7 @@
#include <QVariant>
#include "node/output/track/track.h"
#include "project/item/footage/footage.h"
#include "timeline/timelinecommon.h"
@@ -42,6 +43,11 @@ public:
kTrimShouldBeIgnored
};
struct AttachedFootage {
Footage* footage;
QString output;
};
TimelineViewGhostItem() :
track_adj_(0),
mode_(Timeline::kNone),
@@ -267,4 +273,6 @@ private:
}
Q_DECLARE_METATYPE(olive::TimelineViewGhostItem::AttachedFootage)
#endif // TIMELINEVIEWGHOSTITEM_H
+40 -49
View File
@@ -32,12 +32,6 @@ FootageViewerWidget::FootageViewerWidget(QWidget *parent) :
ViewerWidget(parent),
footage_(nullptr)
{
video_node_ = new MediaInput();
video_node_->setParent(&sequence_);
audio_node_ = new MediaInput();
audio_node_->setParent(&sequence_);
connect(display_widget(), &ViewerDisplayWidget::DragStarted, this, &FootageViewerWidget::StartFootageDrag);
controls_->SetAudioVideoDragButtonsVisible(true);
@@ -57,56 +51,25 @@ void FootageViewerWidget::SetFootage(Footage *footage)
ConnectViewerNode(nullptr);
video_node_->SetStream(nullptr);
audio_node_->SetStream(nullptr);
Node::DisconnectEdge(video_node_, NodeInput(sequence_.viewer_output(), ViewerOutput::kTextureInput));
Node::DisconnectEdge(audio_node_, NodeInput(sequence_.viewer_output(), ViewerOutput::kSamplesInput));
Node::DisconnectEdge(sequence_.GetConnectedOutput(ViewerOutput::kTextureInput), NodeInput(&sequence_, ViewerOutput::kTextureInput));
Node::DisconnectEdge(sequence_.GetConnectedOutput(ViewerOutput::kSamplesInput), NodeInput(&sequence_, ViewerOutput::kSamplesInput));
}
footage_ = footage;
if (footage_) {
// Update sequence media name
sequence_.viewer_output()->SetLabel(footage_->name());
sequence_.SetLabel(footage_->GetLabel());
// Reset parameters and then attempt to set from footage
sequence_.set_default_parameters();
sequence_.set_parameters_from_footage({footage_});
// Use first of each stream
VideoStream* video_stream = nullptr;
AudioStream* audio_stream = nullptr;
// Try to connect video stream
TryConnectingType(footage, Stream::kVideo);
TryConnectingType(footage, Stream::kAudio);
foreach (Stream* s, footage_->streams()) {
if (!s->enabled()) {
continue;
}
if (!audio_stream && s->type() == Stream::kAudio) {
audio_stream = static_cast<AudioStream*>(s);
}
if (!video_stream && s->type() == Stream::kVideo) {
video_stream = static_cast<VideoStream*>(s);
}
if (audio_stream && video_stream) {
break;
}
}
if (video_stream) {
video_node_->SetStream(video_stream);
Node::ConnectEdge(video_node_, NodeInput(sequence_.viewer_output(), ViewerOutput::kTextureInput));
}
if (audio_stream) {
audio_node_->SetStream(audio_stream);
Node::ConnectEdge(audio_node_, NodeInput(sequence_.viewer_output(), ViewerOutput::kSamplesInput));
}
ConnectViewerNode(sequence_.viewer_output(), footage_->project()->color_manager());
ConnectViewerNode(&sequence_, footage_->project()->color_manager());
SetTimestamp(cached_timestamps_.value(footage_, 0));
} else {
@@ -134,7 +97,7 @@ void FootageViewerWidget::StartFootageDragInternal(bool enable_video, bool enabl
QMimeData* mimedata = new QMimeData();
QByteArray encoded_data;
QDataStream stream(&encoded_data, QIODevice::WriteOnly);
QDataStream data_stream(&encoded_data, QIODevice::WriteOnly);
quint64 enabled_stream_flags = GetFootage()->get_enabled_stream_flags();
@@ -142,9 +105,11 @@ void FootageViewerWidget::StartFootageDragInternal(bool enable_video, bool enabl
if (!enable_video || !enable_audio) {
quint64 stream_disabler = 0x1;
foreach (Stream* s, GetFootage()->streams()) {
if ((s->type() == Stream::kVideo && !enable_video)
|| (s->type() == Stream::kAudio && !enable_audio)) {
for (int i=0; i<GetFootage()->GetStreamCount(); i++) {
Stream stream = GetFootage()->GetStreamAt(i);
if ((stream.type() == Stream::kVideo && !enable_video)
|| (stream.type() == Stream::kAudio && !enable_audio)) {
enabled_stream_flags &= ~stream_disabler;
}
@@ -152,7 +117,7 @@ void FootageViewerWidget::StartFootageDragInternal(bool enable_video, bool enabl
}
}
stream << enabled_stream_flags << -1 << reinterpret_cast<quintptr>(GetFootage());
data_stream << enabled_stream_flags << -1 << reinterpret_cast<quintptr>(GetFootage());
mimedata->setData("application/x-oliveprojectitemdata", encoded_data);
drag->setMimeData(mimedata);
@@ -160,6 +125,32 @@ void FootageViewerWidget::StartFootageDragInternal(bool enable_video, bool enabl
drag->exec();
}
void FootageViewerWidget::TryConnectingType(Footage *footage, Stream::Type type)
{
for (int i=0; ; i++) {
Stream stream = footage_->GetStreamAt(type, i);
// Found end of stream list
if (!stream.IsValid()) {
break;
}
if (stream.enabled()) {
QString s = Footage::GetStringFromReference(type, i);
QString input_param;
if (type == Stream::kVideo) {
input_param = ViewerOutput::kTextureInput;
} else {
input_param = ViewerOutput::kSamplesInput;
}
Node::ConnectEdge(NodeOutput(footage, s), NodeInput(&sequence_, input_param));
}
}
}
void FootageViewerWidget::StartFootageDrag()
{
StartFootageDragInternal(true, true);
+2 -5
View File
@@ -21,7 +21,6 @@
#ifndef FOOTAGEVIEWERWIDGET_H
#define FOOTAGEVIEWERWIDGET_H
#include "node/input/media/media.h"
#include "node/output/viewer/viewer.h"
#include "viewer.h"
@@ -44,14 +43,12 @@ protected:
private:
void StartFootageDragInternal(bool enable_video, bool enable_audio);
void TryConnectingType(Footage* footage, Stream::Type type);
Footage* footage_;
Sequence sequence_;
MediaInput* video_node_;
MediaInput* audio_node_;
QHash<Footage*, int64_t> cached_timestamps_;
private slots:
+4 -4
View File
@@ -22,14 +22,14 @@
namespace olive {
QVariant GizmoTraverser::ProcessVideoFootage(VideoStream *stream, const rational &input_time)
QVariant GizmoTraverser::ProcessVideoFootage(const Footage::StreamReference &ref, const rational &input_time)
{
Q_UNUSED(input_time)
VideoStream* image_stream = static_cast<VideoStream*>(stream);
Stream stream = ref.GetStream();
return QVector2D(image_stream->width() * image_stream->pixel_aspect_ratio().toDouble(),
image_stream->height());
return QVector2D(stream.width() * stream.pixel_aspect_ratio().toDouble(),
stream.height());
}
QVariant GizmoTraverser::ProcessShader(const Node *node, const TimeRange &range, const ShaderJob &job)
+1 -1
View File
@@ -34,7 +34,7 @@ public:
}
protected:
virtual QVariant ProcessVideoFootage(VideoStream* stream, const rational &input_time) override;
virtual QVariant ProcessVideoFootage(const Footage::StreamReference& stream, const rational &input_time) override;
virtual QVariant ProcessShader(const Node *node, const TimeRange &range, const ShaderJob& job) override;
+5 -5
View File
@@ -168,7 +168,7 @@ void ViewerWidget::TimeChangedEvent(const int64_t &i)
last_time_ = i;
}
void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
void ViewerWidget::ConnectNodeInternal(Sequence *n)
{
connect(n, &ViewerOutput::SizeChanged, this, &ViewerWidget::SetViewerResolution);
connect(n, &ViewerOutput::PixelAspectChanged, this, &ViewerWidget::SetViewerPixelAspect);
@@ -193,7 +193,7 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
if (override_color_manager_) {
using_manager = override_color_manager_;
} else if (n->parent()) {
using_manager = static_cast<Sequence*>(n->parent())->project()->color_manager();
using_manager = n->project()->color_manager();
} else {
qWarning() << "Failed to find a suitable color manager for the connected viewer node";
using_manager = nullptr;
@@ -220,7 +220,7 @@ void ViewerWidget::ConnectNodeInternal(ViewerOutput *n)
ForceUpdate();
}
void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
void ViewerWidget::DisconnectNodeInternal(Sequence *n)
{
PauseInternal();
@@ -252,7 +252,7 @@ void ViewerWidget::DisconnectNodeInternal(ViewerOutput *n)
QMetaObject::invokeMethod(this, "UpdateStack", Qt::QueuedConnection);
}
void ViewerWidget::ConnectedNodeChanged(ViewerOutput *n)
void ViewerWidget::ConnectedNodeChanged(Sequence *n)
{
auto_cacher_.SetViewerNode(n);
}
@@ -285,7 +285,7 @@ bool ViewerWidget::IsPlaying() const
return playback_speed_ != 0;
}
void ViewerWidget::ConnectViewerNode(ViewerOutput *node, ColorManager* color_manager)
void ViewerWidget::ConnectViewerNode(Sequence *node, ColorManager* color_manager)
{
override_color_manager_ = color_manager;
+4 -4
View File
@@ -63,7 +63,7 @@ public:
bool IsPlaying() const;
void ConnectViewerNode(ViewerOutput* node, ColorManager *color_manager = nullptr);
void ConnectViewerNode(Sequence *node, ColorManager *color_manager = nullptr);
/**
* @brief Enable or disable the color management menu
@@ -153,9 +153,9 @@ protected:
virtual void TimebaseChangedEvent(const rational &) override;
virtual void TimeChangedEvent(const int64_t &) override;
virtual void ConnectNodeInternal(ViewerOutput *) override;
virtual void DisconnectNodeInternal(ViewerOutput *) override;
virtual void ConnectedNodeChanged(ViewerOutput*n) override;
virtual void ConnectNodeInternal(Sequence *) override;
virtual void DisconnectNodeInternal(Sequence *) override;
virtual void ConnectedNodeChanged(Sequence*n) override;
virtual void ScaleChangedEvent(const double& s) override;