From b21271534f4256e0ec334ee6025b23890ab5ea40 Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 20 Feb 2021 13:27:56 +1100 Subject: [PATCH] added UI for editing video parameters in nodes --- app/core.cpp | 16 - app/core.h | 5 - app/dialog/CMakeLists.txt | 1 - .../projectproperties/projectproperties.cpp | 247 ------------ .../projectproperties/projectproperties.h | 73 ---- .../sequence/sequencedialogparametertab.cpp | 51 +-- .../sequence/sequencedialogparametertab.h | 21 +- app/node/CMakeLists.txt | 1 + app/node/graph.h | 12 + .../project}/CMakeLists.txt | 4 +- .../project/projectsettings/CMakeLists.txt | 22 ++ .../projectsettings/projectsettings.cpp | 60 +++ .../project/projectsettings/projectsettings.h | 95 +++++ app/project/item/footage/footage.cpp | 37 +- app/project/item/sequence/sequence.cpp | 5 + app/project/item/sequence/sequence.h | 2 + app/project/project.cpp | 54 ++- app/project/project.h | 16 +- app/render/colormanager.cpp | 16 +- app/render/colormanager.h | 7 +- app/render/videoparams.cpp | 4 +- app/widget/CMakeLists.txt | 1 + app/widget/filefield/filefield.cpp | 18 +- app/widget/filefield/filefield.h | 12 + .../nodeparamviewwidgetbridge.cpp | 68 +++- .../projectexplorer/projectexplorer.cpp | 6 - app/widget/videoparamedit/CMakeLists.txt | 22 ++ app/widget/videoparamedit/videoparamedit.cpp | 374 ++++++++++++++++++ app/widget/videoparamedit/videoparamedit.h | 179 +++++++++ app/window/mainwindow/mainmenu.cpp | 4 - app/window/mainwindow/mainmenu.h | 1 - 31 files changed, 979 insertions(+), 455 deletions(-) delete mode 100644 app/dialog/projectproperties/projectproperties.cpp delete mode 100644 app/dialog/projectproperties/projectproperties.h rename app/{dialog/projectproperties => node/project}/CMakeLists.txt (88%) create mode 100644 app/node/project/projectsettings/CMakeLists.txt create mode 100644 app/node/project/projectsettings/projectsettings.cpp create mode 100644 app/node/project/projectsettings/projectsettings.h create mode 100644 app/widget/videoparamedit/CMakeLists.txt create mode 100644 app/widget/videoparamedit/videoparamedit.cpp create mode 100644 app/widget/videoparamedit/videoparamedit.h diff --git a/app/core.cpp b/app/core.cpp index 0eb5b9aff..6693d5c09 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -44,7 +44,6 @@ #include "dialog/sequence/sequence.h" #include "dialog/task/task.h" #include "dialog/preferences/preferences.h" -#include "dialog/projectproperties/projectproperties.h" #include "node/factory.h" #include "panel/panelmanager.h" #include "panel/project/project.h" @@ -334,21 +333,6 @@ void Core::DialogPreferencesShow() pd.exec(); } -void Core::DialogProjectPropertiesShow() -{ - Project* proj = GetActiveProject(); - - if (proj) { - ProjectPropertiesDialog ppd(proj, main_window_); - ppd.exec(); - } else { - QMessageBox::critical(main_window_, - tr("No Active Project"), - tr("No project is currently open to set the properties for"), - QMessageBox::Ok); - } -} - void Core::DialogExportShow() { Sequence* viewer = GetSequenceToExport(); diff --git a/app/core.h b/app/core.h index 0797b4340..901cb2222 100644 --- a/app/core.h +++ b/app/core.h @@ -363,11 +363,6 @@ public slots: */ void DialogPreferencesShow(); - /** - * @brief Show Project Properties dialog - */ - void DialogProjectPropertiesShow(); - /** * @brief Show Export dialog */ diff --git a/app/dialog/CMakeLists.txt b/app/dialog/CMakeLists.txt index f041cbeeb..05c516662 100644 --- a/app/dialog/CMakeLists.txt +++ b/app/dialog/CMakeLists.txt @@ -24,7 +24,6 @@ add_subdirectory(footagerelink) add_subdirectory(keyframeproperties) add_subdirectory(preferences) add_subdirectory(progress) -add_subdirectory(projectproperties) add_subdirectory(rendercancel) add_subdirectory(richtext) add_subdirectory(sequence) diff --git a/app/dialog/projectproperties/projectproperties.cpp b/app/dialog/projectproperties/projectproperties.cpp deleted file mode 100644 index a49a7b170..000000000 --- a/app/dialog/projectproperties/projectproperties.cpp +++ /dev/null @@ -1,247 +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 . - -***/ - -#include "projectproperties.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "common/filefunctions.h" -#include "common/ocioutils.h" -#include "config/config.h" -#include "core.h" -#include "render/colormanager.h" -#include "render/diskmanager.h" - -namespace olive { - -ProjectPropertiesDialog::ProjectPropertiesDialog(Project* p, QWidget *parent) : - QDialog(parent), - working_project_(p), - ocio_config_is_valid_(true) -{ - QVBoxLayout* layout = new QVBoxLayout(this); - - setWindowTitle(tr("Project Properties for '%1'").arg(working_project_->name())); - - QTabWidget* tabs = new QTabWidget; - layout->addWidget(tabs); - - { - // Color management group - QWidget* color_group = new QWidget(); - - QVBoxLayout* color_outer_layout = new QVBoxLayout(color_group); - - QGridLayout* color_layout = new QGridLayout(); - color_outer_layout->addLayout(color_layout); - - int row = 0; - - color_layout->addWidget(new QLabel(tr("OpenColorIO Configuration:")), row, 0); - - ocio_filename_ = new QLineEdit(); - ocio_filename_->setPlaceholderText(tr("(default)")); - color_layout->addWidget(ocio_filename_, row, 1); - - row++; - - color_layout->addWidget(new QLabel(tr("Default Input Color Space:")), row, 0); - - default_input_colorspace_ = new QComboBox(); - color_layout->addWidget(default_input_colorspace_, row, 1, 1, 2); - - row++; - - QPushButton* browse_btn = new QPushButton(tr("Browse")); - color_layout->addWidget(browse_btn, 0, 2); - connect(browse_btn, &QPushButton::clicked, this, &ProjectPropertiesDialog::BrowseForOCIOConfig); - - ocio_filename_->setText(working_project_->color_manager()->GetConfigFilename()); - - connect(ocio_filename_, &QLineEdit::textChanged, this, &ProjectPropertiesDialog::OCIOFilenameUpdated); - OCIOFilenameUpdated(); - - tabs->addTab(color_group, tr("Color Management")); - - color_outer_layout->addStretch(); - } - - { - // Cache group - QWidget* cache_group = new QWidget(); - - QVBoxLayout* cache_layout = new QVBoxLayout(cache_group); - - QButtonGroup* disk_cache_btn_group = new QButtonGroup(); - - disk_cache_use_default_btn_ = new QRadioButton(tr("Use Default Location")); - disk_cache_store_alongside_project_btn_ = new QRadioButton(tr("Store Alongside Project")); - disk_cache_use_custom_btn_ = new QRadioButton(tr("Use Custom Location:")); - - disk_cache_btn_group->addButton(disk_cache_use_default_btn_); - disk_cache_btn_group->addButton(disk_cache_store_alongside_project_btn_); - disk_cache_btn_group->addButton(disk_cache_use_custom_btn_); - - cache_layout->addWidget(disk_cache_use_default_btn_); - cache_layout->addWidget(disk_cache_store_alongside_project_btn_); - cache_layout->addWidget(disk_cache_use_custom_btn_); - - cache_path_ = new PathWidget(working_project_->cache_path(false), this); - cache_path_->setEnabled(false); - cache_layout->addWidget(cache_path_); - - connect(disk_cache_use_custom_btn_, &QRadioButton::toggled, cache_path_, &PathWidget::setEnabled); - - if (working_project_->cache_path(false).isEmpty()) { - disk_cache_use_default_btn_->setChecked(true); - } else { - disk_cache_use_custom_btn_->setChecked(true); - } - - cache_layout->addWidget(cache_path_); - - QPushButton* disk_cache_settings_btn = new QPushButton(tr("Disk Cache Settings")); - connect(disk_cache_settings_btn, &QPushButton::clicked, this, [this](){ - if (disk_cache_use_default_btn_->isChecked()) { - DiskManager::instance()->ShowDiskCacheSettingsDialog(DiskManager::instance()->GetDefaultCacheFolder(), this); - } else if (disk_cache_store_alongside_project_btn_->isChecked()) { - // FIXME: - QMessageBox::information(this, QString(), tr("\"Store alignside project\" functionality not implemented yet")); - } else { - DiskManager::instance()->ShowDiskCacheSettingsDialog(cache_path_->text(), this); - } - }); - cache_layout->addWidget(disk_cache_settings_btn); - - tabs->addTab(cache_group, tr("Disk Cache")); - } - - QDialogButtonBox* dialog_btns = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, - Qt::Horizontal); - layout->addWidget(dialog_btns); - connect(dialog_btns, &QDialogButtonBox::accepted, this, &ProjectPropertiesDialog::accept); - connect(dialog_btns, &QDialogButtonBox::rejected, this, &ProjectPropertiesDialog::reject); -} - -void ProjectPropertiesDialog::accept() -{ - if (!ocio_config_is_valid_) { - QMessageBox mb(this); - mb.setWindowModality(Qt::WindowModal); - mb.setIcon(QMessageBox::Critical); - mb.setWindowTitle(tr("OpenColorIO Config Error")); - mb.setText(tr("Failed to set OpenColorIO configuration: %1").arg(ocio_config_error_)); - mb.addButton(QMessageBox::Ok); - mb.exec(); - return; - } - - QString new_cache_path; - - if (disk_cache_use_default_btn_->isChecked()) { - // Keep new cache path empty, which means default - } else if (disk_cache_store_alongside_project_btn_->isChecked()) { - // FIXME: - QMessageBox::information(this, QString(), tr("\"Store alignside project\" functionality not implemented yet")); - return; - } else { - if (!FileFunctions::DirectoryIsValid(cache_path_->text(), true)) { - QMessageBox mb(this); - mb.setWindowModality(Qt::WindowModal); - mb.setIcon(QMessageBox::Critical); - mb.setWindowTitle(tr("Invalid path")); - mb.setText(tr("The cache path is invalid. Please check it and try again.")); - mb.addButton(QMessageBox::Ok); - mb.exec(); - return; - } - - // Set new path to the text as entered - new_cache_path = cache_path_->text(); - } - - if (new_cache_path != working_project_->cache_path(false)) { - // Check if the user is okay with invalidating the current cache - if (!DiskManager::ShowDiskCacheChangeConfirmationDialog(this)) { - return; - } - - working_project_->set_cache_path(new_cache_path); - - emit DiskManager::instance()->InvalidateProject(working_project_); - } - - // This should ripple changes throughout the program that the color config has changed, therefore must be done last - ColorManager* color_manager = working_project_->color_manager(); - - color_manager->SetConfigFilename(ocio_filename_->text()); - color_manager->SetDefaultInputColorSpace(default_input_colorspace_->currentText()); - - QDialog::accept(); -} - -void ProjectPropertiesDialog::BrowseForOCIOConfig() -{ - QString fn = QFileDialog::getOpenFileName(this, tr("Browse for OpenColorIO configuration")); - if (!fn.isEmpty()) { - ocio_filename_->setText(fn); - } -} - -void ProjectPropertiesDialog::OCIOFilenameUpdated() -{ - default_input_colorspace_->clear(); - - try { - OCIO::ConstConfigRcPtr c; - - if (ocio_filename_->text().isEmpty()) { - c = ColorManager::GetDefaultConfig(); - } else { - c = ColorManager::CreateConfigFromFile(ocio_filename_->text()); - } - - ocio_filename_->setStyleSheet(QString()); - ocio_config_is_valid_ = true; - - // List input color spaces - QStringList input_cs = ColorManager::ListAvailableColorspaces(c); - - foreach (QString cs, input_cs) { - default_input_colorspace_->addItem(cs); - - if (cs == working_project_->color_manager()->GetDefaultInputColorSpace()) { - default_input_colorspace_->setCurrentIndex(default_input_colorspace_->count()-1); - } - } - } catch (OCIO::Exception& e) { - ocio_config_is_valid_ = false; - ocio_filename_->setStyleSheet(QStringLiteral("QLineEdit {color: red;}")); - ocio_config_error_ = e.what(); - } -} - -} diff --git a/app/dialog/projectproperties/projectproperties.h b/app/dialog/projectproperties/projectproperties.h deleted file mode 100644 index e861004b8..000000000 --- a/app/dialog/projectproperties/projectproperties.h +++ /dev/null @@ -1,73 +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 . - -***/ - -#ifndef PROJECTPROPERTIESDIALOG_H -#define PROJECTPROPERTIESDIALOG_H - -#include -#include -#include -#include -#include -#include - -#include "project/project.h" -#include "widget/path/pathwidget.h" - -namespace olive { - -class ProjectPropertiesDialog : public QDialog -{ - Q_OBJECT -public: - ProjectPropertiesDialog(Project *p, QWidget* parent); - -public slots: - virtual void accept() override; - -private: - Project* working_project_; - - QLineEdit* ocio_filename_; - - QComboBox* default_input_colorspace_; - - bool ocio_config_is_valid_; - - QString ocio_config_error_; - - PathWidget* cache_path_; - - QRadioButton* disk_cache_use_default_btn_; - - QRadioButton* disk_cache_store_alongside_project_btn_; - - QRadioButton* disk_cache_use_custom_btn_; - -private slots: - void BrowseForOCIOConfig(); - - void OCIOFilenameUpdated(); - -}; - -} - -#endif // PROJECTPROPERTIESDIALOG_H diff --git a/app/dialog/sequence/sequencedialogparametertab.cpp b/app/dialog/sequence/sequencedialogparametertab.cpp index 11ea7ea71..96bbd2dd4 100644 --- a/app/dialog/sequence/sequencedialogparametertab.cpp +++ b/app/dialog/sequence/sequencedialogparametertab.cpp @@ -19,32 +19,11 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg // 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:")), row, 0); - video_width_field_ = new IntegerSlider(); - video_width_field_->SetMinimum(1); - video_width_field_->SetMaximum(99999); - connect(video_width_field_, &IntegerSlider::ValueChanged, this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel); - video_layout->addWidget(video_width_field_, row, 1); - row++; - video_layout->addWidget(new QLabel(tr("Height:")), row, 0); - video_height_field_ = new IntegerSlider(); - video_height_field_->SetMinimum(1); - video_height_field_->SetMaximum(99999); - connect(video_height_field_, &IntegerSlider::ValueChanged, this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel); - video_layout->addWidget(video_height_field_, row, 1); - row++; - video_layout->addWidget(new QLabel(tr("Frame Rate:")), row, 0); - video_frame_rate_field_ = new FrameRateComboBox(); - video_layout->addWidget(video_frame_rate_field_, row, 1); - row++; - video_layout->addWidget(new QLabel(tr("Pixel Aspect Ratio:")), row, 0); - video_pixel_aspect_field_ = new PixelAspectRatioComboBox(); - video_layout->addWidget(video_pixel_aspect_field_, row, 1); - row++; - video_layout->addWidget(new QLabel(tr("Interlacing:"))); - video_interlaced_field_ = new InterlacedComboBox(); - video_layout->addWidget(video_interlaced_field_, row, 1); + QHBoxLayout* video_layout = new QHBoxLayout(video_group); + video_section_ = new VideoParamEdit(); + video_section_->SetParameterMask(Sequence::kVideoParamEditMask); + connect(video_section_, &VideoParamEdit::Changed, this, &SequenceDialogParameterTab::UpdatePreviewResolutionLabel); + video_layout->addWidget(video_section_); layout->addWidget(video_group); row = 0; @@ -80,11 +59,7 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg layout->addWidget(preview_group); // Set values based on input sequence - video_width_field_->SetValue(sequence->video_params().width()); - video_height_field_->SetValue(sequence->video_params().height()); - video_frame_rate_field_->SetFrameRate(sequence->video_params().time_base().flipped()); - video_pixel_aspect_field_->SetPixelAspectRatio(sequence->video_params().pixel_aspect_ratio()); - video_interlaced_field_->SetInterlaceMode(sequence->video_params().interlacing()); + video_section_->SetVideoParams(sequence->video_params()); preview_resolution_field_->SetDivider(sequence->video_params().divider()); preview_format_field_->SetPixelFormat(sequence->video_params().format()); audio_sample_rate_field_->SetSampleRate(sequence->audio_params().sample_rate()); @@ -104,11 +79,11 @@ SequenceDialogParameterTab::SequenceDialogParameterTab(Sequence* sequence, QWidg void SequenceDialogParameterTab::PresetChanged(const SequencePreset &preset) { - video_width_field_->SetValue(preset.width()); - video_height_field_->SetValue(preset.height()); - video_frame_rate_field_->SetFrameRate(preset.frame_rate()); - video_pixel_aspect_field_->SetPixelAspectRatio(preset.pixel_aspect()); - video_interlaced_field_->SetInterlaceMode(preset.interlacing()); + video_section_->SetWidth(preset.width()); + video_section_->SetHeight(preset.height()); + video_section_->SetFrameRate(preset.frame_rate()); + video_section_->SetPixelAspectRatio(preset.pixel_aspect()); + video_section_->SetInterlaceMode(preset.interlacing()); audio_sample_rate_field_->SetSampleRate(preset.sample_rate()); audio_channels_field_->SetChannelLayout(preset.channel_layout()); preview_resolution_field_->SetDivider(preset.preview_divider()); @@ -131,8 +106,8 @@ void SequenceDialogParameterTab::SavePresetClicked() void SequenceDialogParameterTab::UpdatePreviewResolutionLabel() { - VideoParams test_param(video_width_field_->GetValue(), - video_height_field_->GetValue(), + VideoParams test_param(video_section_->GetWidth(), + video_section_->GetHeight(), VideoParams::kFormatInvalid, VideoParams::kInternalChannelCount, rational(1), diff --git a/app/dialog/sequence/sequencedialogparametertab.h b/app/dialog/sequence/sequencedialogparametertab.h index dcc1a4b4e..10c38cd7d 100644 --- a/app/dialog/sequence/sequencedialogparametertab.h +++ b/app/dialog/sequence/sequencedialogparametertab.h @@ -9,6 +9,7 @@ #include "sequencepreset.h" #include "widget/slider/integerslider.h" #include "widget/standardcombos/standardcombos.h" +#include "widget/videoparamedit/videoparamedit.h" namespace olive { @@ -20,27 +21,27 @@ public: int GetSelectedVideoWidth() const { - return video_width_field_->GetValue(); + return video_section_->GetWidth(); } int GetSelectedVideoHeight() const { - return video_height_field_->GetValue(); + return video_section_->GetHeight(); } rational GetSelectedVideoFrameRate() const { - return video_frame_rate_field_->GetFrameRate(); + return video_section_->GetFrameRate(); } rational GetSelectedVideoPixelAspect() const { - return video_pixel_aspect_field_->GetPixelAspectRatio(); + return video_section_->GetPixelAspectRatio(); } VideoParams::Interlacing GetSelectedVideoInterlacingMode() const { - return video_interlaced_field_->GetInterlaceMode(); + return video_section_->GetInterlaceMode(); } int GetSelectedAudioSampleRate() const @@ -70,15 +71,7 @@ signals: void SaveParametersAsPreset(const SequencePreset& preset); private: - IntegerSlider* video_width_field_; - - IntegerSlider* video_height_field_; - - FrameRateComboBox* video_frame_rate_field_; - - PixelAspectRatioComboBox* video_pixel_aspect_field_; - - InterlacedComboBox* video_interlaced_field_; + VideoParamEdit* video_section_; SampleRateComboBox* audio_sample_rate_field_; diff --git a/app/node/CMakeLists.txt b/app/node/CMakeLists.txt index 640b4466c..6b5b0e5fa 100644 --- a/app/node/CMakeLists.txt +++ b/app/node/CMakeLists.txt @@ -22,6 +22,7 @@ add_subdirectory(generator) add_subdirectory(input) add_subdirectory(math) add_subdirectory(output) +add_subdirectory(project) set(OLIVE_SOURCES ${OLIVE_SOURCES} diff --git a/app/node/graph.h b/app/node/graph.h index 64fb9b995..e2f23fb14 100644 --- a/app/node/graph.h +++ b/app/node/graph.h @@ -54,6 +54,11 @@ public: return node_children_; } + const QVector& default_nodes() const + { + return default_nodes_; + } + signals: /** * @brief Signal emitted when a Node is added to the graph @@ -72,11 +77,18 @@ signals: void ValueChanged(const NodeInput& input); protected: + void AddDefaultNode(Node* n) + { + default_nodes_.append(n); + } + virtual void childEvent(QChildEvent* event) override; private: QVector node_children_; + QVector default_nodes_; + }; } diff --git a/app/dialog/projectproperties/CMakeLists.txt b/app/node/project/CMakeLists.txt similarity index 88% rename from app/dialog/projectproperties/CMakeLists.txt rename to app/node/project/CMakeLists.txt index b45092bf6..efc953c4e 100644 --- a/app/dialog/projectproperties/CMakeLists.txt +++ b/app/node/project/CMakeLists.txt @@ -14,9 +14,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +add_subdirectory(projectsettings) + set(OLIVE_SOURCES ${OLIVE_SOURCES} - dialog/projectproperties/projectproperties.h - dialog/projectproperties/projectproperties.cpp PARENT_SCOPE ) diff --git a/app/node/project/projectsettings/CMakeLists.txt b/app/node/project/projectsettings/CMakeLists.txt new file mode 100644 index 000000000..9228fa2fd --- /dev/null +++ b/app/node/project/projectsettings/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + node/project/projectsettings/projectsettings.cpp + node/project/projectsettings/projectsettings.h + PARENT_SCOPE +) diff --git a/app/node/project/projectsettings/projectsettings.cpp b/app/node/project/projectsettings/projectsettings.cpp new file mode 100644 index 000000000..f82419092 --- /dev/null +++ b/app/node/project/projectsettings/projectsettings.cpp @@ -0,0 +1,60 @@ +/*** + + 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 . + +***/ + +#include "projectsettings.h" + +namespace olive { + +const QString ProjectSettingsNode::kCacheSetting = QStringLiteral("cache_setting"); +const QString ProjectSettingsNode::kCachePath = QStringLiteral("cache_path"); + +ProjectSettingsNode::ProjectSettingsNode() +{ + AddInput(kCacheSetting, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + + AddInput(kCachePath, NodeValue::kFile, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + SetInputProperty(kCachePath, QStringLiteral("directory"), true); + UpdateCachePathEnabled(); +} + +void ProjectSettingsNode::Retranslate() +{ + SetInputName(kCacheSetting, tr("Disk Cache Location")); + SetInputName(kCachePath, tr("Disk Cache Path")); + SetComboBoxStrings(kCacheSetting, {tr("Use Default Location"), tr("Store Alongside Project"), tr("Use Custom Location")}); + SetInputProperty(kCachePath, QStringLiteral("placeholder"), tr("(default)")); +} + +void ProjectSettingsNode::InputValueChangedEvent(const QString &input, int element) +{ + Q_UNUSED(element) + + if (input == kCacheSetting) { + UpdateCachePathEnabled(); + } +} + +void ProjectSettingsNode::UpdateCachePathEnabled() +{ + CacheSetting setting = GetCacheSetting(); + SetInputProperty(kCachePath, QStringLiteral("enabled"), (setting == kCacheCustomPath)); +} + +} diff --git a/app/node/project/projectsettings/projectsettings.h b/app/node/project/projectsettings/projectsettings.h new file mode 100644 index 000000000..4d83677ba --- /dev/null +++ b/app/node/project/projectsettings/projectsettings.h @@ -0,0 +1,95 @@ +/*** + + 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 . + +***/ + +#ifndef PROJECTSETTINGSNODE_H +#define PROJECTSETTINGSNODE_H + +#include "node/node.h" + +namespace olive { + +class ProjectSettingsNode : public Node +{ + Q_OBJECT +public: + ProjectSettingsNode(); + + virtual QString Name() const override + { + return tr("Project Settings"); + } + + virtual QString id() const override + { + return QStringLiteral("org.olivevideoeditor.Olive.projectsettings"); + } + + virtual QVector Category() const override + { + return {kCategoryProject}; + } + + virtual QString Description() const override + { + return tr("Settings used throughout the project."); + } + + virtual Node* copy() const override + { + return new ProjectSettingsNode(); + } + + enum CacheSetting { + kCacheUseDefaultLocation, + kCacheStoreAlongsideProject, + kCacheCustomPath + }; + + static const QString kCacheSetting; + static const QString kCachePath; + + virtual void Retranslate() override; + + CacheSetting GetCacheSetting() const + { + return static_cast(GetStandardValue(kCacheSetting).toInt()); + } + + QString GetCustomCachePath() const + { + return GetStandardValue(kCachePath).toString(); + } + + void SetCustomCachePath(const QString& s) + { + SetStandardValue(kCachePath, s); + } + +protected: + virtual void InputValueChangedEvent(const QString &input, int element) override; + +private: + void UpdateCachePathEnabled(); + +}; + +} + +#endif // PROJECTSETTINGSNODE_H diff --git a/app/project/item/footage/footage.cpp b/app/project/item/footage/footage.cpp index 1381ded5b..5e68581b3 100644 --- a/app/project/item/footage/footage.cpp +++ b/app/project/item/footage/footage.cpp @@ -31,6 +31,7 @@ #include "core.h" #include "render/job/footagejob.h" #include "ui/icons/icons.h" +#include "widget/videoparamedit/videoparamedit.h" namespace olive { @@ -645,9 +646,43 @@ void Footage::AddStreamAsInput(Stream::Type type, int index, QVariant value) StreamReference ref(type, index); // Create input for parameters - AddInput(input_id, type == Stream::kVideo ? NodeValue::kVideoParams : NodeValue::kAudioParams, + NodeValue::Type value_type; + uint64_t param_mask = 0; + + if (type == Stream::kVideo) { + VideoParams vp = value.value(); + value_type = NodeValue::kVideoParams; + + // Universal parameters for video/image footage + param_mask |= VideoParamEdit::kEnabled; + param_mask |= VideoParamEdit::kColorspace; + param_mask |= VideoParamEdit::kPixelAspect; + param_mask |= VideoParamEdit::kInterlacing; + + if (vp.channel_count() == VideoParams::kRGBAChannelCount) { + // If this has an alpha channel, add a premultiplied optino + param_mask |= VideoParamEdit::kPremultipliedAlpha; + } + + if (vp.video_type() != VideoParams::kVideoTypeVideo) { + // This is either a still image or an image sequence, add properties for those + param_mask |= VideoParamEdit::kIsImageSequence; + param_mask |= VideoParamEdit::kStartTime; + param_mask |= VideoParamEdit::kEndTime; + param_mask |= VideoParamEdit::kFrameRate; + } else { + // Ensure timebase isn't overwritten by the frame rate field + param_mask |= VideoParamEdit::kFrameRateIsNotTimebase; + } + } else { + value_type = NodeValue::kAudioParams; + param_mask = 0; + } + + AddInput(input_id, value_type, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); SetStandardValue(input_id, value); + SetInputProperty(input_id, QStringLiteral("mask"), QVariant::fromValue(param_mask)); inputs_for_stream_properties_.insert(ref, input_id); // Create output for stream diff --git a/app/project/item/sequence/sequence.cpp b/app/project/item/sequence/sequence.cpp index 56f81d86d..aea03c4d8 100644 --- a/app/project/item/sequence/sequence.cpp +++ b/app/project/item/sequence/sequence.cpp @@ -34,6 +34,7 @@ #include "panel/timeline/timeline.h" #include "panel/sequenceviewer/sequenceviewer.h" #include "ui/icons/icons.h" +#include "widget/videoparamedit/videoparamedit.h" namespace olive { @@ -43,6 +44,8 @@ const QString Sequence::kTextureInput = QStringLiteral("tex_in"); const QString Sequence::kSamplesInput = QStringLiteral("samples_in"); const QString Sequence::kTrackInputFormat = QStringLiteral("track_in_%1"); +const uint64_t Sequence::kVideoParamEditMask = VideoParamEdit::kWidthHeight | VideoParamEdit::kInterlacing | VideoParamEdit::kFrameRate | VideoParamEdit::kPixelAspect; + #define super Item Sequence::Sequence(bool viewer_only_mode) : @@ -52,6 +55,8 @@ Sequence::Sequence(bool viewer_only_mode) : operation_stack_(0) { AddInput(kVideoParamsInput, NodeValue::kVideoParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + SetInputProperty(kVideoParamsInput, QStringLiteral("mask"), QVariant::fromValue(kVideoParamEditMask)); + AddInput(kAudioParamsInput, NodeValue::kAudioParams, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); AddInput(kTextureInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); diff --git a/app/project/item/sequence/sequence.h b/app/project/item/sequence/sequence.h index 30d22c31e..7b16fd583 100644 --- a/app/project/item/sequence/sequence.h +++ b/app/project/item/sequence/sequence.h @@ -161,6 +161,8 @@ public: static const QString kSamplesInput; static const QString kTrackInputFormat; + static const uint64_t kVideoParamEditMask; + TimelinePoints* timeline_points() { return &timeline_points_; diff --git a/app/project/project.cpp b/app/project/project.cpp index b4df36707..74ed46e58 100644 --- a/app/project/project.cpp +++ b/app/project/project.cpp @@ -39,6 +39,12 @@ Project::Project() : // Adds a color manager "node" to this project so that it synchronizes color_manager_ = new ColorManager(); color_manager_->setParent(this); + AddDefaultNode(color_manager_); + + // Same with project settings + settings_ = new ProjectSettingsNode(); + settings_->setParent(this); + AddDefaultNode(settings_); // Folder root for project root_ = new Folder(); @@ -58,10 +64,6 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint root_->Load(reader, xml_node_data, version, cancelled); - } else if (reader->name() == QStringLiteral("cachepath")) { - - set_cache_path(reader->readElementText()); - } else if (reader->name() == QStringLiteral("layout")) { // Since the main window's functions have to occur in the GUI thread (and we're likely @@ -76,6 +78,8 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint while (XMLReadNextStartElement(reader)) { if (reader->name() == QStringLiteral("node")) { bool is_root = false; + bool is_cm = false; + bool is_settings = false; QString id; { @@ -84,6 +88,10 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint id = attr.value().toString(); } else if (attr.name() == QStringLiteral("root") && attr.value() == QStringLiteral("1")) { is_root = true; + } else if (attr.name() == QStringLiteral("cm") && attr.value() == QStringLiteral("1")) { + is_cm = true; + } else if (attr.name() == QStringLiteral("settings") && attr.value() == QStringLiteral("1")) { + is_settings = true; } } } @@ -95,6 +103,10 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint if (is_root) { node = root_; + } else if (is_cm) { + node = color_manager_; + } else if (is_settings) { + node = settings_; } else { node = NodeFactory::CreateFromID(id); } @@ -128,8 +140,6 @@ void Project::Load(QXmlStreamReader *reader, MainWindowLayoutInfo* layout, uint void Project::Save(QXmlStreamWriter *writer) const { - writer->writeTextElement(QStringLiteral("cachepath"), cache_path(false)); - writer->writeStartElement(QStringLiteral("nodes")); foreach (Node* node, nodes()) { @@ -137,6 +147,10 @@ void Project::Save(QXmlStreamWriter *writer) const if (node == root_) { writer->writeAttribute(QStringLiteral("root"), QStringLiteral("1")); + } else if (node == color_manager_) { + writer->writeAttribute(QStringLiteral("cm"), QStringLiteral("1")); + } else if (node == settings_) { + writer->writeAttribute(QStringLiteral("settings"), QStringLiteral("1")); } writer->writeAttribute(QStringLiteral("id"), node->id()); @@ -228,12 +242,32 @@ bool Project::is_new() const return !is_modified_ && filename_.isEmpty(); } -const QString &Project::cache_path(bool default_if_empty) const +QString Project::cache_path() const { - if (cache_path_.isEmpty() && default_if_empty) { - return DiskManager::instance()->GetDefaultCachePath(); + ProjectSettingsNode::CacheSetting setting = settings_->GetCacheSetting(); + + switch (setting) { + case ProjectSettingsNode::kCacheUseDefaultLocation: + break; + case ProjectSettingsNode::kCacheCustomPath: + { + QString cache_path = settings_->GetCustomCachePath(); + + if (cache_path.isEmpty()) { + return cache_path; + } + break; } - return cache_path_; + case ProjectSettingsNode::kCacheStoreAlongsideProject: + { + if (!filename_.isEmpty()) { + return QFileInfo(filename_).path(); + } + break; + } + } + + return DiskManager::instance()->GetDefaultCachePath(); } void Project::ColorManagerValueChanged(const NodeInput &input, const TimeRange &range) diff --git a/app/project/project.h b/app/project/project.h index cfa5cbf3d..eeac418f3 100644 --- a/app/project/project.h +++ b/app/project/project.h @@ -24,6 +24,7 @@ #include #include +#include "node/project/projectsettings/projectsettings.h" #include "render/colormanager.h" #include "project/item/folder/folder.h" #include "window/mainwindow/mainwindowlayoutinfo.h" @@ -69,22 +70,13 @@ public: bool is_new() const; - const QString& cache_path(bool default_if_empty = true) const; - - void set_cache_path(const QString& cache_path) - { - cache_path_ = cache_path; - - emit CachePathChanged(cache_path_); - } + QString cache_path() const; signals: void NameChanged(); void ModifiedChanged(bool e); - void CachePathChanged(const QString& s); - private: Folder* root_; @@ -92,12 +84,12 @@ private: ColorManager* color_manager_; + ProjectSettingsNode* settings_; + bool is_modified_; bool autorecovery_saved_; - QString cache_path_; - private slots: void ColorManagerValueChanged(const NodeInput& input, const TimeRange& range); diff --git a/app/render/colormanager.cpp b/app/render/colormanager.cpp index c3a84d8a7..10f2609bb 100644 --- a/app/render/colormanager.cpp +++ b/app/render/colormanager.cpp @@ -47,7 +47,7 @@ ColorManager::ColorManager() : AddInput(kDefaultColorspaceIn, NodeValue::kCombo, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); // Default reference space is scene linear - AddInput(kReferenceSpaceIn, NodeValue::kText, OCIO::ROLE_SCENE_LINEAR, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); + AddInput(kReferenceSpaceIn, NodeValue::kCombo, 0, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); // Set config to our built-in default SetConfig(GetDefaultConfig()); @@ -176,12 +176,13 @@ void ColorManager::SetDefaultInputColorSpace(const QString &s) QString ColorManager::GetReferenceColorSpace() const { - return GetStandardValue(kReferenceSpaceIn).toString(); -} + ReferenceSpace ref_space = static_cast(GetStandardValue(kReferenceSpaceIn).toInt()); -void ColorManager::SetReferenceColorSpace(const QString &s) -{ - SetStandardValue(kReferenceSpaceIn, s); + if (ref_space == kCompositingLog) { + return OCIO::ROLE_COMPOSITING_LOG; + } else { + return OCIO::ROLE_SCENE_LINEAR; + } } QString ColorManager::GetCompliantColorSpace(const QString &s) @@ -267,6 +268,9 @@ void ColorManager::Retranslate() SetInputName(kConfigFilenameIn, tr("Configuration")); SetInputName(kDefaultColorspaceIn, tr("Default Input")); SetInputName(kReferenceSpaceIn, tr("Reference Space")); + + SetComboBoxStrings(kReferenceSpaceIn, {tr("Scene Linear"), tr("Compositing Log")}); + SetInputProperty(kConfigFilenameIn, QStringLiteral("placeholder"), tr("(built-in)")); } void ColorManager::InputValueChangedEvent(const QString &input, int element) diff --git a/app/render/colormanager.h b/app/render/colormanager.h index 837bacc13..d07f543a7 100644 --- a/app/render/colormanager.h +++ b/app/render/colormanager.h @@ -93,8 +93,6 @@ public: QString GetReferenceColorSpace() const; - void SetReferenceColorSpace(const QString& s); - QString GetCompliantColorSpace(const QString& s); ColorTransform GetCompliantColorSpace(const ColorTransform& transform, bool force_display = false); @@ -131,6 +129,11 @@ protected: virtual void InputValueChangedEvent(const QString &input, int element) override; private: + enum ReferenceSpace { + kSceneLinear, + kCompositingLog + }; + void SetConfig(OCIO::ConstConfigRcPtr config); OCIO::ConstConfigRcPtr config_; diff --git a/app/render/videoparams.cpp b/app/render/videoparams.cpp index 66adb10ae..4dd95c2e8 100644 --- a/app/render/videoparams.cpp +++ b/app/render/videoparams.cpp @@ -76,7 +76,7 @@ VideoParams::VideoParams() : VideoParams::VideoParams(int width, int height, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) : width_(width), height_(height), - depth_(0), + depth_(1), format_(format), channel_count_(nb_channels), pixel_aspect_ratio_(pixel_aspect_ratio), @@ -106,7 +106,7 @@ VideoParams::VideoParams(int width, int height, int depth, Format format, int nb VideoParams::VideoParams(int width, int height, const rational &time_base, Format format, int nb_channels, const rational& pixel_aspect_ratio, Interlacing interlacing, int divider) : width_(width), height_(height), - depth_(0), + depth_(1), time_base_(time_base), format_(format), channel_count_(nb_channels), diff --git a/app/widget/CMakeLists.txt b/app/widget/CMakeLists.txt index ea219e3ca..1e8a0e945 100644 --- a/app/widget/CMakeLists.txt +++ b/app/widget/CMakeLists.txt @@ -50,6 +50,7 @@ add_subdirectory(timelinewidget) add_subdirectory(timeruler) add_subdirectory(timetarget) add_subdirectory(toolbar) +add_subdirectory(videoparamedit) add_subdirectory(viewer) set(OLIVE_SOURCES diff --git a/app/widget/filefield/filefield.cpp b/app/widget/filefield/filefield.cpp index 222bd6a7b..ab8269836 100644 --- a/app/widget/filefield/filefield.cpp +++ b/app/widget/filefield/filefield.cpp @@ -29,15 +29,16 @@ namespace olive { FileField::FileField(QWidget* parent) : - QWidget(parent) + QWidget(parent), + directory_mode_(false) { QHBoxLayout* layout = new QHBoxLayout(this); - layout->setSpacing(0); layout->setMargin(0); line_edit_ = new QLineEdit(); connect(line_edit_, &QLineEdit::textChanged, this, &FileField::LineEditChanged); + connect(line_edit_, &QLineEdit::textEdited, this, &FileField::FilenameChanged); layout->addWidget(line_edit_); browse_btn_ = new QPushButton(); @@ -48,22 +49,27 @@ FileField::FileField(QWidget* parent) : void FileField::BrowseBtnClicked() { - QString s = QFileDialog::getOpenFileName(this, tr("Open File")); + QString s; + + if (directory_mode_) { + s = QFileDialog::getExistingDirectory(this, tr("Open Directory")); + } else { + s = QFileDialog::getOpenFileName(this, tr("Open File")); + } if (!s.isEmpty()) { line_edit_->setText(s); + emit FilenameChanged(s); } } void FileField::LineEditChanged(const QString& text) { - if (QFileInfo::exists(text)) { + if (QFileInfo::exists(text) || text.isEmpty()) { line_edit_->setStyleSheet(QString()); } else { line_edit_->setStyleSheet(QStringLiteral("QLineEdit {color: red;}")); } - - emit FilenameChanged(text); } } diff --git a/app/widget/filefield/filefield.h b/app/widget/filefield/filefield.h index 0c7368f8b..8489ef514 100644 --- a/app/widget/filefield/filefield.h +++ b/app/widget/filefield/filefield.h @@ -42,6 +42,16 @@ public: line_edit_->setText(s); } + void SetPlaceholder(const QString& s) + { + line_edit_->setPlaceholderText(s); + } + + void SetDirectoryMode(bool e) + { + directory_mode_ = e; + } + signals: void FilenameChanged(const QString& filename); @@ -50,6 +60,8 @@ private: QPushButton* browse_btn_; + bool directory_mode_; + private slots: void BrowseBtnClicked(); diff --git a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp index e89753534..55a6ff90e 100644 --- a/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp +++ b/app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp @@ -37,6 +37,7 @@ #include "widget/filefield/filefield.h" #include "widget/slider/floatslider.h" #include "widget/slider/integerslider.h" +#include "widget/videoparamedit/videoparamedit.h" namespace olive { @@ -81,8 +82,6 @@ void NodeParamViewWidgetBridge::CreateWidgets() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: - case NodeValue::kVideoParams: - case NodeValue::kAudioParams: break; case NodeValue::kInt: { @@ -131,7 +130,6 @@ void NodeParamViewWidgetBridge::CreateWidgets() } case NodeValue::kColor: { - // NOTE: Very convoluted way to get back to the project's color manager ColorButton* color_button = new ColorButton(input_.node()->project()->color_manager()); widgets_.append(color_button); connect(color_button, &ColorButton::ColorChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); @@ -158,6 +156,19 @@ void NodeParamViewWidgetBridge::CreateWidgets() connect(font_combobox, &QFontComboBox::currentFontChanged, this, &NodeParamViewWidgetBridge::WidgetCallback); break; } + case NodeValue::kVideoParams: + { + VideoParamEdit* edit = new VideoParamEdit(); + edit->SetColorManager(input_.node()->project()->color_manager()); + widgets_.append(edit); + connect(edit, &VideoParamEdit::Changed, this, &NodeParamViewWidgetBridge::WidgetCallback); + break; + } + case NodeValue::kAudioParams: + { + // FIXME: Create audio param widget + break; + } } // Check all properties @@ -252,8 +263,6 @@ void NodeParamViewWidgetBridge::WidgetCallback() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: - case NodeValue::kVideoParams: - case NodeValue::kAudioParams: break; case NodeValue::kInt: { @@ -367,6 +376,15 @@ void NodeParamViewWidgetBridge::WidgetCallback() SetInputValue(index, 0); break; } + case NodeValue::kVideoParams: + { + VideoParamEdit* edit = static_cast(sender()); + SetInputValue(QVariant::fromValue(edit->GetVideoParams()), 0); + break; + } + case NodeValue::kAudioParams: + // FIXME: No audio param widget yet + break; } } @@ -402,8 +420,6 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() case NodeValue::kShaderJob: case NodeValue::kSampleJob: case NodeValue::kGenerateJob: - case NodeValue::kVideoParams: - case NodeValue::kAudioParams: break; case NodeValue::kInt: { @@ -452,9 +468,7 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() case NodeValue::kFile: { FileField* ff = static_cast(widgets_.first()); - ff->blockSignals(true); ff->SetFilename(input_.GetValueAtTime(node_time).toString()); - ff->blockSignals(false); break; } case NodeValue::kColor: @@ -497,6 +511,15 @@ void NodeParamViewWidgetBridge::UpdateWidgetValues() cb->blockSignals(false); break; } + case NodeValue::kVideoParams: + { + VideoParamEdit* edit = static_cast(widgets_.first()); + edit->SetVideoParams(input_.GetValueAtTime(node_time).value()); + break; + } + case NodeValue::kAudioParams: + // FIXME: No audio param widget + break; } } @@ -523,6 +546,13 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString& input, const QStr NodeValue::Type data_type = input_.GetDataType(); + // Parameters for all types + if (key == QStringLiteral("enabled")) { + foreach (QWidget* w, widgets_) { + w->setEnabled(value.toBool()); + } + } + // Parameters for vectors only if (NodeValue::type_is_vector(data_type)) { if (key == QStringLiteral("disablex")) { @@ -672,6 +702,26 @@ void NodeParamViewWidgetBridge::PropertyChanged(const QString& input, const QStr } } } + + // Parameters for files + if (data_type == NodeValue::kFile) { + FileField* ff = static_cast(widgets_.first()); + + if (key == QStringLiteral("placeholder")) { + ff->SetPlaceholder(value.toString()); + } else if (key == QStringLiteral("directory")) { + ff->SetDirectoryMode(value.toBool()); + } + } + + // Parameters for video param objects + if (data_type == NodeValue::kVideoParams) { + VideoParamEdit* edit = static_cast(widgets_.first()); + + if (key == QStringLiteral("mask")) { + edit->SetParameterMask(value.toULongLong()); + } + } } bool NodeParamViewScrollBlocker::eventFilter(QObject *watched, QEvent *event) diff --git a/app/widget/projectexplorer/projectexplorer.cpp b/app/widget/projectexplorer/projectexplorer.cpp index f14770fb2..f8b179fb4 100644 --- a/app/widget/projectexplorer/projectexplorer.cpp +++ b/app/widget/projectexplorer/projectexplorer.cpp @@ -260,12 +260,6 @@ void ProjectExplorer::ShowContextMenu() // "Import" action QAction* import_action = menu.addAction(tr("&Import...")); connect(import_action, &QAction::triggered, Core::instance(), &Core::DialogImportShow); - - menu.addSeparator(); - - // Project properties action - QAction* project_properties = menu.addAction(tr("&Project Properties...")); - connect(project_properties, &QAction::triggered, Core::instance(), &Core::DialogProjectPropertiesShow); } else { // Actions to add when only one item is selected diff --git a/app/widget/videoparamedit/CMakeLists.txt b/app/widget/videoparamedit/CMakeLists.txt new file mode 100644 index 000000000..c9d90c6fb --- /dev/null +++ b/app/widget/videoparamedit/CMakeLists.txt @@ -0,0 +1,22 @@ +# 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 . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + widget/videoparamedit/videoparamedit.cpp + widget/videoparamedit/videoparamedit.h + PARENT_SCOPE +) diff --git a/app/widget/videoparamedit/videoparamedit.cpp b/app/widget/videoparamedit/videoparamedit.cpp new file mode 100644 index 000000000..8561db5e9 --- /dev/null +++ b/app/widget/videoparamedit/videoparamedit.cpp @@ -0,0 +1,374 @@ +/*** + + 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 . + +***/ + +#include "videoparamedit.h" + +#include + +namespace olive { + +VideoParamEdit::VideoParamEdit(QWidget* parent) : + QWidget(parent), + color_manager_(nullptr), + mask_(0) +{ + QGridLayout* layout = new QGridLayout(this); + + layout->setMargin(0); + + int row = 0; + + // Enabled + enabled_lbl_ = new QLabel(tr("Enabled:")); + layout->addWidget(enabled_lbl_, row, 0); + enabled_box_ = new QCheckBox(); + connect(enabled_box_, &QCheckBox::clicked, this, &VideoParamEdit::Changed); + layout->addWidget(enabled_box_, row, 1); + + row++; + + // Width + width_lbl_ = new QLabel(tr("Width:")); + layout->addWidget(width_lbl_, row, 0); + + width_slider_ = new IntegerSlider(); + width_slider_->SetMinimum(1); + width_slider_->SetMaximum(32768); + connect(width_slider_, &IntegerSlider::ValueChanged, this, &VideoParamEdit::Changed); + layout->addWidget(width_slider_, row, 1); + + row++; + + // Height + height_lbl_ = new QLabel(tr("Height:")); + layout->addWidget(height_lbl_, row, 0); + + height_slider_ = new IntegerSlider(); + height_slider_->SetMinimum(1); + height_slider_->SetMaximum(32768); + connect(height_slider_, &IntegerSlider::ValueChanged, this, &VideoParamEdit::Changed); + layout->addWidget(height_slider_, row, 1); + + row++; + + // Depth + depth_lbl_ = new QLabel(tr("Depth:")); + layout->addWidget(depth_lbl_, row, 0); + + depth_slider_ = new IntegerSlider(); + depth_slider_->SetMinimum(1); + depth_slider_->SetMaximum(32768); + connect(depth_slider_, &IntegerSlider::ValueChanged, this, &VideoParamEdit::Changed); + layout->addWidget(depth_slider_, row, 1); + + row++; + + // Pixel Format + format_lbl_ = new QLabel(tr("Format:")); + layout->addWidget(format_lbl_, row, 0); + format_combobox_ = new PixelFormatComboBox(true); + connect(format_combobox_, static_cast(&PixelFormatComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(format_combobox_, row, 1); + + row++; + + // Frame Rate + frame_rate_lbl_ = new QLabel(tr("Frame Rate:")); + layout->addWidget(frame_rate_lbl_, row, 0); + + frame_rate_combobox_ = new FrameRateComboBox(); + connect(frame_rate_combobox_, static_cast(&FrameRateComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(frame_rate_combobox_, row, 1); + + row++; + + // Pixel Aspect Ratio + pixel_aspect_lbl_ = new QLabel(tr("Pixel Aspect Ratio:")); + layout->addWidget(pixel_aspect_lbl_, row, 0); + + pixel_aspect_combobox_ = new PixelAspectRatioComboBox(); + connect(pixel_aspect_combobox_, static_cast(&PixelAspectRatioComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(pixel_aspect_combobox_, row, 1); + + row++; + + // Interlacing + interlaced_lbl_ = new QLabel(tr("Interlacing:")); + layout->addWidget(interlaced_lbl_, row, 0); + + interlaced_combobox_ = new InterlacedComboBox(); + connect(interlaced_combobox_, static_cast(&InterlacedComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(interlaced_combobox_, row, 1); + + row++; + + // Channel Count + channel_count_lbl_ = new QLabel(tr("Channel Count:")); + layout->addWidget(channel_count_lbl_, row, 0); + + channel_count_combobox_ = new QComboBox(); + channel_count_combobox_->addItem(tr("RGB"), VideoParams::kRGBChannelCount); + channel_count_combobox_->addItem(tr("RGBA"), VideoParams::kRGBAChannelCount); + connect(channel_count_combobox_, static_cast(&QComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(channel_count_combobox_, row, 1); + + row++; + + // Divider + divider_lbl_ = new QLabel(tr("Divider:")); + layout->addWidget(divider_lbl_, row, 0); + + divider_combobox_ = new VideoDividerComboBox(); + connect(divider_combobox_, static_cast(&VideoDividerComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(divider_combobox_, row, 1); + + row++; + + // Stream Index + stream_index_lbl_ = new QLabel(tr("Stream Index:")); + layout->addWidget(stream_index_lbl_, row, 0); + stream_index_slider_ = new IntegerSlider(); + stream_index_slider_->SetMinimum(0); + connect(stream_index_slider_, &IntegerSlider::ValueChanged, this, &VideoParamEdit::Changed); + layout->addWidget(stream_index_slider_, row, 1); + + row++; + + // Video type + video_type_lbl_ = new QLabel(tr("Video Type:")); + layout->addWidget(video_type_lbl_, row, 0); + video_type_combobox_ = new QComboBox(); + video_type_combobox_->addItem(tr("Video"), VideoParams::kVideoTypeVideo); + video_type_combobox_->addItem(tr("Still"), VideoParams::kVideoTypeStill); + video_type_combobox_->addItem(tr("Image Sequence"), VideoParams::kVideoTypeImageSequence); + connect(video_type_combobox_, static_cast(&QComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(video_type_combobox_, row, 1); + + row++; + + // Start time (for image sequences) + start_time_lbl_ = new QLabel(tr("Start Time")); + layout->addWidget(start_time_lbl_, row, 0); + + start_time_slider_ = new IntegerSlider(); + start_time_slider_->SetMinimum(0); + connect(start_time_slider_, &IntegerSlider::ValueChanged, this, &VideoParamEdit::Changed); + layout->addWidget(start_time_slider_, row, 1); + + row++; + + // End time (for image sequences) + end_time_lbl_ = new QLabel(tr("End Time")); + layout->addWidget(end_time_lbl_, row, 0); + + end_time_slider_ = new IntegerSlider(); + end_time_slider_->SetMinimum(0); + connect(end_time_slider_, &IntegerSlider::ValueChanged, this, &VideoParamEdit::Changed); + layout->addWidget(end_time_slider_, row, 1); + + row++; + + // Premultiplied alpha + premultiplied_alpha_lbl_ = new QLabel(tr("Premultiplied Alpha")); + layout->addWidget(premultiplied_alpha_lbl_, row, 0); + + premultiplied_alpha_box_ = new QCheckBox(); + connect(premultiplied_alpha_box_, &QCheckBox::clicked, this, &VideoParamEdit::Changed); + layout->addWidget(premultiplied_alpha_box_, row, 1); + + row++; + + // Colorspace + colorspace_lbl_ = new QLabel(tr("Colorspace")); + layout->addWidget(colorspace_lbl_, row, 0); + + colorspace_combobox_ = new QComboBox(); + connect(colorspace_combobox_, static_cast(&QComboBox::currentIndexChanged), this, &VideoParamEdit::Changed); + layout->addWidget(colorspace_combobox_, row, 1); +} + +void VideoParamEdit::SetParameterMask(uint64_t mask) +{ + width_lbl_->setVisible(mask & kWidthHeight); + width_slider_->setVisible(mask & kWidthHeight); + height_lbl_->setVisible(mask & kWidthHeight); + height_slider_->setVisible(mask & kWidthHeight); + + depth_lbl_->setVisible(mask & kDepth); + depth_slider_->setVisible(mask & kDepth); + + frame_rate_lbl_->setVisible(mask & kFrameRate); + frame_rate_combobox_->setVisible(mask & kFrameRate); + + pixel_aspect_lbl_->setVisible(mask & kPixelAspect); + pixel_aspect_combobox_->setVisible(mask & kPixelAspect); + + interlaced_lbl_->setVisible(mask & kInterlacing); + interlaced_combobox_->setVisible(mask & kInterlacing); + + enabled_lbl_->setVisible(mask & kEnabled); + enabled_box_->setVisible(mask & kEnabled); + + format_lbl_->setVisible(mask & kFormat); + format_combobox_->setVisible(mask & kFormat); + + channel_count_lbl_->setVisible(mask & kChannelCount); + channel_count_combobox_->setVisible(mask & kChannelCount); + + divider_lbl_->setVisible(mask & kDivider); + divider_combobox_->setVisible(mask & kDivider); + + stream_index_lbl_->setVisible(mask & kStreamIndex); + stream_index_slider_->setVisible(mask & kStreamIndex); + + video_type_lbl_->setVisible(mask & kIsImageSequence); + video_type_combobox_->setVisible(mask & kIsImageSequence); + + start_time_lbl_->setVisible(mask & kStartTime); + start_time_slider_->setVisible(mask & kStartTime); + + end_time_lbl_->setVisible(mask & kEndTime); + end_time_slider_->setVisible(mask & kEndTime); + + premultiplied_alpha_lbl_->setVisible(mask & kPremultipliedAlpha); + premultiplied_alpha_box_->setVisible(mask & kPremultipliedAlpha); + + colorspace_lbl_->setVisible(mask & kColorspace); + colorspace_combobox_->setVisible(mask & kColorspace); +} + +VideoParams VideoParamEdit::GetVideoParams() const +{ + VideoParams p; + + p.set_enabled(enabled_box_->isChecked()); + p.set_width(width_slider_->GetValue()); + p.set_height(height_slider_->GetValue()); + p.set_depth(depth_slider_->GetValue()); + + p.set_frame_rate(frame_rate_combobox_->GetFrameRate()); + if (mask_ & kFrameRateIsNotTimebase) { + // Frame rate editor will only edit the frame rate + p.set_time_base(timebase_temp_); + } else { + p.set_time_base(frame_rate_combobox_->GetFrameRate().flipped()); + } + + p.set_pixel_aspect_ratio(pixel_aspect_combobox_->GetPixelAspectRatio()); + p.set_interlacing(interlaced_combobox_->GetInterlaceMode()); + p.set_format(format_combobox_->GetPixelFormat()); + p.set_channel_count(channel_count_combobox_->currentData().toInt()); + p.set_divider(divider_combobox_->GetDivider()); + p.set_stream_index(stream_index_slider_->GetValue()); + p.set_video_type(static_cast(video_type_combobox_->currentData().toInt())); + p.set_start_time(start_time_slider_->GetValue()); + p.set_duration(end_time_slider_->GetValue() - start_time_slider_->GetValue() + 1); + p.set_premultiplied_alpha(premultiplied_alpha_box_->isChecked()); + p.set_colorspace(colorspace_combobox_->currentData().toString()); + + return p; +} + +void VideoParamEdit::SetVideoParams(const VideoParams &p) +{ + blockSignals(true); + + enabled_box_->setChecked(p.enabled()); + width_slider_->SetValue(p.width()); + height_slider_->SetValue(p.height()); + depth_slider_->SetValue(p.depth()); + + if (mask_ & kFrameRateIsNotTimebase) { + // Frame rate editor will only edit the frame rate + frame_rate_combobox_->SetFrameRate(p.frame_rate()); + timebase_temp_ = p.time_base(); + } else { + // Frame rate editor will edit both frame rate and time base + frame_rate_combobox_->SetFrameRate(p.time_base().flipped()); + } + + pixel_aspect_combobox_->SetPixelAspectRatio(p.pixel_aspect_ratio()); + interlaced_combobox_->SetInterlaceMode(p.interlacing()); + format_combobox_->SetPixelFormat(p.format()); + SetChannelCount(p.channel_count()); + divider_combobox_->SetDivider(p.divider()); + stream_index_slider_->SetValue(p.stream_index()); + SetVideoTypeComboBox(p.video_type()); + start_time_slider_->SetValue(p.start_time()); + end_time_slider_->SetValue(p.start_time() + p.duration() - 1); + premultiplied_alpha_box_->setChecked(p.premultiplied_alpha()); + + if (color_manager_) { + // Assume colorspace box has been populated correctly + for (int i=0; icount(); i++) { + if (colorspace_combobox_->itemData(i).toString() == p.colorspace()) { + colorspace_combobox_->setCurrentIndex(i); + break; + } + } + } else { + // Box is empty, fill with single option so that it gets preserved in GetVideoParams() + colorspace_combobox_->clear(); + colorspace_combobox_->addItem(p.colorspace(), p.colorspace()); + } + + blockSignals(false); +} + +void VideoParamEdit::SetColorManager(ColorManager *cm) +{ + color_manager_ = cm; + + // Re-populate colorspace combobox + colorspace_combobox_->clear(); + + if (color_manager_) { + // Add default colorspace + colorspace_combobox_->addItem(tr("Default (%1)").arg(color_manager_->GetDefaultInputColorSpace()), QString()); + + // Add remaining + QStringList spaces = color_manager_->ListAvailableColorspaces(); + foreach (const QString& s, spaces) { + colorspace_combobox_->addItem(s, s); + } + } +} + +void VideoParamEdit::SetChannelCount(int count) +{ + for (int i=0; icount(); i++) { + if (channel_count_combobox_->itemData(i).toInt() == count) { + channel_count_combobox_->setCurrentIndex(i); + break; + } + } +} + +void VideoParamEdit::SetVideoTypeComboBox(VideoParams::Type type) +{ + for (int i=0; icount(); i++) { + if (video_type_combobox_->itemData(i).toInt() == type) { + video_type_combobox_->setCurrentIndex(i); + break; + } + } +} + +} diff --git a/app/widget/videoparamedit/videoparamedit.h b/app/widget/videoparamedit/videoparamedit.h new file mode 100644 index 000000000..91c678e1f --- /dev/null +++ b/app/widget/videoparamedit/videoparamedit.h @@ -0,0 +1,179 @@ +/*** + + 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 . + +***/ + +#ifndef VIDEOPARAMEDIT_H +#define VIDEOPARAMEDIT_H + +#include +#include +#include + +#include "render/colormanager.h" +#include "render/videoparams.h" +#include "widget/slider/integerslider.h" +#include "widget/standardcombos/frameratecombobox.h" +#include "widget/standardcombos/interlacedcombobox.h" +#include "widget/standardcombos/pixelaspectratiocombobox.h" +#include "widget/standardcombos/pixelformatcombobox.h" +#include "widget/standardcombos/videodividercombobox.h" + +namespace olive { + +class VideoParamEdit : public QWidget +{ + Q_OBJECT +public: + VideoParamEdit(QWidget* parent = nullptr); + + enum ParamMask { + kNone = 0x0, + kEnabled = 0x1, + kWidthHeight = 0x2, + kDepth = 0x4, + kFrameRate = 0x8, + kFormat = 0x10, + kChannelCount = 0x20, + kPixelAspect = 0x40, + kInterlacing = 0x80, + kDivider = 0x100, + kStreamIndex = 0x200, + kIsImageSequence = 0x400, + kStartTime = 0x800, + kEndTime = 0x1000, + kPremultipliedAlpha = 0x2000, + kColorspace = 0x4000, + kFrameRateIsNotTimebase = 0x8000, + }; + + void SetParameterMask(uint64_t mask); + + VideoParams GetVideoParams() const; + void SetVideoParams(const VideoParams& p); + + /** + * @brief Set pointer to ColorManager + * + * Call this before calling SetVideoParams because it'll populate the colorspace list so it + * can correctly be chosen from in the UI. + */ + void SetColorManager(ColorManager* cm); + + int GetWidth() const + { + return width_slider_->GetValue(); + } + + void SetWidth(int w) + { + width_slider_->SetValue(w); + } + + int GetHeight() const + { + return height_slider_->GetValue(); + } + + void SetHeight(int h) + { + height_slider_->SetValue(h); + } + + rational GetFrameRate() const + { + return frame_rate_combobox_->GetFrameRate(); + } + + void SetFrameRate(const rational& r) + { + frame_rate_combobox_->SetFrameRate(r); + } + + rational GetPixelAspectRatio() const + { + return pixel_aspect_combobox_->GetPixelAspectRatio(); + } + + void SetPixelAspectRatio(const rational& r) + { + pixel_aspect_combobox_->SetPixelAspectRatio(r); + } + + VideoParams::Interlacing GetInterlaceMode() const + { + return interlaced_combobox_->GetInterlaceMode(); + } + + void SetInterlaceMode(VideoParams::Interlacing i) + { + interlaced_combobox_->SetInterlaceMode(i); + } + +signals: + void Changed(); + +private: + void SetChannelCount(int count); + + void SetVideoTypeComboBox(VideoParams::Type type); + + QLabel* enabled_lbl_; + QCheckBox* enabled_box_; + QLabel* width_lbl_; + IntegerSlider* width_slider_; + QLabel* height_lbl_; + IntegerSlider* height_slider_; + QLabel* depth_lbl_; + IntegerSlider* depth_slider_; + QLabel* frame_rate_lbl_; + FrameRateComboBox* frame_rate_combobox_; + QLabel* pixel_aspect_lbl_; + PixelAspectRatioComboBox* pixel_aspect_combobox_; + QLabel* interlaced_lbl_; + InterlacedComboBox* interlaced_combobox_; + QLabel* format_lbl_; + PixelFormatComboBox* format_combobox_; + QLabel* channel_count_lbl_; + QComboBox* channel_count_combobox_; + QLabel* divider_lbl_; + VideoDividerComboBox* divider_combobox_; + QLabel* stream_index_lbl_; + IntegerSlider* stream_index_slider_; + QLabel* video_type_lbl_; + QComboBox* video_type_combobox_; + QLabel* start_time_lbl_; + IntegerSlider* start_time_slider_; + QLabel* end_time_lbl_; + IntegerSlider* end_time_slider_; + QLabel* premultiplied_alpha_lbl_; + QCheckBox* premultiplied_alpha_box_; + QLabel* colorspace_lbl_; + QComboBox* colorspace_combobox_; + + ColorManager* color_manager_; + + rational timebase_temp_; + + uint64_t mask_; + +}; + +} + +#endif // VIDEOPARAMEDIT_H diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index f387f65f7..f207adf6f 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -62,8 +62,6 @@ MainMenu::MainMenu(MainWindow *parent) : file_export_menu_ = new Menu(file_menu_); file_export_media_item_ = file_export_menu_->AddItem("export", Core::instance(), &Core::DialogExportShow, "Ctrl+M"); file_menu_->addSeparator(); - file_project_properties_item_ = file_menu_->AddItem("projectproperties", Core::instance(), &Core::DialogProjectPropertiesShow, "Shift+F10"); - file_menu_->addSeparator(); file_close_project_item_ = file_menu_->AddItem("closeproj", Core::instance(), &Core::CloseActiveProject); file_close_all_projects_item_ = file_menu_->AddItem("closeallproj", Core::instance(), static_cast(&Core::CloseAllProjects)); file_close_all_except_item_ = file_menu_->AddItem("closeallexcept", Core::instance(), &Core::CloseAllExceptActiveProject); @@ -284,7 +282,6 @@ void MainMenu::FileMenuAboutToShow() { Project* active_project = Core::instance()->GetActiveProject(); - file_project_properties_item_->setEnabled(active_project); file_save_item_->setEnabled(active_project); file_save_as_item_->setEnabled(active_project); file_close_project_item_->setEnabled(active_project); @@ -610,7 +607,6 @@ void MainMenu::Retranslate() file_import_item_->setText(tr("&Import...")); file_export_menu_->setTitle(tr("&Export")); file_export_media_item_->setText(tr("&Media...")); - file_project_properties_item_->setText(tr("&Project Properties...")); file_close_all_projects_item_->setText(tr("Close All Projects")); file_exit_item_->setText(tr("E&xit")); diff --git a/app/window/mainwindow/mainmenu.h b/app/window/mainwindow/mainmenu.h index b2e7c0546..120d45e8f 100644 --- a/app/window/mainwindow/mainmenu.h +++ b/app/window/mainwindow/mainmenu.h @@ -194,7 +194,6 @@ private: QAction* file_import_item_; Menu* file_export_menu_; QAction* file_export_media_item_; - QAction* file_project_properties_item_; QAction* file_close_project_item_; QAction* file_close_all_projects_item_; QAction* file_close_all_except_item_;