From f8830beac704eded9275d69eaeb73e39a4832405 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sun, 21 Jul 2019 18:21:40 -0700 Subject: [PATCH] created new sequence dialog --- app/CMakeLists.txt | 1 + app/common/clamp.h | 20 ++ app/common/lerp.h | 23 ++ app/common/qobjectlistcast.h | 20 ++ app/common/rational.cpp | 9 +- app/common/rational.h | 6 +- app/core.cpp | 75 ++++- app/core.h | 5 + app/dialog/CMakeLists.txt | 22 ++ app/dialog/sequence/CMakeLists.txt | 22 ++ app/dialog/sequence/sequence.cpp | 284 ++++++++++++++++++ app/dialog/sequence/sequence.h | 152 ++++++++++ app/node/block/block.cpp | 20 ++ app/node/block/block.h | 20 ++ app/node/generator/solid/solid.cpp | 20 ++ app/node/generator/solid/solid.h | 20 ++ app/node/graph.cpp | 10 - app/node/graph.h | 11 - app/node/input/media/media.cpp | 22 ++ app/node/input/media/media.h | 20 ++ app/node/output/viewer/viewer.cpp | 22 +- app/node/output/viewer/viewer.h | 20 ++ app/panel/CMakeLists.txt | 4 +- app/panel/node/node.cpp | 3 - ...panelfocusmanager.cpp => panelmanager.cpp} | 10 +- .../{panelfocusmanager.h => panelmanager.h} | 29 +- app/project/item/item.cpp | 26 ++ app/project/item/item.h | 4 + app/project/item/sequence/sequence.cpp | 39 ++- app/project/item/sequence/sequence.h | 14 +- app/task/import/import.cpp | 2 +- app/ui/style/olive-dark/style.css | 2 +- app/ui/style/olive-light/style.css | 2 +- .../footagecombobox/footagecombobox.cpp | 2 +- app/widget/menu/menushared.cpp | 2 +- .../nodeparamview/nodeparamviewitem.cpp | 2 +- app/window/mainwindow/mainwindow.cpp | 47 +-- 37 files changed, 911 insertions(+), 101 deletions(-) create mode 100644 app/dialog/CMakeLists.txt create mode 100644 app/dialog/sequence/CMakeLists.txt create mode 100644 app/dialog/sequence/sequence.cpp create mode 100644 app/dialog/sequence/sequence.h rename app/panel/{panelfocusmanager.cpp => panelmanager.cpp} (87%) rename app/panel/{panelfocusmanager.h => panelmanager.h} (85%) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 3fa2e554c..4341a515a 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -23,6 +23,7 @@ set(OLIVE_SOURCES add_subdirectory(common) add_subdirectory(decoder) +add_subdirectory(dialog) add_subdirectory(node) add_subdirectory(panel) add_subdirectory(project) diff --git a/app/common/clamp.h b/app/common/clamp.h index b5e891bd9..dda706505 100644 --- a/app/common/clamp.h +++ b/app/common/clamp.h @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #ifndef CLAMP_H #define CLAMP_H diff --git a/app/common/lerp.h b/app/common/lerp.h index 4d98db0a1..d62e97ddd 100644 --- a/app/common/lerp.h +++ b/app/common/lerp.h @@ -1,9 +1,32 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #ifndef LERP_H #define LERP_H template /** * @brief Linearly interpolate a value between a and b using t + * + * t should be a number between 0.0 and 1.0. 0.0 will return a, 1.0 will return b, and between will return a value + * in between a and b at that point linearly. */ T lerp(T a, T b, double t) { return (a * (1.0 - t)) + (b * t); diff --git a/app/common/qobjectlistcast.h b/app/common/qobjectlistcast.h index 5a4660b62..4ef562dc3 100644 --- a/app/common/qobjectlistcast.h +++ b/app/common/qobjectlistcast.h @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #ifndef QOBJECTLISTCAST_H #define QOBJECTLISTCAST_H diff --git a/app/common/rational.cpp b/app/common/rational.cpp index f08008e32..552f298b9 100644 --- a/app/common/rational.cpp +++ b/app/common/rational.cpp @@ -324,16 +324,21 @@ double rational::ToDouble() const } } -const int64_t &rational::numerator() +const int64_t &rational::numerator() const { return numerator_; } -const int64_t &rational::denominator() +const int64_t &rational::denominator() const { return denominator_; } +rational rational::flipped() const +{ + return rational(denominator_, numerator_); +} + void rational::FixSigns() { // Ensures denominator is always positive (while numerator can be positive or negative) diff --git a/app/common/rational.h b/app/common/rational.h index 7ba50b124..6ec18dd99 100644 --- a/app/common/rational.h +++ b/app/common/rational.h @@ -84,8 +84,10 @@ public: double ToDouble() const; // Specific values - const int64_t& numerator(); - const int64_t& denominator(); + const int64_t& numerator() const; + const int64_t& denominator() const; + + rational flipped() const; private: int64_t numerator_; int64_t denominator_; diff --git a/app/core.cpp b/app/core.cpp index 57664e81f..3e1c78ea0 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -28,9 +28,11 @@ #include #include -#include "panel/panelfocusmanager.h" +#include "dialog/sequence/sequence.h" +#include "panel/panelmanager.h" #include "panel/project/project.h" #include "project/item/footage/footage.h" +#include "project/item/sequence/sequence.h" #include "task/import/import.h" #include "task/taskmanager.h" #include "ui/style/style.h" @@ -215,6 +217,75 @@ void Core::CreateNewFolder() active_project_panel->Edit(new_folder.get()); } +// FIXME: Test code +#include "node/input/media/media.h" +#include "node/output/viewer/viewer.h" +#include "node/generator/solid/solid.h" +#include "panel/panelmanager.h" +#include "panel/node/node.h" +#include "panel/viewer/viewer.h" +// End test code + +void Core::CreateNewSequence() +{ + // Locate the most recently focused Project panel (assume that's the panel the user wants to import into) + ProjectPanel* active_project_panel = olive::panel_focus_manager->MostRecentlyFocused(); + Project* active_project; + + if (active_project_panel == nullptr // Check that we found a Project panel + || (active_project = active_project_panel->project()) == nullptr) { // and that we could find an active Project + QMessageBox::critical(main_window_, tr("Failed to create new sequence"), tr("Failed to find active Project panel")); + return; + } + + // Get the selected folder in this panel + Folder* folder = active_project_panel->GetSelectedFolder(); + + // Create new sequence + SequencePtr new_sequence = std::make_shared(); + + // Set all defaults for the sequence + new_sequence->SetDefaultParameters(); + + // Get default name for this sequence (in the format "Sequence N", the first that doesn't exist) + int sequence_number = 1; + QString sequence_name; + do { + sequence_name = tr("Sequence %1").arg(sequence_number); + sequence_number++; + } while (active_project->root()->ChildExistsWithName(sequence_name)); + new_sequence->set_name(sequence_name); + + SequenceDialog sd(new_sequence.get(), SequenceDialog::kNew, main_window_); + + // Make sure SequenceDialog doesn't make an undo command for editing the sequence, since we make an undo command for + // adding it later on + sd.SetUndoable(false); + + if (sd.exec() == QDialog::Accepted) { + // Create an undoable command + ProjectViewModel::AddItemCommand* aic = new ProjectViewModel::AddItemCommand(active_project_panel->model(), + folder, + new_sequence); + + // FIXME: Test code + NodeGraph* graph = new NodeGraph(); + graph->setParent(this); + ViewerOutput* vo = new ViewerOutput(); + vo->AttachViewer(olive::panel_focus_manager->MostRecentlyFocused()); + graph->AddNode(vo); + SolidGenerator* sg = new SolidGenerator(); + NodeInput::ConnectEdge(sg->texture_output(), vo->texture_input()); + graph->AddNode(sg); + MediaInput* ii = new MediaInput(); + graph->AddNode(ii); + olive::panel_focus_manager->MostRecentlyFocused()->SetGraph(graph); + // End test code + + olive::undo_stack.push(aic); + } +} + void Core::AddOpenProject(ProjectPtr p) { open_projects_.append(p); @@ -236,7 +307,7 @@ void Core::StartGUI(bool full_screen) olive::menu_shared.Initialize(); // Since we're starting GUI mode, create a PanelFocusManager (auto-deletes with QObject) - olive::panel_focus_manager = new PanelFocusManager(this); + olive::panel_focus_manager = new PanelManager(this); // Connect the PanelFocusManager to the application's focus change signal connect(qApp, diff --git a/app/core.h b/app/core.h index 24acd3c1a..388a6197f 100644 --- a/app/core.h +++ b/app/core.h @@ -124,6 +124,11 @@ public slots: */ void CreateNewFolder(); + /** + * @brief Createa a new sequence in the currently active project + */ + void CreateNewSequence(); + signals: /** * @brief Signal emitted when a project is opened diff --git a/app/dialog/CMakeLists.txt b/app/dialog/CMakeLists.txt new file mode 100644 index 000000000..8d32061fe --- /dev/null +++ b/app/dialog/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 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 . + +add_subdirectory(sequence) + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + PARENT_SCOPE +) diff --git a/app/dialog/sequence/CMakeLists.txt b/app/dialog/sequence/CMakeLists.txt new file mode 100644 index 000000000..150197b77 --- /dev/null +++ b/app/dialog/sequence/CMakeLists.txt @@ -0,0 +1,22 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + dialog/sequence/sequence.h + dialog/sequence/sequence.cpp + PARENT_SCOPE +) diff --git a/app/dialog/sequence/sequence.cpp b/app/dialog/sequence/sequence.cpp new file mode 100644 index 000000000..9dee5c098 --- /dev/null +++ b/app/dialog/sequence/sequence.cpp @@ -0,0 +1,284 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + +#include "sequence.h" + +extern "C" { +#include +} + +#include +#include +#include +#include +#include +#include + +#include "common/rational.h" +#include "undo/undostack.h" + +SequenceDialog::SequenceDialog(Sequence* s, Type t, QWidget* parent) : + QDialog(parent), + sequence_(s), + make_undoable_(true) +{ + QVBoxLayout* layout = new QVBoxLayout(this); + + // Set up preset section + QHBoxLayout* preset_layout = new QHBoxLayout(); + preset_layout->addWidget(new QLabel(tr("Preset:"))); + QComboBox* preset_combobox = new QComboBox(); + preset_layout->addWidget(preset_combobox); + layout->addLayout(preset_layout); + + // Set up video section + QGroupBox* video_group = new QGroupBox(); + video_group->setTitle(tr("Video")); + QGridLayout* video_layout = new QGridLayout(video_group); + video_layout->addWidget(new QLabel(tr("Width:")), 0, 0); + video_width_field_ = new QSpinBox(); + video_width_field_->setMaximum(99999); + video_layout->addWidget(video_width_field_, 0, 1); + video_layout->addWidget(new QLabel(tr("Height:")), 1, 0); + video_height_field_ = new QSpinBox(); + video_height_field_->setMaximum(99999); + video_layout->addWidget(video_height_field_, 1, 1); + video_layout->addWidget(new QLabel(tr("Frame Rate:")), 2, 0); + video_frame_rate_field_ = new QComboBox(); + // FIXME: No frame rate made + video_layout->addWidget(video_frame_rate_field_, 2, 1); + layout->addWidget(video_group); + + // Set up audio section + QGroupBox* audio_group = new QGroupBox(); + audio_group->setTitle(tr("Audio")); + QGridLayout* audio_layout = new QGridLayout(audio_group); + audio_layout->addWidget(new QLabel(tr("Sample Rate:")), 0, 0); + audio_sample_rate_field_ = new QComboBox(); + // FIXME: No sample rate made + audio_layout->addWidget(audio_sample_rate_field_, 0, 1); + audio_layout->addWidget(new QLabel(tr("Channels:")), 1, 0); + audio_channels_field_ = new QComboBox(); + // FIXME: No channels made + audio_layout->addWidget(audio_channels_field_, 1, 1); + layout->addWidget(audio_group); + + // Set up name section + QHBoxLayout* name_layout = new QHBoxLayout(); + name_layout->addWidget(new QLabel(tr("Name:"))); + name_field_ = new QLineEdit(); + name_layout->addWidget(name_field_); + layout->addLayout(name_layout); + + // Set up dialog buttons + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + buttons->setCenterButtons(true); + connect(buttons, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttons, SIGNAL(rejected()), this, SLOT(reject())); + layout->addWidget(buttons); + + // Set window title based on type + switch (t) { + case kNew: + setWindowTitle("New Sequence"); + break; + case kExisting: + setWindowTitle(tr("Editing \"%1\"").arg(sequence_->name())); + break; + } + + // Set up available frame rates + AddFrameRate(rational(10, 1)); // 10 FPS + AddFrameRate(rational(15, 1)); // 15 FPS + AddFrameRate(rational(24000, 1001)); // 23.976 FPS + AddFrameRate(rational(24, 1)); // 24 FPS + AddFrameRate(rational(25, 1)); // 25 FPS + AddFrameRate(rational(30000, 1001)); // 29.97 FPS + AddFrameRate(rational(30, 1)); // 30 FPS + AddFrameRate(rational(48000, 1001)); // 47.952 FPS + AddFrameRate(rational(48, 1)); // 48 FPS + AddFrameRate(rational(50, 1)); // 50 FPS + AddFrameRate(rational(60000, 1001)); // 59.94 FPS + AddFrameRate(rational(60, 1)); // 60 FPS + + // Set up available sample rates + AddSampleRate(rational(8000, 1)); // 8000 Hz + AddSampleRate(rational(11025, 1)); // 11025 Hz + AddSampleRate(rational(16000, 1)); // 16000 Hz + AddSampleRate(rational(22050, 1)); // 22050 Hz + AddSampleRate(rational(24000, 1)); // 24000 Hz + AddSampleRate(rational(32000, 1)); // 32000 Hz + AddSampleRate(rational(44100, 1)); // 44100 Hz + AddSampleRate(rational(48000, 1)); // 48000 Hz + AddSampleRate(rational(88200, 1)); // 88200 Hz + AddSampleRate(rational(96000, 1)); // 96000 Hz + + // Set up available channel layouts + AddChannelLayout(AV_CH_LAYOUT_MONO); + AddChannelLayout(AV_CH_LAYOUT_STEREO); + AddChannelLayout(AV_CH_LAYOUT_5POINT1); + AddChannelLayout(AV_CH_LAYOUT_7POINT1); + + // Set values based on input sequence + video_width_field_->setValue(sequence_->video_width()); + video_height_field_->setValue(sequence_->video_height()); + + int frame_rate_index = frame_rate_list_.indexOf(sequence_->video_time_base().flipped()); + video_frame_rate_field_->setCurrentIndex(frame_rate_index); + + int sample_rate_index = sample_rate_list_.indexOf(sequence_->audio_time_base().flipped()); + audio_sample_rate_field_->setCurrentIndex(sample_rate_index); + + for (int i=0;icount();i++) { + if (audio_channels_field_->itemData(i).toULongLong() == sequence_->audio_channel_layout()) { + audio_channels_field_->setCurrentIndex(i); + break; + } + } + + name_field_->setText(sequence_->name()); +} + +void SequenceDialog::SetUndoable(bool u) +{ + make_undoable_ = u; +} + +void SequenceDialog::accept() +{ + if (name_field_->text().isEmpty()) { + QMessageBox::critical(this, tr("Error editing Sequence"), tr("Please enter a name for this Sequence.")); + return; + } + + // Get the rational at the combobox's index (which will be correct provided AddFrameRate() was used at all time) + rational video_time_base = frame_rate_list_.at(video_frame_rate_field_->currentIndex()).flipped(); + + + // Get the rational at the combobox's index (which will be correct provided AddFrameRate() was used at all time) + rational audio_time_base = sample_rate_list_.at(audio_sample_rate_field_->currentIndex()).flipped(); + + // Get the audio channel layout value + uint64_t channels = audio_channels_field_->currentData().toULongLong(); + + if (make_undoable_) { + + // Make undoable command to change the parameters + SequenceParamCommand* param_command = new SequenceParamCommand(sequence_, + video_width_field_->value(), + video_height_field_->value(), + video_time_base, + audio_time_base, + channels); + + olive::undo_stack.push(param_command); + + } else { + // Set sequence values directly with no undo command + sequence_->set_video_width(video_width_field_->value()); + sequence_->set_video_height(video_height_field_->value()); + sequence_->set_video_time_base(video_time_base); + + sequence_->set_audio_time_base(audio_time_base); + sequence_->set_audio_channel_layout(channels); + + sequence_->set_name(name_field_->text()); + } + + QDialog::accept(); +} + +void SequenceDialog::AddFrameRate(const rational &r) +{ + frame_rate_list_.append(r); + + video_frame_rate_field_->addItem(tr("%1 FPS").arg(r.ToDouble())); +} + +void SequenceDialog::AddSampleRate(const rational &rate) +{ + sample_rate_list_.append(rate); + + audio_sample_rate_field_->addItem(tr("%1 Hz").arg(rate.ToDouble())); +} + +void SequenceDialog::AddChannelLayout(int layout) +{ + QString layout_name; + + switch (layout) { + case AV_CH_LAYOUT_MONO: + layout_name = tr("Mono"); + break; + case AV_CH_LAYOUT_STEREO: + layout_name = tr("Stereo"); + break; + case AV_CH_LAYOUT_5POINT1: + layout_name = tr("5.1"); + break; + case AV_CH_LAYOUT_7POINT1: + layout_name = tr("7.1"); + break; + default: + layout_name = tr("Unknown (%1)").arg(layout); + } + + audio_channels_field_->addItem(layout_name, layout); +} + +SequenceDialog::SequenceParamCommand::SequenceParamCommand(Sequence *s, + const int &width, + const int &height, + const rational &v_timebase, + const rational &a_timebase, + const uint64_t &channels, + QUndoCommand *parent): + QUndoCommand(parent), + sequence_(s), + width_(width), + height_(height), + v_timebase_(v_timebase), + a_timebase_(a_timebase), + channels_(channels), + old_width_(s->video_width()), + old_height_(s->video_height()), + old_v_timebase_(s->video_time_base()), + old_a_timebase_(s->audio_time_base()), + old_channels_(s->audio_channel_layout()) +{ +} + +void SequenceDialog::SequenceParamCommand::redo() +{ + sequence_->set_video_width(width_); + sequence_->set_video_height(height_); + sequence_->set_video_time_base(v_timebase_); + sequence_->set_audio_time_base(a_timebase_); + sequence_->set_audio_channel_layout(channels_); +} + +void SequenceDialog::SequenceParamCommand::undo() +{ + sequence_->set_video_width(old_width_); + sequence_->set_video_height(old_height_); + sequence_->set_video_time_base(old_v_timebase_); + sequence_->set_audio_time_base(old_a_timebase_); + sequence_->set_audio_channel_layout(old_channels_); +} diff --git a/app/dialog/sequence/sequence.h b/app/dialog/sequence/sequence.h new file mode 100644 index 000000000..6ada69f10 --- /dev/null +++ b/app/dialog/sequence/sequence.h @@ -0,0 +1,152 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + +#ifndef SEQUENCEDIALOG_H +#define SEQUENCEDIALOG_H + +#include +#include +#include +#include + +#include "project/item/sequence/sequence.h" + +/** + * @brief A dialog for editing Sequence parameters + * + * This dialog exposes all the parameters of a Sequence to users allowing them to set up a Sequence however they wish. + * A Sequence can be sent to this dialog through the constructor. All fields will be filled using that Sequence's + * parameters, allowing the user to view and edit them. Accepting the dialog will apply them back to that Sequence, + * either directly or using a QUndoCommand (see SetUndoable()). + * + * If creating a new Sequence, the Sequence must still be constructed first before sending it to SequenceDialog. + * SequenceDialog does not create any new objects. In most cases when creating a new Sequence, editing its parameters + * with SequenceDialog will be paired with the action of adding the Sequence to a project. In this situation, since the + * latter will be the main undoable action, the parameter editing doesn't have to be undoable since to the user they'll + * be viewed as one single action (see SetUndoable()). + */ +class SequenceDialog : public QDialog +{ + Q_OBJECT +public: + /** + * @brief Used to set the dialog mode of operation (see SequenceDialog()) + */ + enum Type { + kNew, + kExisting + }; + + /** + * @brief SequenceDialog Constructor + * + * @param s + * Sequence to edit + * + * @param t + * Mode of operation (changes some UI like the window title to best represent the action being performed) + * + * @param parent + * QWidget parent + */ + SequenceDialog(Sequence* s, Type t = kExisting, QWidget* parent = nullptr); + + /** + * @brief Set whether the parameter changes should be made into an undo command or not + * + * @param u + */ + void SetUndoable(bool u); + +public slots: + /** + * @brief Function called when the user presses OK + */ + virtual void accept() override; + +private: + /** + * @brief Internal function for adding a selectable frame rate + */ + void AddFrameRate(const rational& r); + + /** + * @brief Internal function for adding a selectable sample rate + */ + void AddSampleRate(const rational &rate); + + /** + * @brief Internal function for adding a selectable channel layout + */ + void AddChannelLayout(int layout); + + Sequence* sequence_; + + bool make_undoable_; + + QSpinBox* video_width_field_; + + QSpinBox* video_height_field_; + + QComboBox* video_frame_rate_field_; + + QComboBox* audio_sample_rate_field_; + + QComboBox* audio_channels_field_; + + QLineEdit* name_field_; + + QVector frame_rate_list_; + + QVector sample_rate_list_; + + /** + * @brief A QUndoCommand for setting the parameters on a sequence + */ + class SequenceParamCommand : public QUndoCommand { + public: + SequenceParamCommand(Sequence* s, + const int& width, + const int& height, + const rational& v_timebase, + const rational& a_timebase, + const uint64_t &channels, + QUndoCommand* parent = nullptr); + + virtual void redo() override; + virtual void undo() override; + private: + Sequence* sequence_; + + int width_; + int height_; + rational v_timebase_; + rational a_timebase_; + uint64_t channels_; + + int old_width_; + int old_height_; + rational old_v_timebase_; + rational old_a_timebase_; + uint64_t old_channels_; + }; +}; + +#endif // SEQUENCEDIALOG_H diff --git a/app/node/block/block.cpp b/app/node/block/block.cpp index ceacac3a7..2daad454d 100644 --- a/app/node/block/block.cpp +++ b/app/node/block/block.cpp @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #include "block.h" Block::Block() diff --git a/app/node/block/block.h b/app/node/block/block.h index 9f69658d1..d274e023f 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #ifndef BLOCK_H #define BLOCK_H diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index f284d7790..33956d2ad 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #include "solid.h" SolidGenerator::SolidGenerator() : diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h index fd378d1ff..18b79eca0 100644 --- a/app/node/generator/solid/solid.h +++ b/app/node/generator/solid/solid.h @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #ifndef SOLIDGENERATOR_H #define SOLIDGENERATOR_H diff --git a/app/node/graph.cpp b/app/node/graph.cpp index 94ef78a86..7c11f1c5b 100644 --- a/app/node/graph.cpp +++ b/app/node/graph.cpp @@ -35,16 +35,6 @@ void NodeGraph::AddNode(Node *node) connect(node, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SIGNAL(EdgeRemoved(NodeEdgePtr))); } -const QString &NodeGraph::name() -{ - return name_; -} - -void NodeGraph::set_name(const QString &name) -{ - name_ = name; -} - QList NodeGraph::nodes() { return static_qobjectlist_cast(children()); diff --git a/app/node/graph.h b/app/node/graph.h index 0d5064829..a18f3f4e3 100644 --- a/app/node/graph.h +++ b/app/node/graph.h @@ -45,16 +45,6 @@ public: */ void AddNode(Node* node); - /** - * @brief Return the name of this graph (user-defined) - */ - const QString& name(); - - /** - * @brief Set the name of this graph (user-defined) - */ - void set_name(const QString& name); - /** * @brief Retrieve a complete list of the nodes belonging to this graph */ @@ -72,7 +62,6 @@ signals: void EdgeRemoved(NodeEdgePtr edge); private: - QString name_; }; #endif // NODEGRAPH_H diff --git a/app/node/input/media/media.cpp b/app/node/input/media/media.cpp index f1b5a28d4..bbd9a9f48 100644 --- a/app/node/input/media/media.cpp +++ b/app/node/input/media/media.cpp @@ -1,5 +1,27 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #include "media.h" +#include + MediaInput::MediaInput() : texture_(nullptr) { diff --git a/app/node/input/media/media.h b/app/node/input/media/media.h index e359ea076..6851c8ee8 100644 --- a/app/node/input/media/media.h +++ b/app/node/input/media/media.h @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #ifndef IMAGE_H #define IMAGE_H diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index 3b5b75299..c9cb2a950 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -1,6 +1,26 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #include "viewer.h" -#include "panel/panelfocusmanager.h" +#include "panel/panelmanager.h" ViewerOutput::ViewerOutput() : attached_viewer_(nullptr) diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index d219fa8ac..923f64f82 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -1,3 +1,23 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 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 . + +***/ + #ifndef VIEWER_H #define VIEWER_H diff --git a/app/panel/CMakeLists.txt b/app/panel/CMakeLists.txt index 0b3f572b0..c8c37999b 100644 --- a/app/panel/CMakeLists.txt +++ b/app/panel/CMakeLists.txt @@ -24,7 +24,7 @@ add_subdirectory(viewer) set(OLIVE_SOURCES ${OLIVE_SOURCES} - panel/panelfocusmanager.h - panel/panelfocusmanager.cpp + panel/panelmanager.h + panel/panelmanager.cpp PARENT_SCOPE ) diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index 9caad412b..05f911882 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -38,8 +38,6 @@ NodePanel::NodePanel(QWidget *parent) : void NodePanel::SetGraph(NodeGraph *graph) { - SetSubtitle(graph->name()); - node_view_->SetGraph(graph); } @@ -54,5 +52,4 @@ void NodePanel::changeEvent(QEvent *e) void NodePanel::Retranslate() { SetTitle(tr("Node Editor")); - SetSubtitle(tr("(none)")); } diff --git a/app/panel/panelfocusmanager.cpp b/app/panel/panelmanager.cpp similarity index 87% rename from app/panel/panelfocusmanager.cpp rename to app/panel/panelmanager.cpp index c25e77245..ef4a76e6f 100644 --- a/app/panel/panelfocusmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -18,17 +18,17 @@ ***/ -#include "panelfocusmanager.h" +#include "panelmanager.h" -PanelFocusManager* olive::panel_focus_manager = nullptr; +PanelManager* olive::panel_focus_manager = nullptr; -PanelFocusManager::PanelFocusManager(QObject *parent) : +PanelManager::PanelManager(QObject *parent) : QObject(parent) { } -PanelWidget *PanelFocusManager::CurrentlyFocused() const +PanelWidget *PanelManager::CurrentlyFocused() const { if (focus_history_.isEmpty()) { return nullptr; @@ -37,7 +37,7 @@ PanelWidget *PanelFocusManager::CurrentlyFocused() const return focus_history_.first(); } -void PanelFocusManager::FocusChanged(QWidget *old, QWidget *now) +void PanelManager::FocusChanged(QWidget *old, QWidget *now) { Q_UNUSED(old) diff --git a/app/panel/panelfocusmanager.h b/app/panel/panelmanager.h similarity index 85% rename from app/panel/panelfocusmanager.h rename to app/panel/panelmanager.h index a5668546a..48d04812c 100644 --- a/app/panel/panelfocusmanager.h +++ b/app/panel/panelmanager.h @@ -41,17 +41,18 @@ * PanelFocusManager's SLOT(FocusChanged()) connects to the QApplication instance's SIGNAL(focusChanged()) so that * it always knows when focus has changed within the application. */ -class PanelFocusManager : public QObject +class PanelManager : public QObject { Q_OBJECT public: - PanelFocusManager(QObject* parent); + PanelManager(QObject* parent); /** * @brief Return the currently focused widget, or nullptr if nothing is focused */ PanelWidget* CurrentlyFocused() const; + template /** * @brief Get most recently focused panel of a certain type * @@ -59,9 +60,16 @@ public: * * The most recently focused panel of the specified type, or nullptr if none exists */ - template T* MostRecentlyFocused(); + template + /** + * @brief Create a panel + * @param parent + * @return + */ + T* CreatePanel(QWidget* parent); + public slots: /** * @brief Connect this to a QApplication's SIGNAL(focusChanged()) @@ -78,7 +86,18 @@ private: }; template -T* PanelFocusManager::MostRecentlyFocused() +T *PanelManager::CreatePanel(QWidget *parent) +{ + T* panel = new T(parent); + + // Add panel to the bottom of the focus history + focus_history_.append(panel); + + return panel; +} + +template +T* PanelManager::MostRecentlyFocused() { T* cast_test; @@ -94,7 +113,7 @@ T* PanelFocusManager::MostRecentlyFocused() } namespace olive { -extern PanelFocusManager* panel_focus_manager; +extern PanelManager* panel_focus_manager; } #endif // PANELFOCUSMANAGER_H diff --git a/app/project/item/item.cpp b/app/project/item/item.cpp index 0705a6ac7..aad058551 100644 --- a/app/project/item/item.cpp +++ b/app/project/item/item.cpp @@ -132,6 +132,32 @@ bool Item::CanHaveChildren() const return false; } +bool Item::ChildExistsWithName(const QString &name) +{ + return ChildExistsWithNameInternal(name, this); +} + +bool Item::ChildExistsWithNameInternal(const QString &name, Item *folder) +{ + // Loop through all children + for (int i=0;ichild_count();i++) { + Item* child = folder->child(i); + + // If this child has the same name, return true + if (child->name() == name) { + return true; + } else if (child->CanHaveChildren()) { + // If the child has children, run function recursively on this item + if (ChildExistsWithNameInternal(name, child)) { + // If it returns true, we've found a child so we can return now + return true; + } + } + } + + return false; +} + void Item::Lock() { mutex_.lock(); diff --git a/app/project/item/item.h b/app/project/item/item.h index a7ad340db..f1036f5dc 100644 --- a/app/project/item/item.h +++ b/app/project/item/item.h @@ -98,10 +98,14 @@ public: virtual bool CanHaveChildren() const; + bool ChildExistsWithName(const QString& name); + void Lock(); void Unlock(); private: + bool ChildExistsWithNameInternal(const QString& name, Item* folder); + QList children_; Item* parent_; diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index fafb37458..a903f1c33 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -20,6 +20,10 @@ #include "sequence.h" +extern "C" { +#include +} + #include "ui/icons/icons.h" Sequence::Sequence() @@ -47,9 +51,9 @@ const int &Sequence::video_height() const return video_height_; } -void Sequence::set_video_height(const int &video_height) +void Sequence::set_video_height(const int &height) { - video_height_ = video_height; + video_height_ = height; } const rational &Sequence::video_time_base() @@ -62,16 +66,6 @@ void Sequence::set_video_time_base(const rational &time_base) video_time_base_ = time_base; } -const int &Sequence::audio_sampling_rate() -{ - return audio_sampling_rate_; -} - -void Sequence::set_audio_sampling_rate(const int &sample_rate) -{ - audio_sampling_rate_ = sample_rate; -} - const rational &Sequence::audio_time_base() { return audio_time_base_; @@ -81,3 +75,24 @@ void Sequence::set_audio_time_base(const rational &time_base) { audio_time_base_ = time_base; } + +const uint64_t &Sequence::audio_channel_layout() +{ + return audio_channel_layout_; +} + +void Sequence::set_audio_channel_layout(const uint64_t &channel_layout) +{ + audio_channel_layout_ = channel_layout; +} + +void Sequence::SetDefaultParameters() +{ + // FIXME: Make these configurable + set_video_width(1920); + set_video_height(1080); + set_video_time_base(rational(1001, 30000)); + + set_audio_time_base(rational(1, 48000)); + set_audio_channel_layout(AV_CH_LAYOUT_STEREO); +} diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index a995a4d25..a547af2d8 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -44,26 +44,30 @@ public: void set_video_width(const int& width); const int& video_height() const; - void set_video_height(const int& video_height); + void set_video_height(const int& height); const rational& video_time_base(); void set_video_time_base(const rational& time_base); /* AUDIO GETTER/SETTER FUNCTIONS */ - const int& audio_sampling_rate(); - void set_audio_sampling_rate(const int& sample_rate); - const rational& audio_time_base(); void set_audio_time_base(const rational& time_base); + const uint64_t& audio_channel_layout(); + void set_audio_channel_layout(const uint64_t& channel_layout); + + void SetDefaultParameters(); + private: int video_width_; int video_height_; rational video_time_base_; - int audio_sampling_rate_; rational audio_time_base_; + uint64_t audio_channel_layout_; }; +using SequencePtr = std::shared_ptr; + #endif // SEQUENCE_H diff --git a/app/task/import/import.cpp b/app/task/import/import.cpp index f24ea0049..59ddda41f 100644 --- a/app/task/import/import.cpp +++ b/app/task/import/import.cpp @@ -27,7 +27,7 @@ #include // FIXME: Only used for test code -#include "panel/panelfocusmanager.h" +#include "panel/panelmanager.h" #include "panel/project/project.h" // End test code diff --git a/app/ui/style/olive-dark/style.css b/app/ui/style/olive-dark/style.css index f6dc64880..c2bf689f8 100644 --- a/app/ui/style/olive-dark/style.css +++ b/app/ui/style/olive-dark/style.css @@ -63,7 +63,7 @@ a { } /* All of these widgets' backgrounds are dark */ -QTreeView, QListView, QLineEdit, QMenu, QProgressBar, QPushButton::checked, NodeView, QComboBox { +QTreeView, QListView, QLineEdit, QMenu, QProgressBar, QPushButton::checked, NodeView, QComboBox, QSpinBox { /* Dark */ background: #191919; } diff --git a/app/ui/style/olive-light/style.css b/app/ui/style/olive-light/style.css index 29de1db44..e30729303 100644 --- a/app/ui/style/olive-light/style.css +++ b/app/ui/style/olive-light/style.css @@ -63,7 +63,7 @@ a { } /* All of these widgets' backgrounds are dark */ -QTreeView, QListView, QLineEdit, QMenu, QProgressBar, QPushButton::checked, NodeView, QCheckBox { +QTreeView, QListView, QLineEdit, QMenu, QProgressBar, QPushButton::checked, NodeView, QComboBox, QSpinBox { /* Dark */ background: #ffffff; } diff --git a/app/widget/footagecombobox/footagecombobox.cpp b/app/widget/footagecombobox/footagecombobox.cpp index f3db40464..6fd97331c 100644 --- a/app/widget/footagecombobox/footagecombobox.cpp +++ b/app/widget/footagecombobox/footagecombobox.cpp @@ -52,7 +52,7 @@ void FootageComboBox::TraverseFolder(const Folder *f, QMenu *m) for (int i=0;ichild_count();i++) { Item* child = f->child(i); - if (child->type() == Item::kFolder) { + if (child->CanHaveChildren()) { TraverseFolder(static_cast(child), m->addMenu(child->name())); diff --git a/app/widget/menu/menushared.cpp b/app/widget/menu/menushared.cpp index 6354adb59..04d3ad7b5 100644 --- a/app/widget/menu/menushared.cpp +++ b/app/widget/menu/menushared.cpp @@ -32,7 +32,7 @@ void MenuShared::Initialize() { // "New" menu shared items new_project_item_ = Menu::CreateItem(this, "newproj", nullptr, nullptr, "Ctrl+N"); - new_sequence_item_ = Menu::CreateItem(this, "newseq", nullptr, nullptr, "Ctrl+Shift+N"); + new_sequence_item_ = Menu::CreateItem(this, "newseq", &olive::core, SLOT(CreateNewSequence()), "Ctrl+Shift+N"); new_folder_item_ = Menu::CreateItem(this, "newfolder", &olive::core, SLOT(CreateNewFolder())); // "Edit" menu shared items diff --git a/app/widget/nodeparamview/nodeparamviewitem.cpp b/app/widget/nodeparamview/nodeparamviewitem.cpp index 187472d5c..b22929b8a 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.cpp +++ b/app/widget/nodeparamview/nodeparamviewitem.cpp @@ -31,7 +31,7 @@ #include "widget/footagecombobox/footagecombobox.h" // FIXME: Test code only -#include "panel/panelfocusmanager.h" +#include "panel/panelmanager.h" #include "panel/project/project.h" // End test code diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 558c3a9bb..905ae5522 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -23,6 +23,7 @@ #include // Panel objects +#include "panel/panelmanager.h" #include "panel/node/node.h" #include "panel/param/param.h" #include "panel/project/project.h" @@ -33,12 +34,6 @@ // Main menu bar #include "mainmenu.h" -// FIXME: Test code -#include "node/input/media/media.h" -#include "node/output/viewer/viewer.h" -#include "node/generator/solid/solid.h" -// End test code - olive::MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { @@ -62,42 +57,24 @@ olive::MainWindow::MainWindow(QWidget *parent) : void olive::MainWindow::ProjectOpen(Project* p) { // TODO Use settings data to create panels and restore state if they exist - ProjectPanel* project_panel = new ProjectPanel(this); - project_panel->set_project(p); - addDockWidget(Qt::TopDockWidgetArea, project_panel); + NodePanel* node_panel = olive::panel_focus_manager->CreatePanel(this); + addDockWidget(Qt::TopDockWidgetArea, node_panel); - ViewerPanel* viewer_panel1 = new ViewerPanel(this); - addDockWidget(Qt::TopDockWidgetArea, viewer_panel1); + ParamPanel* param_panel = olive::panel_focus_manager->CreatePanel(this); + addDockWidget(Qt::TopDockWidgetArea, param_panel); - ViewerPanel* viewer_panel2 = new ViewerPanel(this); + ViewerPanel* viewer_panel2 = olive::panel_focus_manager->CreatePanel(this); addDockWidget(Qt::TopDockWidgetArea, viewer_panel2); - ToolPanel* tool_panel = new ToolPanel(this); + ProjectPanel* project_panel = olive::panel_focus_manager->CreatePanel(this); + project_panel->set_project(p); + addDockWidget(Qt::BottomDockWidgetArea, project_panel); + + ToolPanel* tool_panel = olive::panel_focus_manager->CreatePanel(this); addDockWidget(Qt::BottomDockWidgetArea, tool_panel); - NodePanel* node_panel = new NodePanel(this); - addDockWidget(Qt::BottomDockWidgetArea, node_panel); - - ParamPanel* param_panel = new ParamPanel(this); - addDockWidget(Qt::BottomDockWidgetArea, param_panel); - - TimelinePanel* timeline_panel = new TimelinePanel(this); + TimelinePanel* timeline_panel = olive::panel_focus_manager->CreatePanel(this); addDockWidget(Qt::BottomDockWidgetArea, timeline_panel); connect(node_panel, SIGNAL(SelectionChanged(QList)), param_panel, SLOT(SetNodes(QList))); - - // FIXME: Test code - NodeGraph* graph = new NodeGraph(); - graph->setParent(this); - graph->set_name("New Graph"); - ViewerOutput* vo = new ViewerOutput(); - vo->AttachViewer(viewer_panel2); - graph->AddNode(vo); - SolidGenerator* sg = new SolidGenerator(); - NodeInput::ConnectEdge(sg->texture_output(), vo->texture_input()); - graph->AddNode(sg); - MediaInput* ii = new MediaInput(); - graph->AddNode(ii); - node_panel->SetGraph(graph); - // End test code }