diff --git a/app/audio/audiomanager.cpp b/app/audio/audiomanager.cpp index 878944505..8fac9bd65 100644 --- a/app/audio/audiomanager.cpp +++ b/app/audio/audiomanager.cpp @@ -235,7 +235,7 @@ PaDeviceIndex AudioManager::FindConfigDeviceByName(bool is_output_device) { QString entry = is_output_device ? QStringLiteral("AudioOutput") : QStringLiteral("AudioInput"); - return FindDeviceByName(Config::Current()[entry].toString(), is_output_device); + return FindDeviceByName(OLIVE_CONFIG_STR(entry).toString(), is_output_device); } PaDeviceIndex AudioManager::FindDeviceByName(const QString &s, bool is_output_device) diff --git a/app/audio/audiovisualwaveform.cpp b/app/audio/audiovisualwaveform.cpp index af439bca0..dbc0cb973 100644 --- a/app/audio/audiovisualwaveform.cpp +++ b/app/audio/audiovisualwaveform.cpp @@ -426,7 +426,7 @@ void AudioVisualWaveform::DrawWaveform(QPainter *painter, const QRect& rect, con int start = qMax(rect.x(), -top_left.x()); int end = qMin(rect.right(), -top_left.x() + viewport.width()); - bool rectified = Config::Current()[QStringLiteral("RectifiedWaveforms")].toBool(); + bool rectified = OLIVE_CONFIG("RectifiedWaveforms").toBool(); for (int i=start;ispec().width); - video_params.set_height(in->spec().height); - video_params.set_format(OIIOUtils::GetFormatFromOIIOBasetype(static_cast(in->spec().format.basetype))); - video_params.set_channel_count(in->spec().nchannels); - video_params.set_pixel_aspect_ratio(OIIOUtils::GetPixelAspectRatioFromOIIO(in->spec())); - video_params.set_video_type(VideoParams::kVideoTypeStill); + for (int i=0; in->seek_subimage(i, 0); i++) { + VideoParams video_params; - // OIIO automatically premultiplies alpha - // FIXME: We usually disassociate the alpha for the color management later, for 8-bit images this - // likely reduces the fidelity? - video_params.set_premultiplied_alpha(true); + OIIO::ImageSpec spec = in->spec(); - desc.AddVideoStream(video_params); + video_params.set_stream_index(i); + video_params.set_width(spec.width); + video_params.set_height(spec.height); + video_params.set_format(OIIOUtils::GetFormatFromOIIOBasetype(static_cast(spec.format.basetype))); + video_params.set_channel_count(spec.nchannels); + video_params.set_pixel_aspect_ratio(OIIOUtils::GetPixelAspectRatioFromOIIO(spec)); + video_params.set_video_type(VideoParams::kVideoTypeStill); + + if (i > 1) { + // This is a multilayer image and this image might have an offset + OIIO::ImageSpec root_spec = in->spec(0); + + float norm_x = spec.x + float(spec.width)*0.5f - float(root_spec.width)*0.5f; + float norm_y = spec.y + float(spec.height)*0.5f - float(root_spec.height)*0.5f; + + video_params.set_x(norm_x); + video_params.set_y(norm_y); + } + + // By default, only enable the first subimage (presumably the combined image). Later we will + // ask the user if they want to enable the layers instead. + video_params.set_enabled(stream_enabled); + stream_enabled = false; + + // OIIO automatically premultiplies alpha + // FIXME: We usually disassociate the alpha for the color management later, for 8-bit images this + // likely reduces the fidelity? + video_params.set_premultiplied_alpha(true); + + desc.AddVideoStream(video_params); + } // If we're here, we have a successful image open in->close(); @@ -98,7 +120,7 @@ FootageDescription OIIODecoder::Probe(const QString &filename, const QAtomicInt* bool OIIODecoder::OpenInternal() { // If we can open the filename provided, assume everything is working - return OpenImageHandler(stream().filename()); + return OpenImageHandler(stream().filename(), stream().stream()); } FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const RetrieveVideoParams ÷r, const QAtomicInt *cancelled) @@ -108,13 +130,15 @@ FramePtr OIIODecoder::RetrieveVideoInternal(const rational &timecode, const Retr FramePtr frame = Frame::Create(); - frame->set_video_params(VideoParams(buffer_->spec().width, - buffer_->spec().height, - pix_fmt_, - channel_count_, - OIIOUtils::GetPixelAspectRatioFromOIIO(buffer_->spec()), - VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us? - divider.divider)); + VideoParams vp(buffer_->spec().width, + buffer_->spec().height, + pix_fmt_, + channel_count_, + OIIOUtils::GetPixelAspectRatioFromOIIO(buffer_->spec()), + VideoParams::kInterlaceNone, // FIXME: Does OIIO deinterlace for us? + divider.divider); + + frame->set_video_params(vp); frame->allocate(); if (divider.divider == 1) { @@ -167,7 +191,7 @@ bool OIIODecoder::FileTypeIsSupported(const QString& fn) return true; } -bool OIIODecoder::OpenImageHandler(const QString &fn) +bool OIIODecoder::OpenImageHandler(const QString &fn, int subimage) { image_ = OIIO::ImageInput::open(fn.toStdString()); @@ -175,6 +199,10 @@ bool OIIODecoder::OpenImageHandler(const QString &fn) return false; } + if (!image_->seek_subimage(subimage, 0)) { + return false; + } + // Check if we can work with this pixel format const OIIO::ImageSpec& spec = image_->spec(); diff --git a/app/codec/oiio/oiiodecoder.h b/app/codec/oiio/oiiodecoder.h index 4232cb2d1..a6039871d 100644 --- a/app/codec/oiio/oiiodecoder.h +++ b/app/codec/oiio/oiiodecoder.h @@ -52,7 +52,7 @@ private: static bool FileTypeIsSupported(const QString& fn); - bool OpenImageHandler(const QString& fn); + bool OpenImageHandler(const QString& fn, int subimage); void CloseImageHandle(); diff --git a/app/config/config.h b/app/config/config.h index b5c18e063..b15362802 100644 --- a/app/config/config.h +++ b/app/config/config.h @@ -31,6 +31,7 @@ namespace olive { #define OLIVE_CONFIG(x) Config::Current()[QStringLiteral(x)] +#define OLIVE_CONFIG_STR(x) Config::Current()[x] class Config { public: diff --git a/app/core.cpp b/app/core.cpp index c86f1a9e5..eacde37e8 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -533,6 +533,49 @@ void Core::ImportTaskComplete(Task* task) MultiUndoCommand *command = import_task->GetCommand(); + foreach (Footage *f, import_task->GetImportedFootage()) { + // Look for multi-layer images + if (f->GetAudioStreamCount() == 0 && f->GetVideoStreamCount() > 1) { + bool all_stills = true; + + for (int i=0; iGetVideoStreamCount(); i++) { + const VideoParams &vs = f->GetVideoParams(i); + if (!(vs.video_type() == VideoParams::kVideoTypeStill && vs.enabled() == (i == 0))) { + all_stills = false; + } + } + + if (all_stills) { + QMessageBox d(main_window()); + + d.setIcon(QMessageBox::Question); + d.setWindowTitle(tr("Multi-Layer Image")); + d.setText(tr("The file '%1' has multiple layers. Would you like these layers to be " + "separated across multiple tracks or merged into a single image?").arg(f->filename())); + + auto multi_btn = d.addButton(tr("Multiple Layers"), QMessageBox::YesRole); + auto single_btn = d.addButton(tr("Single Layer"), QMessageBox::NoRole); + auto cancel_btn = d.addButton(QMessageBox::Cancel); + + d.exec(); + + if (d.clickedButton() == multi_btn) { + for (int i=0; iGetVideoStreamCount(); i++) { + VideoParams vs = f->GetVideoParams(i); + vs.set_enabled(!vs.enabled()); + f->SetVideoParams(vs, i); + } + } else if (d.clickedButton() == single_btn) { + // Do nothing, footage will already be set up this way + } else if (d.clickedButton() == cancel_btn) { + // Cancel import + delete command; + return; + } + } + } + } + if (import_task->HasInvalidFiles()) { ProjectImportErrorDialog d(import_task->GetInvalidFiles(), main_window_); d.exec(); @@ -751,7 +794,7 @@ void Core::StartGUI(bool full_screen) connect(this, &Core::ProjectClosed, main_window_, &MainWindow::ProjectClose); // Start autorecovery timer using the config value as its interval - SetAutorecoveryInterval(Config::Current()["AutorecoveryInterval"].toInt()); + SetAutorecoveryInterval(OLIVE_CONFIG("AutorecoveryInterval").toInt()); connect(&autorecovery_timer_, &QTimer::timeout, this, &Core::SaveAutorecovery); autorecovery_timer_.start(); @@ -917,7 +960,7 @@ bool Core::RevertProjectInternal(Project *p, bool by_opening_existing) void Core::SaveAutorecovery() { - if (Config::Current()[QStringLiteral("AutorecoveryEnabled")].toBool()) { + if (OLIVE_CONFIG("AutorecoveryEnabled").toBool()) { foreach (Project* p, open_projects_) { if (!p->has_autorecovery_been_saved()) { QDir project_autorecovery_dir(QDir(FileFunctions::GetAutoRecoveryRoot()).filePath(p->GetUuid().toString())); @@ -943,7 +986,7 @@ void Core::SaveAutorecovery() realname_file.close(); } - int64_t max_recoveries_per_file = Config::Current()[QStringLiteral("AutorecoveryMaximum")].toLongLong(); + int64_t max_recoveries_per_file = OLIVE_CONFIG("AutorecoveryMaximum").toLongLong(); // Since we write an extra file, increment total allowed files by 1 max_recoveries_per_file++; @@ -1032,12 +1075,12 @@ Folder *Core::GetSelectedFolderInActiveProject() const Timecode::Display Core::GetTimecodeDisplay() const { - return static_cast(Config::Current()["TimecodeDisplay"].toInt()); + return static_cast(OLIVE_CONFIG("TimecodeDisplay").toInt()); } void Core::SetTimecodeDisplay(Timecode::Display d) { - Config::Current()["TimecodeDisplay"] = d; + OLIVE_CONFIG("TimecodeDisplay") = d; emit TimecodeDisplayChanged(d); } @@ -1159,7 +1202,7 @@ void Core::SetStartupLocale() } } - QString use_locale = Config::Current()[QStringLiteral("Language")].toString(); + QString use_locale = OLIVE_CONFIG("Language").toString(); if (use_locale.isEmpty()) { // No configured locale, auto-detect the system's locale @@ -1380,12 +1423,12 @@ QString GetRenderModePreferencePrefix(RenderMode::Mode mode, const QString &pref QVariant Core::GetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference) { - return Config::Current()[GetRenderModePreferencePrefix(mode, preference)]; + return OLIVE_CONFIG_STR(GetRenderModePreferencePrefix(mode, preference)); } void Core::SetPreferenceForRenderMode(RenderMode::Mode mode, const QString &preference, const QVariant &value) { - Config::Current()[GetRenderModePreferencePrefix(mode, preference)] = value; + OLIVE_CONFIG_STR(GetRenderModePreferencePrefix(mode, preference)) = value; } bool Core::LabelNodes(const QVector &nodes, MultiUndoCommand *parent) diff --git a/app/dialog/about/about.cpp b/app/dialog/about/about.cpp index e3500e217..066f8b537 100644 --- a/app/dialog/about/about.cpp +++ b/app/dialog/about/about.cpp @@ -132,7 +132,7 @@ AboutDialog::AboutDialog(bool welcome_dialog, QWidget *parent) : void AboutDialog::accept() { if (dont_show_again_checkbox_ && dont_show_again_checkbox_->isChecked()) { - Config::Current()[QStringLiteral("ShowWelcomeDialog")] = false; + OLIVE_CONFIG("ShowWelcomeDialog") = false; } QDialog::accept(); diff --git a/app/dialog/export/export.cpp b/app/dialog/export/export.cpp index 8723634e2..58813f7d5 100644 --- a/app/dialog/export/export.cpp +++ b/app/dialog/export/export.cpp @@ -208,7 +208,7 @@ ExportDialog::ExportDialog(ViewerOutput *viewer_node, QWidget *parent) : video_tab_->height_slider()->SetDefaultValue(vp.height()); video_tab_->SetSelectedFrameRate(vp.frame_rate()); video_tab_->pixel_aspect_combobox()->SetPixelAspectRatio(vp.pixel_aspect_ratio()); - video_tab_->pixel_format_field()->SetPixelFormat(static_cast(Config::Current()[QStringLiteral("OnlinePixelFormat")].toInt())); + video_tab_->pixel_format_field()->SetPixelFormat(static_cast(OLIVE_CONFIG("OnlinePixelFormat").toInt())); video_tab_->interlaced_combobox()->SetInterlaceMode(vp.interlacing()); audio_tab_->sample_rate_combobox()->SetSampleRate(ap.sample_rate()); audio_tab_->sample_format_combobox()->SetAttemptToRestoreFormat(false); diff --git a/app/dialog/preferences/tabs/preferencesappearancetab.cpp b/app/dialog/preferences/tabs/preferencesappearancetab.cpp index 761ea18dd..63c5da053 100644 --- a/app/dialog/preferences/tabs/preferencesappearancetab.cpp +++ b/app/dialog/preferences/tabs/preferencesappearancetab.cpp @@ -74,7 +74,7 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() color_layout->addWidget(new QLabel(cat_name), i, 0); ColorCodingComboBox* ccc = new ColorCodingComboBox(); - ccc->SetColor(Config::Current()[QStringLiteral("CatColor%1").arg(i)].toInt()); + ccc->SetColor(OLIVE_CONFIG_STR(QStringLiteral("CatColor%1").arg(i)).toInt()); color_layout->addWidget(ccc, i, 1); color_btns_.append(ccc); } @@ -92,7 +92,7 @@ PreferencesAppearanceTab::PreferencesAppearanceTab() marker_layout->addWidget(new QLabel("Default Marker Color"), 0, 0); marker_btn_ = new ColorCodingComboBox(); - marker_btn_->SetColor(Config::Current()[QStringLiteral("MarkerColor")].toInt()); + marker_btn_->SetColor(OLIVE_CONFIG("MarkerColor").toInt()); marker_layout->addWidget(marker_btn_, 0, 1); appearance_layout->addWidget(marker_group, row, 0, 1, 2); @@ -109,14 +109,14 @@ void PreferencesAppearanceTab::Accept(MultiUndoCommand *command) if (style_path != StyleManager::GetStyle()) { StyleManager::SetStyle(style_path); - Config::Current()[QStringLiteral("Style")] = style_path; + OLIVE_CONFIG("Style") = style_path; } for (int i=0; iGetSelectedColor(); + OLIVE_CONFIG_STR(QStringLiteral("CatColor%1").arg(i)) = color_btns_.at(i)->GetSelectedColor(); } - Config::Current()[QStringLiteral("MarkerColor")] = marker_btn_->GetSelectedColor(); + OLIVE_CONFIG("MarkerColor") = marker_btn_->GetSelectedColor(); } } diff --git a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp index 8d71b3df5..d16c7dce5 100644 --- a/app/dialog/preferences/tabs/preferencesbehaviortab.cpp +++ b/app/dialog/preferences/tabs/preferencesbehaviortab.cpp @@ -108,10 +108,8 @@ void PreferencesBehaviorTab::Accept(MultiUndoCommand *command) { Q_UNUSED(command) - QMap::const_iterator iterator; - - for (iterator=config_map_.begin();iterator!=config_map_.end();iterator++) { - Config::Current()[iterator.value()] = (iterator.key()->checkState(0) == Qt::Checked); + for (auto iterator=config_map_.begin();iterator!=config_map_.end();iterator++) { + OLIVE_CONFIG_STR(iterator.value()) = (iterator.key()->checkState(0) == Qt::Checked); } } @@ -119,7 +117,7 @@ QTreeWidgetItem* PreferencesBehaviorTab::AddItem(const QString &text, const QStr { QTreeWidgetItem* item = new QTreeWidgetItem({text}); item->setToolTip(0, tooltip); - item->setCheckState(0, Config::Current()[config_key].toBool() ? Qt::Checked : Qt::Unchecked); + item->setCheckState(0, OLIVE_CONFIG_STR(config_key).toBool() ? Qt::Checked : Qt::Unchecked); config_map_.insert(item, config_key); diff --git a/app/dialog/preferences/tabs/preferencesdisktab.cpp b/app/dialog/preferences/tabs/preferencesdisktab.cpp index f5258f34e..3d3ee3fa1 100644 --- a/app/dialog/preferences/tabs/preferencesdisktab.cpp +++ b/app/dialog/preferences/tabs/preferencesdisktab.cpp @@ -71,7 +71,7 @@ PreferencesDiskTab::PreferencesDiskTab() cache_ahead_slider_ = new FloatSlider(); cache_ahead_slider_->SetFormat(tr("%1 seconds")); cache_ahead_slider_->SetMinimum(0); - cache_ahead_slider_->SetValue(Config::Current()["DiskCacheAhead"].value().toDouble()); + cache_ahead_slider_->SetValue(OLIVE_CONFIG("DiskCacheAhead").value().toDouble()); cache_behavior_layout->addWidget(cache_ahead_slider_, row, 1); cache_behavior_layout->addWidget(new QLabel(tr("Cache Behind:")), row, 2); @@ -79,7 +79,7 @@ PreferencesDiskTab::PreferencesDiskTab() cache_behind_slider_ = new FloatSlider(); cache_behind_slider_->SetMinimum(0); cache_behind_slider_->SetFormat(tr("%1 seconds")); - cache_behind_slider_->SetValue(Config::Current()["DiskCacheBehind"].value().toDouble()); + cache_behind_slider_->SetValue(OLIVE_CONFIG("DiskCacheBehind").value().toDouble()); cache_behavior_layout->addWidget(cache_behind_slider_, row, 3); outer_layout->addStretch(); @@ -115,8 +115,8 @@ void PreferencesDiskTab::Accept(MultiUndoCommand *command) default_disk_cache_folder_->SetPath(disk_cache_location_->text()); } - Config::Current()["DiskCacheBehind"] = QVariant::fromValue(rational::fromDouble(cache_behind_slider_->GetValue())); - Config::Current()["DiskCacheAhead"] = QVariant::fromValue(rational::fromDouble(cache_ahead_slider_->GetValue())); + OLIVE_CONFIG("DiskCacheBehind") = QVariant::fromValue(rational::fromDouble(cache_behind_slider_->GetValue())); + OLIVE_CONFIG("DiskCacheAhead") = QVariant::fromValue(rational::fromDouble(cache_ahead_slider_->GetValue())); } } diff --git a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp index 3c869bb73..2e6425731 100644 --- a/app/dialog/preferences/tabs/preferencesgeneraltab.cpp +++ b/app/dialog/preferences/tabs/preferencesgeneraltab.cpp @@ -55,7 +55,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() AddLanguage(l); } - QString current_language = Config::Current()[QStringLiteral("Language")].toString(); + QString current_language = OLIVE_CONFIG("Language").toString(); if (current_language.isEmpty()) { // No configured language, use system language current_language = QLocale::system().name(); @@ -86,7 +86,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autoscroll_method_->addItem(tr("None"), AutoScroll::kNone); autoscroll_method_->addItem(tr("Page Scrolling"), AutoScroll::kPage); autoscroll_method_->addItem(tr("Smooth Scrolling"), AutoScroll::kSmooth); - autoscroll_method_->setCurrentIndex(Config::Current()["Autoscroll"].toInt()); + autoscroll_method_->setCurrentIndex(OLIVE_CONFIG("Autoscroll").toInt()); timeline_layout->addWidget(autoscroll_method_, row, 1); row++; @@ -94,7 +94,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() timeline_layout->addWidget(new QLabel(tr("Rectified Waveforms:")), row, 0); rectified_waveforms_ = new QCheckBox(); - rectified_waveforms_->setChecked(Config::Current()["RectifiedWaveforms"].toBool()); + rectified_waveforms_->setChecked(OLIVE_CONFIG("RectifiedWaveforms").toBool()); timeline_layout->addWidget(rectified_waveforms_, row, 1); row++; @@ -105,7 +105,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() default_still_length_->SetMinimum(rational(100, 1000)); default_still_length_->SetTimebase(rational(100, 1000)); default_still_length_->SetFormat(tr("%1 seconds")); - default_still_length_->SetValue(Config::Current()["DefaultStillLength"].value()); + default_still_length_->SetValue(OLIVE_CONFIG("DefaultStillLength").value()); timeline_layout->addWidget(default_still_length_); } @@ -119,7 +119,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autorecovery_layout->addWidget(new QLabel(tr("Enable Auto-Recovery:")), row, 0); autorecovery_enabled_ = new QCheckBox(); - autorecovery_enabled_->setChecked(Config::Current()[QStringLiteral("AutorecoveryEnabled")].toBool()); + autorecovery_enabled_->setChecked(OLIVE_CONFIG("AutorecoveryEnabled").toBool()); autorecovery_layout->addWidget(autorecovery_enabled_, row, 1); row++; @@ -130,7 +130,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autorecovery_interval_->SetMinimum(1); autorecovery_interval_->SetMaximum(60); autorecovery_interval_->SetFormat(QT_TRANSLATE_N_NOOP("olive::SliderBase", "%n minute(s)"), true); - autorecovery_interval_->SetValue(Config::Current()[QStringLiteral("AutorecoveryInterval")].toLongLong()); + autorecovery_interval_->SetValue(OLIVE_CONFIG("AutorecoveryInterval").toLongLong()); autorecovery_layout->addWidget(autorecovery_interval_, row, 1); row++; @@ -140,7 +140,7 @@ PreferencesGeneralTab::PreferencesGeneralTab() autorecovery_maximum_ = new IntegerSlider(); autorecovery_maximum_->SetMinimum(1); autorecovery_maximum_->SetMaximum(1000); - autorecovery_maximum_->SetValue(Config::Current()[QStringLiteral("AutorecoveryMaximum")].toLongLong()); + autorecovery_maximum_->SetValue(OLIVE_CONFIG("AutorecoveryMaximum").toLongLong()); autorecovery_layout->addWidget(autorecovery_maximum_, row, 1); row++; @@ -157,11 +157,11 @@ void PreferencesGeneralTab::Accept(MultiUndoCommand *command) { Q_UNUSED(command) - Config::Current()[QStringLiteral("RectifiedWaveforms")] = rectified_waveforms_->isChecked(); + OLIVE_CONFIG("RectifiedWaveforms") = rectified_waveforms_->isChecked(); - Config::Current()[QStringLiteral("Autoscroll")] = autoscroll_method_->currentData(); + OLIVE_CONFIG("Autoscroll") = autoscroll_method_->currentData(); - Config::Current()[QStringLiteral("DefaultStillLength")] = QVariant::fromValue(default_still_length_->GetValue()); + OLIVE_CONFIG("DefaultStillLength") = QVariant::fromValue(default_still_length_->GetValue()); QString set_language = language_combobox_->currentData().toString(); if (QLocale::system().name() == set_language) { @@ -170,14 +170,14 @@ void PreferencesGeneralTab::Accept(MultiUndoCommand *command) } // If the language has changed, set it now - if (Config::Current()[QStringLiteral("Language")].toString() != set_language) { - Config::Current()[QStringLiteral("Language")] = set_language; + if (OLIVE_CONFIG("Language").toString() != set_language) { + OLIVE_CONFIG("Language") = set_language; Core::instance()->SetLanguage(set_language.isEmpty() ? QLocale::system().name() : set_language); } - Config::Current()[QStringLiteral("AutorecoveryEnabled")] = autorecovery_enabled_->isChecked(); - Config::Current()[QStringLiteral("AutorecoveryInterval")] = QVariant::fromValue(autorecovery_interval_->GetValue()); - Config::Current()[QStringLiteral("AutorecoveryMaximum")] = QVariant::fromValue(autorecovery_maximum_->GetValue()); + OLIVE_CONFIG("AutorecoveryEnabled") = autorecovery_enabled_->isChecked(); + OLIVE_CONFIG("AutorecoveryInterval") = QVariant::fromValue(autorecovery_interval_->GetValue()); + OLIVE_CONFIG("AutorecoveryMaximum") = QVariant::fromValue(autorecovery_maximum_->GetValue()); Core::instance()->SetAutorecoveryInterval(autorecovery_interval_->GetValue()); } diff --git a/app/dialog/sequence/sequence.cpp b/app/dialog/sequence/sequence.cpp index e7daa93e5..4305e1894 100644 --- a/app/dialog/sequence/sequence.cpp +++ b/app/dialog/sequence/sequence.cpp @@ -148,14 +148,14 @@ void SequenceDialog::SetAsDefaultClicked() tr("Are you sure you want to set the current parameters as defaults?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { // Maybe replace with Preset system - Config::Current()[QStringLiteral("DefaultSequenceWidth")] = parameter_tab_->GetSelectedVideoWidth(); - Config::Current()[QStringLiteral("DefaultSequenceHeight")] = parameter_tab_->GetSelectedVideoHeight(); - Config::Current()[QStringLiteral("DefaultSequencePixelAspect")] = QVariant::fromValue(parameter_tab_->GetSelectedVideoPixelAspect()); - Config::Current()[QStringLiteral("DefaultSequenceFrameRate")] = QVariant::fromValue(parameter_tab_->GetSelectedVideoFrameRate().flipped()); - Config::Current()[QStringLiteral("DefaultSequenceInterlacing")] = parameter_tab_->GetSelectedVideoInterlacingMode(); - Config::Current()[QStringLiteral("DefaultSequenceAudioFrequency")] = parameter_tab_->GetSelectedAudioSampleRate(); - Config::Current()[QStringLiteral("DefaultSequenceAudioLayout")] = QVariant::fromValue(parameter_tab_->GetSelectedAudioChannelLayout()); - Config::Current()[QStringLiteral("DefaultSequenceAutoCache")] = QVariant::fromValue(parameter_tab_->GetSelectedPreviewAutoCache()); + OLIVE_CONFIG("DefaultSequenceWidth") = parameter_tab_->GetSelectedVideoWidth(); + OLIVE_CONFIG("DefaultSequenceHeight") = parameter_tab_->GetSelectedVideoHeight(); + OLIVE_CONFIG("DefaultSequencePixelAspect") = QVariant::fromValue(parameter_tab_->GetSelectedVideoPixelAspect()); + OLIVE_CONFIG("DefaultSequenceFrameRate") = QVariant::fromValue(parameter_tab_->GetSelectedVideoFrameRate().flipped()); + OLIVE_CONFIG("DefaultSequenceInterlacing") = parameter_tab_->GetSelectedVideoInterlacingMode(); + OLIVE_CONFIG("DefaultSequenceAudioFrequency") = parameter_tab_->GetSelectedAudioSampleRate(); + OLIVE_CONFIG("DefaultSequenceAudioLayout") = QVariant::fromValue(parameter_tab_->GetSelectedAudioChannelLayout()); + OLIVE_CONFIG("DefaultSequenceAutoCache") = QVariant::fromValue(parameter_tab_->GetSelectedPreviewAutoCache()); } } diff --git a/app/dialog/sequence/sequencedialogpresettab.cpp b/app/dialog/sequence/sequencedialogpresettab.cpp index c3e471b9c..74c5a0595 100644 --- a/app/dialog/sequence/sequencedialogpresettab.cpp +++ b/app/dialog/sequence/sequencedialogpresettab.cpp @@ -100,8 +100,8 @@ QTreeWidgetItem* SequenceDialogPresetTab::CreateFolder(const QString &name) QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &name, int width, int height, int divider) { - const VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); - const bool default_autocache = Config::Current()[QStringLiteral("DefaultSequenceAutoCache")].toBool(); + const VideoParams::Format default_format = static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()); + const bool default_autocache = OLIVE_CONFIG("DefaultSequenceAutoCache").toBool(); QTreeWidgetItem* parent = CreateFolder(name); AddStandardItem(parent, std::make_shared(tr("%1 23.976 FPS").arg(name), width, @@ -163,8 +163,8 @@ QTreeWidgetItem *SequenceDialogPresetTab::CreateHDPresetFolder(const QString &na QTreeWidgetItem *SequenceDialogPresetTab::CreateSDPresetFolder(const QString &name, int width, int height, const rational& frame_rate, const rational &standard_par, const rational &wide_par, int divider) { - const VideoParams::Format default_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); - const bool default_autocache = Config::Current()[QStringLiteral("DefaultSequenceAutoCache")].toBool(); + const VideoParams::Format default_format = static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()); + const bool default_autocache = OLIVE_CONFIG("DefaultSequenceAutoCache").toBool(); QTreeWidgetItem* parent = CreateFolder(name); preset_tree_->addTopLevelItem(parent); AddStandardItem(parent, std::make_shared(tr("%1 Standard").arg(name), diff --git a/app/node/audio/pan/pan.cpp b/app/node/audio/pan/pan.cpp index 482bf075f..c6311e67a 100644 --- a/app/node/audio/pan/pan.cpp +++ b/app/node/audio/pan/pan.cpp @@ -42,11 +42,6 @@ PanNode::PanNode() SetEffectInput(kSamplesInput); } -Node *PanNode::copy() const -{ - return new PanNode(); -} - QString PanNode::Name() const { return tr("Pan"); diff --git a/app/node/audio/pan/pan.h b/app/node/audio/pan/pan.h index 6f8fd9a89..075eafb02 100644 --- a/app/node/audio/pan/pan.h +++ b/app/node/audio/pan/pan.h @@ -31,9 +31,7 @@ class PanNode : public Node public: PanNode(); - NODE_DEFAULT_DESTRUCTOR(PanNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(PanNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/audio/volume/volume.cpp b/app/node/audio/volume/volume.cpp index 79feef607..e03d284b2 100644 --- a/app/node/audio/volume/volume.cpp +++ b/app/node/audio/volume/volume.cpp @@ -41,11 +41,6 @@ VolumeNode::VolumeNode() SetEffectInput(kSamplesInput); } -Node *VolumeNode::copy() const -{ - return new VolumeNode(); -} - QString VolumeNode::Name() const { return tr("Volume"); diff --git a/app/node/audio/volume/volume.h b/app/node/audio/volume/volume.h index a9fcc10d9..38ba243d8 100644 --- a/app/node/audio/volume/volume.h +++ b/app/node/audio/volume/volume.h @@ -31,9 +31,7 @@ class VolumeNode : public MathNodeBase public: VolumeNode(); - NODE_DEFAULT_DESTRUCTOR(VolumeNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(VolumeNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/block.h b/app/node/block/block.h index a555cb065..33ddc00dd 100644 --- a/app/node/block/block.h +++ b/app/node/block/block.h @@ -37,8 +37,6 @@ class Block : public Node public: Block(); - NODE_DEFAULT_DESTRUCTOR(Block) - virtual QVector Category() const override; const rational& in() const diff --git a/app/node/block/clip/clip.cpp b/app/node/block/clip/clip.cpp index a7ce383b2..16720eafc 100644 --- a/app/node/block/clip/clip.cpp +++ b/app/node/block/clip/clip.cpp @@ -61,11 +61,6 @@ ClipBlock::ClipBlock() : SetEffectInput(kBufferIn); } -Node *ClipBlock::copy() const -{ - return new ClipBlock(); -} - QString ClipBlock::Name() const { if (track()) { diff --git a/app/node/block/clip/clip.h b/app/node/block/clip/clip.h index 300f3408f..943c6ed15 100644 --- a/app/node/block/clip/clip.h +++ b/app/node/block/clip/clip.h @@ -37,9 +37,7 @@ class ClipBlock : public Block public: ClipBlock(); - NODE_DEFAULT_DESTRUCTOR(ClipBlock) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(ClipBlock) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/gap/gap.cpp b/app/node/block/gap/gap.cpp index d5ea6915c..60a066153 100644 --- a/app/node/block/gap/gap.cpp +++ b/app/node/block/gap/gap.cpp @@ -26,11 +26,6 @@ GapBlock::GapBlock() { } -Node *GapBlock::copy() const -{ - return new GapBlock(); -} - QString GapBlock::Name() const { return tr("Gap"); diff --git a/app/node/block/gap/gap.h b/app/node/block/gap/gap.h index c048e229e..5dfc01eb1 100644 --- a/app/node/block/gap/gap.h +++ b/app/node/block/gap/gap.h @@ -34,9 +34,7 @@ class GapBlock : public Block public: GapBlock(); - NODE_DEFAULT_DESTRUCTOR(GapBlock) - - virtual Node * copy() const override; + NODE_DEFAULT_FUNCTIONS(GapBlock) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/subtitle/subtitle.cpp b/app/node/block/subtitle/subtitle.cpp index ef42559cd..8c60d8ee4 100644 --- a/app/node/block/subtitle/subtitle.cpp +++ b/app/node/block/subtitle/subtitle.cpp @@ -31,11 +31,6 @@ SubtitleBlock::SubtitleBlock() AddInput(kTextIn, NodeValue::kText, InputFlags(kInputFlagNotConnectable | kInputFlagNotKeyframable)); } -Node *SubtitleBlock::copy() const -{ - return new SubtitleBlock(); -} - QString SubtitleBlock::Name() const { return tr("Subtitle"); diff --git a/app/node/block/subtitle/subtitle.h b/app/node/block/subtitle/subtitle.h index c88a2bfc1..ed51c37d3 100644 --- a/app/node/block/subtitle/subtitle.h +++ b/app/node/block/subtitle/subtitle.h @@ -31,9 +31,7 @@ class SubtitleBlock : public ClipBlock public: SubtitleBlock(); - NODE_DEFAULT_DESTRUCTOR(SubtitleBlock) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(SubtitleBlock) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp index 8f9d33e62..bf50e7486 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.cpp @@ -24,12 +24,6 @@ namespace olive { CrossDissolveTransition::CrossDissolveTransition() { - -} - -Node *CrossDissolveTransition::copy() const -{ - return new CrossDissolveTransition(); } QString CrossDissolveTransition::Name() const diff --git a/app/node/block/transition/crossdissolve/crossdissolvetransition.h b/app/node/block/transition/crossdissolve/crossdissolvetransition.h index aca4fd039..bd6f7ca9e 100644 --- a/app/node/block/transition/crossdissolve/crossdissolvetransition.h +++ b/app/node/block/transition/crossdissolve/crossdissolvetransition.h @@ -31,9 +31,7 @@ class CrossDissolveTransition : public TransitionBlock public: CrossDissolveTransition(); - NODE_DEFAULT_DESTRUCTOR(CrossDissolveTransition) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(CrossDissolveTransition) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/transition/diptocolor/diptocolortransition.cpp b/app/node/block/transition/diptocolor/diptocolortransition.cpp index 1c9691e13..5a64ed3de 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.cpp +++ b/app/node/block/transition/diptocolor/diptocolortransition.cpp @@ -29,11 +29,6 @@ DipToColorTransition::DipToColorTransition() AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(0, 0, 0))); } -Node *DipToColorTransition::copy() const -{ - return new DipToColorTransition(); -} - QString DipToColorTransition::Name() const { return tr("Dip To Color"); diff --git a/app/node/block/transition/diptocolor/diptocolortransition.h b/app/node/block/transition/diptocolor/diptocolortransition.h index 00ff56550..66164d559 100644 --- a/app/node/block/transition/diptocolor/diptocolortransition.h +++ b/app/node/block/transition/diptocolor/diptocolortransition.h @@ -31,9 +31,7 @@ class DipToColorTransition : public TransitionBlock public: DipToColorTransition(); - NODE_DEFAULT_DESTRUCTOR(DipToColorTransition) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(DipToColorTransition) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/block/transition/transition.h b/app/node/block/transition/transition.h index 93577fcbc..e76888edd 100644 --- a/app/node/block/transition/transition.h +++ b/app/node/block/transition/transition.h @@ -33,8 +33,6 @@ class TransitionBlock : public Block public: TransitionBlock(); - NODE_DEFAULT_DESTRUCTOR(TransitionBlock) - virtual void Retranslate() override; rational in_offset() const; diff --git a/app/node/color/colormanager/colormanager.h b/app/node/color/colormanager/colormanager.h index 26ea7cc90..a26d3b424 100644 --- a/app/node/color/colormanager/colormanager.h +++ b/app/node/color/colormanager/colormanager.h @@ -38,6 +38,8 @@ class ColorManager : public Node public: ColorManager(); + NODE_DEFAULT_FUNCTIONS(ColorManager) + virtual QString Name() const override { return tr("Color Manager"); @@ -58,11 +60,6 @@ public: return tr("Color management configuration for project."); } - virtual Node* copy() const override - { - return new ColorManager(); - } - OCIO::ConstConfigRcPtr GetConfig() const; static OCIO::ConstConfigRcPtr CreateConfigFromFile(const QString& filename); diff --git a/app/node/distort/cornerpin/cornerpindistortnode.h b/app/node/distort/cornerpin/cornerpindistortnode.h index 86d80952f..8c5cae8cb 100644 --- a/app/node/distort/cornerpin/cornerpindistortnode.h +++ b/app/node/distort/cornerpin/cornerpindistortnode.h @@ -35,12 +35,7 @@ class CornerPinDistortNode : public Node public: CornerPinDistortNode(); - NODE_DEFAULT_DESTRUCTOR(CornerPinDistortNode) - - virtual Node* copy() const override - { - return new CornerPinDistortNode(); - } + NODE_DEFAULT_FUNCTIONS(CornerPinDistortNode) virtual QString Name() const override { diff --git a/app/node/distort/crop/cropdistortnode.h b/app/node/distort/crop/cropdistortnode.h index d2916a24d..402719281 100644 --- a/app/node/distort/crop/cropdistortnode.h +++ b/app/node/distort/crop/cropdistortnode.h @@ -36,12 +36,7 @@ class CropDistortNode : public Node public: CropDistortNode(); - NODE_DEFAULT_DESTRUCTOR(CropDistortNode) - - virtual Node* copy() const override - { - return new CropDistortNode(); - } + NODE_DEFAULT_FUNCTIONS(CropDistortNode) virtual QString Name() const override { diff --git a/app/node/distort/flip/flipdistortnode.cpp b/app/node/distort/flip/flipdistortnode.cpp index 4589b4542..53fbcfb84 100644 --- a/app/node/distort/flip/flipdistortnode.cpp +++ b/app/node/distort/flip/flipdistortnode.cpp @@ -40,11 +40,6 @@ FlipDistortNode::FlipDistortNode() SetEffectInput(kTextureInput); } -Node* FlipDistortNode::copy() const -{ - return new FlipDistortNode(); -} - QString FlipDistortNode::Name() const { return tr("Flip"); diff --git a/app/node/distort/flip/flipdistortnode.h b/app/node/distort/flip/flipdistortnode.h index ba78023f1..3bb53bb0c 100644 --- a/app/node/distort/flip/flipdistortnode.h +++ b/app/node/distort/flip/flipdistortnode.h @@ -31,9 +31,7 @@ class FlipDistortNode : public Node public: FlipDistortNode(); - NODE_DEFAULT_DESTRUCTOR(FlipDistortNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(FlipDistortNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/distort/transform/transformdistortnode.cpp b/app/node/distort/transform/transformdistortnode.cpp index d2eb794ea..1b5cad90f 100644 --- a/app/node/distort/transform/transformdistortnode.cpp +++ b/app/node/distort/transform/transformdistortnode.cpp @@ -318,7 +318,7 @@ void TransformDistortNode::GizmoDragMove(double x, double y, const Qt::KeyboardM } } -QMatrix4x4 TransformDistortNode::AdjustMatrixByResolutions(const QMatrix4x4 &mat, const QVector2D &sequence_res, const QVector2D &texture_res, AutoScaleType autoscale_type) +QMatrix4x4 TransformDistortNode::AdjustMatrixByResolutions(const QMatrix4x4 &mat, const QVector2D &sequence_res, const QVector2D &texture_res, const QVector2D &offset, AutoScaleType autoscale_type) { // First, create an identity matrix QMatrix4x4 adjusted_matrix; @@ -326,6 +326,9 @@ QMatrix4x4 TransformDistortNode::AdjustMatrixByResolutions(const QMatrix4x4 &mat // Scale it to a square based on the sequence's resolution adjusted_matrix.scale(2.0 / sequence_res.x(), 2.0 / sequence_res.y(), 1.0); + // Apply offset if applicable + adjusted_matrix.translate(offset); + // Adjust by the matrix we generated earlier adjusted_matrix *= mat; @@ -378,6 +381,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N // GizmoTraverser just returns the sizes of the textures and no other data VideoParams tex_params = tex->params(); QVector2D tex_sz(tex_params.square_pixel_width(), tex_params.height()); + QVector2D tex_offset = tex_params.offset(); // Retrieve autoscale value AutoScaleType autoscale = static_cast(row[kAutoscaleInput].data().toInt()); @@ -388,6 +392,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N rectangle_matrix *= AdjustMatrixByResolutions(GenerateMatrix(row, false, false, false, false), sequence_res, tex_sz, + tex_offset, autoscale); // Create rect and transform it @@ -407,6 +412,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N anchor_matrix *= AdjustMatrixByResolutions(GenerateMatrix(row, false, true, false, false), sequence_res, tex_sz, + tex_offset, autoscale); anchor_gizmo_->SetPoint(anchor_matrix.toTransform().map(QPointF(0, 0)) + sequence_half_res_pt); @@ -422,7 +428,7 @@ void TransformDistortNode::UpdateGizmoPositions(const NodeValueRow &row, const N // Use offsets to make the appearance of values that start in the top left, even though we // really anchor around the center - SetInputProperty(kPositionInput, QStringLiteral("offset"), sequence_half_res); + SetInputProperty(kPositionInput, QStringLiteral("offset"), sequence_half_res + tex_offset); SetInputProperty(kAnchorInput, QStringLiteral("offset"), tex_sz * 0.5); } @@ -440,6 +446,7 @@ QMatrix4x4 TransformDistortNode::GenerateAutoScaledMatrix(const QMatrix4x4& gene return AdjustMatrixByResolutions(generated_matrix, sequence_res, texture_res, + texture_params.offset(), autoscale); } diff --git a/app/node/distort/transform/transformdistortnode.h b/app/node/distort/transform/transformdistortnode.h index a2ca55919..68e71d8a5 100644 --- a/app/node/distort/transform/transformdistortnode.h +++ b/app/node/distort/transform/transformdistortnode.h @@ -34,12 +34,7 @@ class TransformDistortNode : public MatrixGenerator public: TransformDistortNode(); - NODE_DEFAULT_DESTRUCTOR(TransformDistortNode) - - virtual Node* copy() const override - { - return new TransformDistortNode(); - } + NODE_DEFAULT_FUNCTIONS(TransformDistortNode) virtual QString Name() const override { @@ -82,6 +77,7 @@ public: static QMatrix4x4 AdjustMatrixByResolutions(const QMatrix4x4& mat, const QVector2D& sequence_res, const QVector2D& texture_res, + const QVector2D& offset, AutoScaleType autoscale_type = kAutoScaleNone); virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override; diff --git a/app/node/effect/opacity/opacityeffect.h b/app/node/effect/opacity/opacityeffect.h index d18af81cc..a7c8f7f0a 100644 --- a/app/node/effect/opacity/opacityeffect.h +++ b/app/node/effect/opacity/opacityeffect.h @@ -10,9 +10,7 @@ class OpacityEffect : public Node public: OpacityEffect(); - NODE_DEFAULT_DESTRUCTOR(OpacityEffect) - - NODE_COPY_FUNCTION(OpacityEffect) + NODE_DEFAULT_FUNCTIONS(OpacityEffect) virtual QString Name() const override { diff --git a/app/node/filter/blur/blur.cpp b/app/node/filter/blur/blur.cpp index 0452c4fba..86d277ce1 100644 --- a/app/node/filter/blur/blur.cpp +++ b/app/node/filter/blur/blur.cpp @@ -50,11 +50,6 @@ BlurFilterNode::BlurFilterNode() SetEffectInput(kTextureInput); } -Node *BlurFilterNode::copy() const -{ - return new BlurFilterNode(); -} - QString BlurFilterNode::Name() const { return tr("Blur"); diff --git a/app/node/filter/blur/blur.h b/app/node/filter/blur/blur.h index 4b061040d..da70956a4 100644 --- a/app/node/filter/blur/blur.h +++ b/app/node/filter/blur/blur.h @@ -31,9 +31,7 @@ class BlurFilterNode : public Node public: BlurFilterNode(); - NODE_DEFAULT_DESTRUCTOR(BlurFilterNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(BlurFilterNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/filter/mosaic/mosaicfilternode.h b/app/node/filter/mosaic/mosaicfilternode.h index 726da5744..f1dea64e4 100644 --- a/app/node/filter/mosaic/mosaicfilternode.h +++ b/app/node/filter/mosaic/mosaicfilternode.h @@ -31,12 +31,7 @@ class MosaicFilterNode : public Node public: MosaicFilterNode(); - NODE_DEFAULT_DESTRUCTOR(MosaicFilterNode) - - virtual Node* copy() const override - { - return new MosaicFilterNode(); - } + NODE_DEFAULT_FUNCTIONS(MosaicFilterNode) virtual QString Name() const override { diff --git a/app/node/filter/stroke/stroke.cpp b/app/node/filter/stroke/stroke.cpp index d0360cc10..6f05f61fa 100644 --- a/app/node/filter/stroke/stroke.cpp +++ b/app/node/filter/stroke/stroke.cpp @@ -53,11 +53,6 @@ StrokeFilterNode::StrokeFilterNode() SetEffectInput(kTextureInput); } -Node *StrokeFilterNode::copy() const -{ - return new StrokeFilterNode(); -} - QString StrokeFilterNode::Name() const { return tr("Stroke"); diff --git a/app/node/filter/stroke/stroke.h b/app/node/filter/stroke/stroke.h index d70e7e7bc..d762b3923 100644 --- a/app/node/filter/stroke/stroke.h +++ b/app/node/filter/stroke/stroke.h @@ -31,9 +31,7 @@ class StrokeFilterNode : public Node public: StrokeFilterNode(); - NODE_DEFAULT_DESTRUCTOR(StrokeFilterNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(StrokeFilterNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/matrix/matrix.cpp b/app/node/generator/matrix/matrix.cpp index bbd5c9ba6..30cbf6065 100644 --- a/app/node/generator/matrix/matrix.cpp +++ b/app/node/generator/matrix/matrix.cpp @@ -51,11 +51,6 @@ MatrixGenerator::MatrixGenerator() AddInput(kAnchorInput, NodeValue::kVec2, QVector2D(0.0, 0.0)); } -Node *MatrixGenerator::copy() const -{ - return new MatrixGenerator(); -} - QString MatrixGenerator::Name() const { return tr("Orthographic Matrix"); diff --git a/app/node/generator/matrix/matrix.h b/app/node/generator/matrix/matrix.h index 6ccb318a0..3466c703d 100644 --- a/app/node/generator/matrix/matrix.h +++ b/app/node/generator/matrix/matrix.h @@ -34,9 +34,7 @@ class MatrixGenerator : public Node public: MatrixGenerator(); - NODE_DEFAULT_DESTRUCTOR(MatrixGenerator) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(MatrixGenerator) virtual QString Name() const override; virtual QString ShortName() const override; diff --git a/app/node/generator/noise/noise.cpp b/app/node/generator/noise/noise.cpp index 64ea2266a..0d4e3c832 100644 --- a/app/node/generator/noise/noise.cpp +++ b/app/node/generator/noise/noise.cpp @@ -20,8 +20,11 @@ #include "noise.h" +#include "widget/slider/floatslider.h" + namespace olive { +const QString NoiseGeneratorNode::kBaseIn = QStringLiteral("base_in"); const QString NoiseGeneratorNode::kColorInput = QStringLiteral("color_in"); const QString NoiseGeneratorNode::kStrengthInput = QStringLiteral("strength_in"); @@ -29,14 +32,16 @@ const QString NoiseGeneratorNode::kStrengthInput = QStringLiteral("strength_in") NoiseGeneratorNode::NoiseGeneratorNode() { - AddInput(kStrengthInput, NodeValue::kFloat, 20); + AddInput(kBaseIn, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + + AddInput(kStrengthInput, NodeValue::kFloat, 0.2); + SetInputProperty(kStrengthInput, QStringLiteral("view"), FloatSlider::kPercentage); + SetInputProperty(kStrengthInput, QStringLiteral("min"), 0); AddInput(kColorInput, NodeValue::kBoolean, false); -} -Node* NoiseGeneratorNode::copy() const -{ - return new NoiseGeneratorNode(); + SetEffectInput(kBaseIn); + SetFlags(kVideoEffect); } QString NoiseGeneratorNode::Name() const @@ -63,12 +68,13 @@ void NoiseGeneratorNode::Retranslate() { super::Retranslate(); + SetInputName(kBaseIn, tr("Base")); SetInputName(kStrengthInput, tr("Strength")); SetInputName(kColorInput, tr("Color")); } -ShaderCode NoiseGeneratorNode::GetShaderCode(const QString& shader_id) const { - Q_UNUSED(shader_id) +ShaderCode NoiseGeneratorNode::GetShaderCode(const QString& shader_id) const +{ return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/noise.frag")); } @@ -79,8 +85,6 @@ void NoiseGeneratorNode::Value(const NodeValueRow &value, const NodeGlobals &glo job.InsertValue(value); job.InsertValue(QStringLiteral("time_in"), NodeValue(NodeValue::kFloat, globals.time().in().toDouble(), this)); - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); - } } diff --git a/app/node/generator/noise/noise.h b/app/node/generator/noise/noise.h index 31dfd2f3b..7b8ea005c 100644 --- a/app/node/generator/noise/noise.h +++ b/app/node/generator/noise/noise.h @@ -30,9 +30,7 @@ class NoiseGeneratorNode : public Node { public: NoiseGeneratorNode(); - NODE_DEFAULT_DESTRUCTOR(NoiseGeneratorNode) - - virtual Node *copy() const override; + NODE_DEFAULT_FUNCTIONS(NoiseGeneratorNode) virtual QString Name() const override; virtual QString id() const override; @@ -44,8 +42,10 @@ class NoiseGeneratorNode : public Node { virtual ShaderCode GetShaderCode(const QString &shader_id) const override; virtual void Value(const NodeValueRow &value, const NodeGlobals &globals, NodeValueTable *table) const override; + static const QString kBaseIn; static const QString kColorInput; static const QString kStrengthInput; + }; } // namespace olive diff --git a/app/node/generator/polygon/polygon.cpp b/app/node/generator/polygon/polygon.cpp index cfccc83c2..cb294b9ed 100644 --- a/app/node/generator/polygon/polygon.cpp +++ b/app/node/generator/polygon/polygon.cpp @@ -30,7 +30,7 @@ namespace olive { const QString PolygonGenerator::kPointsInput = QStringLiteral("points_in"); const QString PolygonGenerator::kColorInput = QStringLiteral("color_in"); -#define super Node +#define super GeneratorWithMerge PolygonGenerator::PolygonGenerator() { @@ -61,11 +61,6 @@ PolygonGenerator::PolygonGenerator() poly_gizmo_ = new PathGizmo(this); } -Node *PolygonGenerator::copy() const -{ - return new PolygonGenerator(); -} - QString PolygonGenerator::Name() const { return tr("Polygon"); @@ -102,7 +97,7 @@ void PolygonGenerator::Value(const NodeValueRow &value, const NodeGlobals &globa job.SetRequestedFormat(VideoParams::kFormatFloat32); job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); + PushMergableJob(value, QVariant::fromValue(job), table); } void PolygonGenerator::GenerateFrame(FramePtr frame, const GenerateJob &job) const diff --git a/app/node/generator/polygon/polygon.h b/app/node/generator/polygon/polygon.h index e1c66573a..0b2d98457 100644 --- a/app/node/generator/polygon/polygon.h +++ b/app/node/generator/polygon/polygon.h @@ -24,6 +24,7 @@ #include #include "common/bezier.h" +#include "node/generator/shape/generatorwithmerge.h" #include "node/gizmo/line.h" #include "node/gizmo/path.h" #include "node/gizmo/point.h" @@ -32,15 +33,13 @@ namespace olive { -class PolygonGenerator : public Node +class PolygonGenerator : public GeneratorWithMerge { Q_OBJECT public: PolygonGenerator(); - NODE_DEFAULT_DESTRUCTOR(PolygonGenerator) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(PolygonGenerator) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/shape/CMakeLists.txt b/app/node/generator/shape/CMakeLists.txt index b3d0fed04..275b80e75 100644 --- a/app/node/generator/shape/CMakeLists.txt +++ b/app/node/generator/shape/CMakeLists.txt @@ -16,6 +16,8 @@ set(OLIVE_SOURCES ${OLIVE_SOURCES} + node/generator/shape/generatorwithmerge.cpp + node/generator/shape/generatorwithmerge.h node/generator/shape/shapenode.cpp node/generator/shape/shapenode.h node/generator/shape/shapenodebase.cpp diff --git a/app/node/generator/shape/generatorwithmerge.cpp b/app/node/generator/shape/generatorwithmerge.cpp new file mode 100644 index 000000000..363ba4d12 --- /dev/null +++ b/app/node/generator/shape/generatorwithmerge.cpp @@ -0,0 +1,71 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 "generatorwithmerge.h" + +#include "node/math/merge/merge.h" + +namespace olive { + +#define super Node + +const QString GeneratorWithMerge::kBaseInput = QStringLiteral("base_in"); + +GeneratorWithMerge::GeneratorWithMerge() +{ + AddInput(kBaseInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); + SetEffectInput(kBaseInput); + SetFlags(kVideoEffect); +} + +void GeneratorWithMerge::Retranslate() +{ + super::Retranslate(); + + SetInputName(kBaseInput, tr("Base")); +} + +ShaderCode GeneratorWithMerge::GetShaderCode(const QString &shader_id) const +{ + if (shader_id == QStringLiteral("mrg")) { + return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/alphaover.frag")); + } + + return ShaderCode(); +} + +void GeneratorWithMerge::PushMergableJob(const NodeValueRow &value, const QVariant &job, NodeValueTable *table) const +{ + if (!value[kBaseInput].data().isNull()) { + // Push as merge node + ShaderJob merge; + + merge.SetShaderID(QStringLiteral("mrg")); + merge.InsertValue(MergeNode::kBaseIn, value[kBaseInput]); + merge.InsertValue(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, job, this)); + + table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); + } else { + // Just push generate job + table->Push(NodeValue::kTexture, job, this); + } +} + +} diff --git a/app/node/generator/shape/generatorwithmerge.h b/app/node/generator/shape/generatorwithmerge.h new file mode 100644 index 000000000..af69e1ed4 --- /dev/null +++ b/app/node/generator/shape/generatorwithmerge.h @@ -0,0 +1,47 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2021 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 GENERATORWITHMERGE_H +#define GENERATORWITHMERGE_H + +#include "node/node.h" + +namespace olive { + +class GeneratorWithMerge : public Node +{ + Q_OBJECT +public: + GeneratorWithMerge(); + + virtual void Retranslate() override; + + virtual ShaderCode GetShaderCode(const QString &shader_id) const override; + + static const QString kBaseInput; + +protected: + void PushMergableJob(const NodeValueRow &value, const QVariant &job, NodeValueTable *table) const; + +}; + +} + +#endif // GENERATORWITHMERGE_H diff --git a/app/node/generator/shape/shapenode.cpp b/app/node/generator/shape/shapenode.cpp index a0aeb7b03..34db8dfcb 100644 --- a/app/node/generator/shape/shapenode.cpp +++ b/app/node/generator/shape/shapenode.cpp @@ -79,20 +79,7 @@ void ShapeNode::Value(const NodeValueRow &value, const NodeGlobals &globals, Nod job.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); job.SetShaderID(QStringLiteral("shape")); - if (!value[kBaseInput].data().isNull()) { - // Push as merge node - ShaderJob merge; - - merge.SetShaderID(QStringLiteral("mrg")); - merge.InsertValue(MergeNode::kBaseIn, value[kBaseInput]); - merge.InsertValue(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, QVariant::fromValue(job), this)); - merge.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - - table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); - } else { - // Just push generate job - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); - } + PushMergableJob(value, QVariant::fromValue(job), table); } } diff --git a/app/node/generator/shape/shapenode.h b/app/node/generator/shape/shapenode.h index 2df95bed4..7ae7d5469 100644 --- a/app/node/generator/shape/shapenode.h +++ b/app/node/generator/shape/shapenode.h @@ -36,8 +36,7 @@ public: kEllipse }; - NODE_DEFAULT_DESTRUCTOR(ShapeNode) - NODE_COPY_FUNCTION(ShapeNode) + NODE_DEFAULT_FUNCTIONS(ShapeNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/shape/shapenodebase.cpp b/app/node/generator/shape/shapenodebase.cpp index 9a5e2ed6d..4eb411079 100644 --- a/app/node/generator/shape/shapenodebase.cpp +++ b/app/node/generator/shape/shapenodebase.cpp @@ -28,16 +28,14 @@ namespace olive { -#define super Node +#define super GeneratorWithMerge -const QString ShapeNodeBase::kBaseInput = QStringLiteral("base_in"); const QString ShapeNodeBase::kPositionInput = QStringLiteral("pos_in"); const QString ShapeNodeBase::kSizeInput = QStringLiteral("size_in"); const QString ShapeNodeBase::kColorInput = QStringLiteral("color_in"); ShapeNodeBase::ShapeNodeBase(bool create_color_input) { - AddInput(kBaseInput, NodeValue::kTexture, InputFlags(kInputFlagNotKeyframable)); AddInput(kPositionInput, NodeValue::kVec2, QVector2D(0, 0)); AddInput(kSizeInput, NodeValue::kVec2, QVector2D(100, 100)); SetInputProperty(kSizeInput, QStringLiteral("min"), QVector2D(0, 0)); @@ -60,16 +58,12 @@ ShapeNodeBase::ShapeNodeBase(bool create_color_input) for (int i=0; i(pos_n_sz, PointGizmo::kAbsolute); } - - SetEffectInput(kBaseInput); - SetFlags(kVideoEffect); } void ShapeNodeBase::Retranslate() { super::Retranslate(); - SetInputName(kBaseInput, tr("Base")); SetInputName(kPositionInput, tr("Position")); SetInputName(kSizeInput, tr("Size")); @@ -108,15 +102,6 @@ void ShapeNodeBase::UpdateGizmoPositions(const NodeValueRow &row, const NodeGlob poly_gizmo_->SetPolygon(QRectF(left_pt, top_pt, right_pt - left_pt, bottom_pt - top_pt)); } -ShaderCode ShapeNodeBase::GetShaderCode(const QString &shader_id) const -{ - if (shader_id == QStringLiteral("mrg")) { - return ShaderCode(FileFunctions::ReadFileAsString(":/shaders/alphaover.frag")); - } - - return ShaderCode(); -} - void ShapeNodeBase::GizmoDragMove(double x, double y, const Qt::KeyboardModifiers &modifiers) { DraggableGizmo *gizmo = static_cast(sender()); diff --git a/app/node/generator/shape/shapenodebase.h b/app/node/generator/shape/shapenodebase.h index 4079ad3c3..4d9b01006 100644 --- a/app/node/generator/shape/shapenodebase.h +++ b/app/node/generator/shape/shapenodebase.h @@ -21,29 +21,24 @@ #ifndef SHAPENODEBASE_H #define SHAPENODEBASE_H +#include "generatorwithmerge.h" #include "node/gizmo/point.h" #include "node/gizmo/polygon.h" #include "node/inputdragger.h" -#include "node/math/merge/merge.h" #include "node/node.h" namespace olive { -class ShapeNodeBase : public Node +class ShapeNodeBase : public GeneratorWithMerge { Q_OBJECT public: ShapeNodeBase(bool create_color_input = true); - NODE_DEFAULT_DESTRUCTOR(ShapeNodeBase) - virtual void Retranslate() override; virtual void UpdateGizmoPositions(const NodeValueRow &row, const NodeGlobals &globals) override; - virtual ShaderCode GetShaderCode(const QString &shader_id) const override; - - static const QString kBaseInput; static const QString kPositionInput; static const QString kSizeInput; static const QString kColorInput; diff --git a/app/node/generator/solid/solid.cpp b/app/node/generator/solid/solid.cpp index 713a096a7..0bfe93f9c 100644 --- a/app/node/generator/solid/solid.cpp +++ b/app/node/generator/solid/solid.cpp @@ -34,11 +34,6 @@ SolidGenerator::SolidGenerator() AddInput(kColorInput, NodeValue::kColor, QVariant::fromValue(Color(1.0f, 0.0f, 0.0f, 1.0f))); } -Node *SolidGenerator::copy() const -{ - return new SolidGenerator(); -} - QString SolidGenerator::Name() const { return tr("Solid"); diff --git a/app/node/generator/solid/solid.h b/app/node/generator/solid/solid.h index 9e60090bc..55f5bdb50 100644 --- a/app/node/generator/solid/solid.h +++ b/app/node/generator/solid/solid.h @@ -31,9 +31,7 @@ class SolidGenerator : public Node public: SolidGenerator(); - NODE_DEFAULT_DESTRUCTOR(SolidGenerator) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(SolidGenerator) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/text/textv1.h b/app/node/generator/text/textv1.h index 868e22449..85e4f24cf 100644 --- a/app/node/generator/text/textv1.h +++ b/app/node/generator/text/textv1.h @@ -31,8 +31,7 @@ class TextGeneratorV1 : public Node public: TextGeneratorV1(); - NODE_DEFAULT_DESTRUCTOR(TextGeneratorV1) - NODE_COPY_FUNCTION(TextGeneratorV1) + NODE_DEFAULT_FUNCTIONS(TextGeneratorV1) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/text/textv2.h b/app/node/generator/text/textv2.h index d9fb17386..d98443dfc 100644 --- a/app/node/generator/text/textv2.h +++ b/app/node/generator/text/textv2.h @@ -31,8 +31,7 @@ class TextGeneratorV2 : public ShapeNodeBase public: TextGeneratorV2(); - NODE_DEFAULT_DESTRUCTOR(TextGeneratorV2) - NODE_COPY_FUNCTION(TextGeneratorV2) + NODE_DEFAULT_FUNCTIONS(TextGeneratorV2) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/generator/text/textv3.cpp b/app/node/generator/text/textv3.cpp index e56c445e3..4413d6f65 100644 --- a/app/node/generator/text/textv3.cpp +++ b/app/node/generator/text/textv3.cpp @@ -89,20 +89,7 @@ void TextGeneratorV3::Value(const NodeValueRow &value, const NodeGlobals &global job.SetColorspace(project()->color_manager()->GetDefaultInputColorSpace()); if (!job.GetValue(kTextInput).data().toString().isEmpty()) { - if (!value[kBaseInput].data().isNull()) { - // Push as merge node - ShaderJob merge; - - merge.SetShaderID(QStringLiteral("mrg")); - merge.InsertValue(MergeNode::kBaseIn, value[kBaseInput]); - merge.InsertValue(MergeNode::kBlendIn, NodeValue(NodeValue::kTexture, QVariant::fromValue(job), this)); - merge.SetAlphaChannelRequired(GenerateJob::kAlphaForceOn); - - table->Push(NodeValue::kTexture, QVariant::fromValue(merge), this); - } else { - // Just push generate job - table->Push(NodeValue::kTexture, QVariant::fromValue(job), this); - } + PushMergableJob(value, QVariant::fromValue(job), table); } else if (!value[kBaseInput].data().isNull()) { table->Push(value[kBaseInput]); } diff --git a/app/node/generator/text/textv3.h b/app/node/generator/text/textv3.h index 1fd9237c4..f2cd2d47c 100644 --- a/app/node/generator/text/textv3.h +++ b/app/node/generator/text/textv3.h @@ -32,8 +32,7 @@ class TextGeneratorV3 : public ShapeNodeBase public: TextGeneratorV3(); - NODE_DEFAULT_DESTRUCTOR(TextGeneratorV3) - NODE_COPY_FUNCTION(TextGeneratorV3) + NODE_DEFAULT_FUNCTIONS(TextGeneratorV3) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/group/group.h b/app/node/group/group.h index fe2151b26..d906c987e 100644 --- a/app/node/group/group.h +++ b/app/node/group/group.h @@ -31,8 +31,7 @@ class NodeGroup : public Node public: NodeGroup(); - NODE_DEFAULT_DESTRUCTOR(NodeGroup) - NODE_COPY_FUNCTION(NodeGroup) + NODE_DEFAULT_FUNCTIONS(NodeGroup) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/input/time/timeinput.cpp b/app/node/input/time/timeinput.cpp index 96f80f385..b9e46c27a 100644 --- a/app/node/input/time/timeinput.cpp +++ b/app/node/input/time/timeinput.cpp @@ -28,11 +28,6 @@ TimeInput::TimeInput() { } -Node *TimeInput::copy() const -{ - return new TimeInput(); -} - QString TimeInput::Name() const { return tr("Time"); diff --git a/app/node/input/time/timeinput.h b/app/node/input/time/timeinput.h index c5afc75f4..c892e351c 100644 --- a/app/node/input/time/timeinput.h +++ b/app/node/input/time/timeinput.h @@ -27,13 +27,11 @@ namespace olive { class TimeInput : public Node { - Q_OBJECT + Q_OBJECT public: TimeInput(); - NODE_DEFAULT_DESTRUCTOR(TimeInput) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(TimeInput) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/input/value/valuenode.h b/app/node/input/value/valuenode.h index 2d6d2ada8..8d2569786 100644 --- a/app/node/input/value/valuenode.h +++ b/app/node/input/value/valuenode.h @@ -31,12 +31,7 @@ class ValueNode : public Node public: ValueNode(); - NODE_DEFAULT_DESTRUCTOR(ValueNode) - - virtual Node* copy() const override - { - return new ValueNode(); - } + NODE_DEFAULT_FUNCTIONS(ValueNode) virtual QString Name() const override { diff --git a/app/node/keying/colordifferencekey/colordifferencekey.cpp b/app/node/keying/colordifferencekey/colordifferencekey.cpp index 39595e039..534d06a78 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.cpp +++ b/app/node/keying/colordifferencekey/colordifferencekey.cpp @@ -49,11 +49,6 @@ ColorDifferenceKeyNode::ColorDifferenceKeyNode() SetEffectInput(kTextureInput); } -Node *ColorDifferenceKeyNode::copy() const -{ - return new ColorDifferenceKeyNode(); -} - QString ColorDifferenceKeyNode::Name() const { return tr("Color Difference Key"); diff --git a/app/node/keying/colordifferencekey/colordifferencekey.h b/app/node/keying/colordifferencekey/colordifferencekey.h index 01ddaf718..3b4809256 100644 --- a/app/node/keying/colordifferencekey/colordifferencekey.h +++ b/app/node/keying/colordifferencekey/colordifferencekey.h @@ -24,7 +24,7 @@ class ColorDifferenceKeyNode : public Node { public: ColorDifferenceKeyNode(); - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(ColorDifferenceKeyNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/keying/despill/despill.cpp b/app/node/keying/despill/despill.cpp index e72124f31..17ea0a5ca 100644 --- a/app/node/keying/despill/despill.cpp +++ b/app/node/keying/despill/despill.cpp @@ -40,11 +40,6 @@ DespillNode::DespillNode() SetEffectInput(kTextureInput); } -Node* DespillNode::copy() const -{ - return new DespillNode(); -} - QString DespillNode::Name() const { return tr("Despill"); diff --git a/app/node/keying/despill/despill.h b/app/node/keying/despill/despill.h index c5aaed49d..098cb3132 100644 --- a/app/node/keying/despill/despill.h +++ b/app/node/keying/despill/despill.h @@ -25,7 +25,7 @@ class DespillNode : public Node { public: DespillNode(); - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(DespillNode) virtual QString Name() const override; virtual QString id() const override; @@ -36,13 +36,13 @@ class DespillNode : public Node { virtual ShaderCode GetShaderCode(const QString& shader_id) const override; virtual void Value(const NodeValueRow& value, const NodeGlobals& globals, NodeValueTable* table) const override; - + static const QString kTextureInput; static const QString kColorInput; static const QString kMethodInput; static const QString kPreserveLuminanceInput; - - + + }; } // namespace olive diff --git a/app/node/math/math/math.cpp b/app/node/math/math/math.cpp index 932a963d1..123f768fa 100644 --- a/app/node/math/math/math.cpp +++ b/app/node/math/math/math.cpp @@ -42,11 +42,6 @@ MathNode::MathNode() SetInputProperty(kParamBIn, QStringLiteral("autotrim"), true); } -Node *MathNode::copy() const -{ - return new MathNode(); -} - QString MathNode::Name() const { return tr("Math"); diff --git a/app/node/math/math/math.h b/app/node/math/math/math.h index b87b09a19..6001db776 100644 --- a/app/node/math/math/math.h +++ b/app/node/math/math/math.h @@ -31,9 +31,7 @@ class MathNode : public MathNodeBase public: MathNode(); - NODE_DEFAULT_DESTRUCTOR(MathNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(MathNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/math/math/mathbase.cpp b/app/node/math/math/mathbase.cpp index d21e0e613..51ef80060 100644 --- a/app/node/math/math/mathbase.cpp +++ b/app/node/math/math/mathbase.cpp @@ -363,6 +363,7 @@ void MathNodeBase::ValueInternal(Operation operation, Pairing pairing, const QSt QMatrix4x4 adjusted_matrix = TransformDistortNode::AdjustMatrixByResolutions(number_val.data().value(), sequence_res, + texture->params().offset(), texture_res); if (operation != kOpMultiply || adjusted_matrix.isIdentity()) { diff --git a/app/node/math/math/mathbase.h b/app/node/math/math/mathbase.h index 6391c10d3..77f3fe336 100644 --- a/app/node/math/math/mathbase.h +++ b/app/node/math/math/mathbase.h @@ -30,8 +30,6 @@ class MathNodeBase : public Node public: MathNodeBase() = default; - NODE_DEFAULT_DESTRUCTOR(MathNodeBase) - enum Operation { kOpAdd, kOpSubtract, diff --git a/app/node/math/merge/merge.cpp b/app/node/math/merge/merge.cpp index 1f1c9be42..5a911e8a2 100644 --- a/app/node/math/merge/merge.cpp +++ b/app/node/math/merge/merge.cpp @@ -38,11 +38,6 @@ MergeNode::MergeNode() SetFlags(kDontShowInParamView); } -Node *MergeNode::copy() const -{ - return new MergeNode(); -} - QString MergeNode::Name() const { return tr("Merge"); diff --git a/app/node/math/merge/merge.h b/app/node/math/merge/merge.h index fff8bbd5a..f73994a3f 100644 --- a/app/node/math/merge/merge.h +++ b/app/node/math/merge/merge.h @@ -31,9 +31,7 @@ class MergeNode : public Node public: MergeNode(); - NODE_DEFAULT_DESTRUCTOR(MergeNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(MergeNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/math/trigonometry/trigonometry.cpp b/app/node/math/trigonometry/trigonometry.cpp index 5c6e16663..461ba538a 100644 --- a/app/node/math/trigonometry/trigonometry.cpp +++ b/app/node/math/trigonometry/trigonometry.cpp @@ -34,11 +34,6 @@ TrigonometryNode::TrigonometryNode() AddInput(kXIn, NodeValue::kFloat, 0.0); } -olive::Node *olive::TrigonometryNode::copy() const -{ - return new TrigonometryNode(); -} - QString TrigonometryNode::Name() const { return tr("Trigonometry"); diff --git a/app/node/math/trigonometry/trigonometry.h b/app/node/math/trigonometry/trigonometry.h index 1f1058f6b..a78f9ea59 100644 --- a/app/node/math/trigonometry/trigonometry.h +++ b/app/node/math/trigonometry/trigonometry.h @@ -31,9 +31,7 @@ class TrigonometryNode : public Node public: TrigonometryNode(); - NODE_DEFAULT_DESTRUCTOR(TrigonometryNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(TrigonometryNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/node.cpp b/app/node/node.cpp index 4a0c60b03..907287880 100644 --- a/app/node/node.cpp +++ b/app/node/node.cpp @@ -148,7 +148,7 @@ Color Node::color() const if (override_color_ >= 0) { c = override_color_; } else { - c = Config::Current()[QStringLiteral("CatColor%1").arg(this->Category().first())].toInt(); + c = OLIVE_CONFIG_STR(QStringLiteral("CatColor%1").arg(this->Category().first())).toInt(); } return ColorCoding::GetColor(c); @@ -171,7 +171,7 @@ QLinearGradient Node::gradient_color(qreal top, qreal bottom) const QBrush Node::brush(qreal top, qreal bottom) const { - if (Config::Current()[QStringLiteral("UseGradients")].toBool()) { + if (OLIVE_CONFIG("UseGradients").toBool()) { return gradient_color(top, bottom); } else { return color().toQColor(); @@ -1103,7 +1103,7 @@ Node *Node::CopyNodeInGraph(Node *node, MultiUndoCommand *command) { Node* copy; - if (Config::Current()[QStringLiteral("SplitClipsCopyNodes")].toBool()) { + if (OLIVE_CONFIG("SplitClipsCopyNodes").toBool()) { copy = Node::CopyNodeAndDependencyGraphMinusItems(node, command); } else { copy = node->copy(); diff --git a/app/node/node.h b/app/node/node.h index 98fcd8e27..4f45277d6 100644 --- a/app/node/node.h +++ b/app/node/node.h @@ -48,6 +48,10 @@ namespace olive { +#define NODE_DEFAULT_FUNCTIONS(x) \ + NODE_DEFAULT_DESTRUCTOR(x) \ + NODE_COPY_FUNCTION(x) + #define NODE_DEFAULT_DESTRUCTOR(x) \ virtual ~x() override {DisconnectAll();} @@ -100,6 +104,11 @@ public: kAudioEffect = 0x4 }; + struct ContextPair { + Node *node; + Node *context; + }; + Node(); virtual ~Node() override; diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index f4244804b..ce34c2240 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -66,11 +66,6 @@ const Track::Type& Track::type() const return track_type_; } -Node *Track::copy() const -{ - return new Track(); -} - QString Track::Name() const { if (track_type_ == Track::kVideo) { diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 72a1b6a78..237a70f15 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -45,13 +45,11 @@ public: Track(); - NODE_DEFAULT_DESTRUCTOR(Track) + NODE_DEFAULT_FUNCTIONS(Track) const Track::Type& type() const; void set_type(const Track::Type& track_type); - virtual Node* copy() const override; - virtual QString Name() const override; virtual QString id() const override; virtual QVector Category() const override; diff --git a/app/node/output/viewer/viewer.cpp b/app/node/output/viewer/viewer.cpp index ee458d7d5..b1d9db487 100644 --- a/app/node/output/viewer/viewer.cpp +++ b/app/node/output/viewer/viewer.cpp @@ -72,11 +72,6 @@ ViewerOutput::ViewerOutput(bool create_buffer_inputs, bool create_default_stream timeline_points_ = new TimelinePoints(this); } -Node *ViewerOutput::copy() const -{ - return new ViewerOutput(); -} - QString ViewerOutput::Name() const { return tr("Viewer"); @@ -188,26 +183,26 @@ AudioParams ViewerOutput::GetFirstEnabledAudioStream() const void ViewerOutput::set_default_parameters() { - int width = Config::Current()["DefaultSequenceWidth"].toInt(); - int height = Config::Current()["DefaultSequenceHeight"].toInt(); + int width = OLIVE_CONFIG("DefaultSequenceWidth").toInt(); + int height = OLIVE_CONFIG("DefaultSequenceHeight").toInt(); SetVideoParams(VideoParams( width, height, - Config::Current()["DefaultSequenceFrameRate"].value(), - static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + OLIVE_CONFIG("DefaultSequenceFrameRate").value(), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount, - Config::Current()["DefaultSequencePixelAspect"].value(), - Config::Current()["DefaultSequenceInterlacing"].value(), + OLIVE_CONFIG("DefaultSequencePixelAspect").value(), + OLIVE_CONFIG("DefaultSequenceInterlacing").value(), VideoParams::generate_auto_divider(width, height) )); SetAudioParams(AudioParams( - Config::Current()["DefaultSequenceAudioFrequency"].toInt(), - Config::Current()["DefaultSequenceAudioLayout"].toULongLong(), + OLIVE_CONFIG("DefaultSequenceAudioFrequency").toInt(), + OLIVE_CONFIG("DefaultSequenceAudioLayout").toULongLong(), AudioParams::kInternalFormat )); - SetVideoAutoCacheEnabled(Config::Current()["DefaultSequenceAutoCache"].toBool()); + SetVideoAutoCacheEnabled(OLIVE_CONFIG("DefaultSequenceAutoCache").toBool()); } void ViewerOutput::ShiftVideoCache(const rational &from, const rational &to) @@ -475,7 +470,9 @@ void ViewerOutput::set_parameters_from_footage(const QVector foo QVector video_streams = f->GetEnabledVideoStreams(); QVector audio_streams = f->GetEnabledAudioStreams(); - foreach (const VideoParams& s, video_streams) { + for (int i=0; i foo // If this is a still image, we'll use it's resolution but won't set // `found_video_params` in case something with a frame rate comes along which we'll // prioritize + if (i > 0) { + // Ignore still images past stream 0 + continue; + } + using_timebase = GetVideoParams().time_base(); } else { using_timebase = s.frame_rate_as_time_base(); @@ -492,7 +494,7 @@ void ViewerOutput::set_parameters_from_footage(const QVector foo SetVideoParams(VideoParams(s.width(), s.height(), using_timebase, - static_cast(Config::Current()[QStringLiteral("OfflinePixelFormat")].toInt()), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount, s.pixel_aspect_ratio(), s.interlacing(), diff --git a/app/node/output/viewer/viewer.h b/app/node/output/viewer/viewer.h index ee207c6ec..2edf2d344 100644 --- a/app/node/output/viewer/viewer.h +++ b/app/node/output/viewer/viewer.h @@ -46,9 +46,7 @@ class ViewerOutput : public Node public: ViewerOutput(bool create_buffer_inputs = true, bool create_default_streams = true); - NODE_DEFAULT_DESTRUCTOR(ViewerOutput) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(ViewerOutput) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/project/folder/folder.h b/app/node/project/folder/folder.h index 12677e57b..7c779719d 100644 --- a/app/node/project/folder/folder.h +++ b/app/node/project/folder/folder.h @@ -37,12 +37,7 @@ class Folder : public Node public: Folder(); - NODE_DEFAULT_DESTRUCTOR(Folder) - - virtual Node* copy() const override - { - return new Folder(); - } + NODE_DEFAULT_FUNCTIONS(Folder) virtual QString Name() const override { diff --git a/app/node/project/footage/footage.h b/app/node/project/footage/footage.h index aed465106..77202dbe8 100644 --- a/app/node/project/footage/footage.h +++ b/app/node/project/footage/footage.h @@ -55,12 +55,7 @@ public: */ Footage(const QString& filename = QString()); - NODE_DEFAULT_DESTRUCTOR(Footage) - - virtual Node* copy() const override - { - return new Footage(); - } + NODE_DEFAULT_FUNCTIONS(Footage) virtual QString Name() const override { diff --git a/app/node/project/projectsettings/projectsettings.h b/app/node/project/projectsettings/projectsettings.h index ce1890847..35b9d578c 100644 --- a/app/node/project/projectsettings/projectsettings.h +++ b/app/node/project/projectsettings/projectsettings.h @@ -31,7 +31,7 @@ class ProjectSettingsNode : public Node public: ProjectSettingsNode(); - NODE_DEFAULT_DESTRUCTOR(ProjectSettingsNode) + NODE_DEFAULT_FUNCTIONS(ProjectSettingsNode) virtual QString Name() const override { @@ -53,11 +53,6 @@ public: return tr("Settings used throughout the project."); } - virtual Node* copy() const override - { - return new ProjectSettingsNode(); - } - enum CacheSetting { kCacheUseDefaultLocation, kCacheStoreAlongsideProject, diff --git a/app/node/project/sequence/sequence.h b/app/node/project/sequence/sequence.h index 62900b031..40cc9f4d6 100644 --- a/app/node/project/sequence/sequence.h +++ b/app/node/project/sequence/sequence.h @@ -36,12 +36,7 @@ class Sequence : public ViewerOutput public: Sequence(); - NODE_DEFAULT_DESTRUCTOR(Sequence) - - virtual Node* copy() const override - { - return new Sequence(); - } + NODE_DEFAULT_FUNCTIONS(Sequence) virtual QString Name() const override { diff --git a/app/node/project/serializer/serializer210528.cpp b/app/node/project/serializer/serializer210528.cpp index baf53e442..47700b240 100644 --- a/app/node/project/serializer/serializer210528.cpp +++ b/app/node/project/serializer/serializer210528.cpp @@ -605,7 +605,7 @@ void ProjectSerializer210528::LoadMarkerList(QXmlStreamReader *reader, TimelineM } } - new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers); + new TimelineMarker(OLIVE_CONFIG("MarkerColor").toInt(), TimeRange(in, out), name, markers); } reader->skipCurrentElement(); diff --git a/app/node/project/serializer/serializer210907.cpp b/app/node/project/serializer/serializer210907.cpp index 96b69f214..b65678a04 100644 --- a/app/node/project/serializer/serializer210907.cpp +++ b/app/node/project/serializer/serializer210907.cpp @@ -597,7 +597,7 @@ void ProjectSerializer210907::LoadMarkerList(QXmlStreamReader *reader, TimelineM } } - new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers); + new TimelineMarker(OLIVE_CONFIG("MarkerColor").toInt(), TimeRange(in, out), name, markers); } reader->skipCurrentElement(); diff --git a/app/node/project/serializer/serializer211228.cpp b/app/node/project/serializer/serializer211228.cpp index 139fd2438..70ae3b494 100644 --- a/app/node/project/serializer/serializer211228.cpp +++ b/app/node/project/serializer/serializer211228.cpp @@ -647,7 +647,7 @@ void ProjectSerializer211228::LoadMarkerList(QXmlStreamReader *reader, TimelineM } } - new TimelineMarker(Config::Current()[QStringLiteral("MarkerColor")].toInt(), TimeRange(in, out), name, markers); + new TimelineMarker(OLIVE_CONFIG("MarkerColor").toInt(), TimeRange(in, out), name, markers); } reader->skipCurrentElement(); diff --git a/app/node/time/timeoffset/timeoffsetnode.h b/app/node/time/timeoffset/timeoffsetnode.h index b44a1f1e0..961492245 100644 --- a/app/node/time/timeoffset/timeoffsetnode.h +++ b/app/node/time/timeoffset/timeoffsetnode.h @@ -30,8 +30,7 @@ class TimeOffsetNode : public Node public: TimeOffsetNode(); - NODE_DEFAULT_DESTRUCTOR(TimeOffsetNode) - NODE_COPY_FUNCTION(TimeOffsetNode) + NODE_DEFAULT_FUNCTIONS(TimeOffsetNode) virtual QString Name() const override { diff --git a/app/node/time/timeremap/timeremap.cpp b/app/node/time/timeremap/timeremap.cpp index ff2b1ff77..e903ad8eb 100644 --- a/app/node/time/timeremap/timeremap.cpp +++ b/app/node/time/timeremap/timeremap.cpp @@ -39,11 +39,6 @@ TimeRemapNode::TimeRemapNode() AddInput(kInputInput, NodeValue::kNone, InputFlags(kInputFlagNotKeyframable)); } -Node *TimeRemapNode::copy() const -{ - return new TimeRemapNode(); -} - QString TimeRemapNode::Name() const { return tr("Time Remap"); diff --git a/app/node/time/timeremap/timeremap.h b/app/node/time/timeremap/timeremap.h index 6cdaf618a..a9a8cdb53 100644 --- a/app/node/time/timeremap/timeremap.h +++ b/app/node/time/timeremap/timeremap.h @@ -31,9 +31,7 @@ class TimeRemapNode : public Node public: TimeRemapNode(); - NODE_DEFAULT_DESTRUCTOR(TimeRemapNode) - - virtual Node* copy() const override; + NODE_DEFAULT_FUNCTIONS(TimeRemapNode) virtual QString Name() const override; virtual QString id() const override; diff --git a/app/node/traverser.cpp b/app/node/traverser.cpp index 10567fdde..103702fa3 100644 --- a/app/node/traverser.cpp +++ b/app/node/traverser.cpp @@ -307,6 +307,7 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) TexturePtr tex = CreateTexture(tex_params); + PreProcessRow(range, job.GetValues()); ProcessShader(tex, val.source(), range, job); val.set_data(QVariant::fromValue(tex)); @@ -317,14 +318,26 @@ void NodeTraverser::ResolveJobs(NodeValue &val, const TimeRange &range) VideoParams tex_params = GetCacheVideoParams(); tex_params.set_channel_count(GetChannelCountFromJob(job)); + + VideoParams upload_params = tex_params; if (job.GetRequestedFormat() != VideoParams::kFormatInvalid) { - tex_params.set_format(job.GetRequestedFormat()); + upload_params.set_format(job.GetRequestedFormat()); } - TexturePtr tex = CreateTexture(tex_params); + TexturePtr tex = CreateTexture(upload_params); + PreProcessRow(range, job.GetValues()); ProcessFrameGeneration(tex, val.source(), job); + if (!job.GetColorspace().isEmpty()) { + // Convert to reference space + TexturePtr dest = CreateTexture(tex_params); + + ConvertToReferenceSpace(dest, tex, job.GetColorspace()); + + tex = dest; + } + val.set_data(QVariant::fromValue(tex)); } else if (v.canConvert()) { diff --git a/app/node/traverser.h b/app/node/traverser.h index ae6c74867..b806230cb 100644 --- a/app/node/traverser.h +++ b/app/node/traverser.h @@ -95,6 +95,8 @@ protected: virtual void ProcessFrameGeneration(TexturePtr destination, const Node *node, const GenerateJob& job){} + virtual void ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs){} + virtual TexturePtr CreateTexture(const VideoParams &p) { return CreateDummyTexture(p); @@ -108,7 +110,11 @@ protected: SampleBufferPtr CreateSampleBuffer(const AudioParams ¶ms, const rational &length) { - return CreateSampleBuffer(params, params.time_to_samples(length)); + if (params.is_valid()) { + return CreateSampleBuffer(params, params.time_to_samples(length)); + } else { + return SampleBuffer::Create(); + } } virtual bool CanCacheFrames() diff --git a/app/panel/node/node.cpp b/app/panel/node/node.cpp index 5e694867b..d618c7d80 100644 --- a/app/panel/node/node.cpp +++ b/app/panel/node/node.cpp @@ -28,9 +28,10 @@ NodePanel::NodePanel(QWidget *parent) : node_widget_ = new NodeWidget(); connect(this, &NodePanel::visibilityChanged, node_widget_->view(), &NodeView::CenterOnItemsBoundingRect); - // Connect node view signals to this panel - MAY REMOVE connect(node_widget_->view(), &NodeView::NodesSelected, this, &NodePanel::NodesSelected); connect(node_widget_->view(), &NodeView::NodesDeselected, this, &NodePanel::NodesDeselected); + connect(node_widget_->view(), &NodeView::NodeSelectionChanged, this, &NodePanel::NodeSelectionChanged); + connect(node_widget_->view(), &NodeView::NodeSelectionChangedWithContexts, this, &NodePanel::NodeSelectionChangedWithContexts); connect(node_widget_->view(), &NodeView::NodeGroupOpened, this, &NodePanel::NodeGroupOpened); connect(node_widget_->view(), &NodeView::NodeGroupClosed, this, &NodePanel::NodeGroupClosed); diff --git a/app/panel/node/node.h b/app/panel/node/node.h index b9a5ebf35..c8ebccaaa 100644 --- a/app/panel/node/node.h +++ b/app/panel/node/node.h @@ -105,10 +105,9 @@ public: } public slots: - void Select(const QVector& nodes, bool center_view_on_item) + void Select(const QVector &p) { - node_widget_->view()->Select(nodes, center_view_on_item); - this->raise(); + node_widget_->view()->Select(p, true); } signals: @@ -116,6 +115,9 @@ signals: void NodesDeselected(const QVector& nodes); + void NodeSelectionChanged(const QVector& nodes); + void NodeSelectionChangedWithContexts(const QVector& nodes); + void NodeGroupOpened(NodeGroup *group); void NodeGroupClosed(); diff --git a/app/panel/panelmanager.cpp b/app/panel/panelmanager.cpp index e3959bfbf..edef10377 100644 --- a/app/panel/panelmanager.cpp +++ b/app/panel/panelmanager.cpp @@ -49,7 +49,7 @@ PanelWidget *PanelManager::CurrentlyFocused(bool enable_hover) const { // If hover focus is enabled, find the currently hovered panel and return it (if no panel is hovered, resort to // default behavior) - if (enable_hover && Config::Current()[QStringLiteral("HoverFocus")].toBool()) { + if (enable_hover && OLIVE_CONFIG("HoverFocus").toBool()) { PanelWidget* hovered = CurrentlyHovered(); if (hovered != nullptr) { diff --git a/app/panel/param/param.cpp b/app/panel/param/param.cpp index 8504a86b4..368a6abd2 100644 --- a/app/panel/param/param.cpp +++ b/app/panel/param/param.cpp @@ -28,24 +28,14 @@ ParamPanel::ParamPanel(QWidget* parent) : TimeBasedPanel(QStringLiteral("ParamPanel"), parent) { NodeParamView* view = new NodeParamView(); - connect(view, &NodeParamView::RequestSelectNode, this, &ParamPanel::RequestSelectNode); connect(view, &NodeParamView::FocusedNodeChanged, this, &ParamPanel::FocusedNodeChanged); + connect(view, &NodeParamView::SelectedNodesChanged, this, &ParamPanel::SelectedNodesChanged); connect(this, &ParamPanel::visibilityChanged, view, &NodeParamView::UpdateElementY); SetTimeBasedWidget(view); Retranslate(); } -void ParamPanel::SelectNodes(const QVector &nodes) -{ - static_cast(GetTimeBasedWidget())->SelectNodes(nodes); -} - -void ParamPanel::DeselectNodes(const QVector &nodes) -{ - static_cast(GetTimeBasedWidget())->DeselectNodes(nodes); -} - void ParamPanel::DeleteSelected() { static_cast(GetTimeBasedWidget())->DeleteSelected(); diff --git a/app/panel/param/param.h b/app/panel/param/param.h index 25b50a2db..9cfb881c0 100644 --- a/app/panel/param/param.h +++ b/app/panel/param/param.h @@ -49,8 +49,10 @@ public: } public slots: - void SelectNodes(const QVector& nodes); - void DeselectNodes(const QVector& nodes); + void SetSelectedNodes(const QVector &nodes) + { + GetParamView()->SetSelectedNodes(nodes, false); + } virtual void DeleteSelected() override; @@ -61,10 +63,10 @@ public slots: void SetContexts(const QVector &contexts); signals: - void RequestSelectNode(const QVector& target); - void FocusedNodeChanged(Node* n); + void SelectedNodesChanged(const QVector &nodes); + protected: virtual void Retranslate() override; diff --git a/app/render/diskmanager.cpp b/app/render/diskmanager.cpp index af67d6bfa..21b4b0413 100644 --- a/app/render/diskmanager.cpp +++ b/app/render/diskmanager.cpp @@ -196,7 +196,7 @@ DiskCacheFolder::DiskCacheFolder(const QString &path, QObject *parent) : { SetPath(path); - save_timer_.setInterval(Config::Current()[QStringLiteral("DiskCacheSaveInterval")].toInt()); + save_timer_.setInterval(OLIVE_CONFIG("DiskCacheSaveInterval").toInt()); connect(&save_timer_, &QTimer::timeout, this, &DiskCacheFolder::SaveDiskCacheIndex); save_timer_.start(); } diff --git a/app/render/previewautocacher.cpp b/app/render/previewautocacher.cpp index dcdb3d20a..c548b1f8f 100644 --- a/app/render/previewautocacher.cpp +++ b/app/render/previewautocacher.cpp @@ -48,7 +48,7 @@ PreviewAutoCacher::PreviewAutoCacher() : SetPlayhead(0); // Wait a certain amount of time before requeuing when we receive an invalidate signal - delayed_requeue_timer_.setInterval(Config::Current()[QStringLiteral("AutoCacheDelay")].toInt()); + delayed_requeue_timer_.setInterval(OLIVE_CONFIG("AutoCacheDelay").toInt()); delayed_requeue_timer_.setSingleShot(true); connect(&delayed_requeue_timer_, &QTimer::timeout, this, &PreviewAutoCacher::RequeueFrames); @@ -502,8 +502,8 @@ void PreviewAutoCacher::StartCachingAudioRange(const TimeRange &range) void PreviewAutoCacher::SetPlayhead(const rational &playhead) { - cache_range_ = TimeRange(playhead - Config::Current()[QStringLiteral("DiskCacheBehind")].value(), - playhead + Config::Current()[QStringLiteral("DiskCacheAhead")].value()); + cache_range_ = TimeRange(playhead - OLIVE_CONFIG("DiskCacheBehind").value(), + playhead + OLIVE_CONFIG("DiskCacheAhead").value()); RequeueFrames(); } diff --git a/app/render/renderprocessor.cpp b/app/render/renderprocessor.cpp index 51e743d5e..3dd43bca2 100644 --- a/app/render/renderprocessor.cpp +++ b/app/render/renderprocessor.cpp @@ -109,7 +109,7 @@ FramePtr RenderProcessor::GenerateFrame(TexturePtr texture, const rational& time job.SetColorProcessor(output_color_transform); job.SetInputTexture(texture); - job.SetInputAlphaAssociation(Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? kAlphaAssociated : kAlphaNone); + job.SetInputAlphaAssociation(OLIVE_CONFIG("ReassocLinToNonLin").toBool() ? kAlphaAssociated : kAlphaNone); job.SetTransformMatrix(matrix); render_ctx_->BlitColorManaged(job, blit_tex.get()); @@ -523,10 +523,6 @@ void RenderProcessor::ProcessShader(TexturePtr destination, const Node *node, co } } - VideoParams tex_params = GetCacheVideoParams(); - - tex_params.set_channel_count(GetChannelCountFromJob(job)); - // Run shader render_ctx_->BlitToTexture(shader, job, destination.get()); } @@ -575,27 +571,7 @@ void RenderProcessor::ProcessFrameGeneration(TexturePtr destination, const Node node->GenerateFrame(frame, job); - if (job.GetColorspace().isEmpty()) { - // Just upload frame data straight to frame - destination->Upload(frame->data(), frame->linesize_pixels()); - } else { - // Convert to reference space - - // Upload to middle texture - TexturePtr mid = render_ctx_->CreateTexture(GetCacheVideoParams()); - mid->Upload(frame->data(), frame->linesize_pixels()); - - ColorManager* color_manager = Node::ValueToPtr(ticket_->property("colormanager")); - ColorProcessorPtr cp = ColorProcessor::Create(color_manager, job.GetColorspace(), color_manager->GetReferenceColorSpace()); - - ColorTransformJob ctj; - - ctj.SetColorProcessor(cp); - ctj.SetInputTexture(mid); - ctj.SetInputAlphaAssociation(kAlphaAssociated); - - render_ctx_->BlitColorManaged(ctj, destination.get()); - } + destination->Upload(frame->data(), frame->linesize_pixels()); } bool RenderProcessor::CanCacheFrames() @@ -603,4 +579,18 @@ bool RenderProcessor::CanCacheFrames() return ticket_->property("type").value() == RenderManager::kTypeVideo; } +void RenderProcessor::ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs) +{ + ColorManager* color_manager = Node::ValueToPtr(ticket_->property("colormanager")); + ColorProcessorPtr cp = ColorProcessor::Create(color_manager, input_cs, color_manager->GetReferenceColorSpace()); + + ColorTransformJob ctj; + + ctj.SetColorProcessor(cp); + ctj.SetInputTexture(source); + ctj.SetInputAlphaAssociation(kAlphaAssociated); + + render_ctx_->BlitColorManaged(ctj, destination.get()); +} + } diff --git a/app/render/renderprocessor.h b/app/render/renderprocessor.h index 9a1fcaddc..8397b5f45 100644 --- a/app/render/renderprocessor.h +++ b/app/render/renderprocessor.h @@ -68,6 +68,8 @@ protected: return SampleBuffer::CreateAllocated(params, sample_count); } + virtual void ConvertToReferenceSpace(TexturePtr destination, TexturePtr source, const QString &input_cs) override; + private: RenderProcessor(RenderTicketPtr ticket, Renderer* render_ctx, DecoderCache* decoder_cache, ShaderCache* shader_cache, QVariant default_shader); diff --git a/app/render/videoparams.cpp b/app/render/videoparams.cpp index 032357aea..405deb371 100644 --- a/app/render/videoparams.cpp +++ b/app/render/videoparams.cpp @@ -259,6 +259,8 @@ void VideoParams::set_defaults_for_footage() start_time_ = 0; duration_ = 0; premultiplied_alpha_ = false; + x_ = 0; + y_ = 0; } void VideoParams::calculate_square_pixel_width() @@ -327,6 +329,8 @@ QByteArray VideoParams::toBytes() const hasher.addData(reinterpret_cast(&interlacing_), sizeof(interlacing_)); hasher.addData(reinterpret_cast(÷r_), sizeof(divider_)); hasher.addData(reinterpret_cast(&enabled_), sizeof(enabled_)); + hasher.addData(reinterpret_cast(&x_), sizeof(x_)); + hasher.addData(reinterpret_cast(&y_), sizeof(y_)); hasher.addData(reinterpret_cast(&stream_index_), sizeof(stream_index_)); hasher.addData(reinterpret_cast(&video_type_), sizeof(video_type_)); hasher.addData(reinterpret_cast(&frame_rate_), sizeof(frame_rate_)); @@ -370,6 +374,10 @@ void VideoParams::Load(QXmlStreamReader *reader) set_divider(reader->readElementText().toInt()); } else if (reader->name() == QStringLiteral("enabled")) { set_enabled(reader->readElementText().toInt()); + } else if (reader->name() == QStringLiteral("x")) { + set_x(reader->readElementText().toFloat()); + } else if (reader->name() == QStringLiteral("y")) { + set_y(reader->readElementText().toFloat()); } else if (reader->name() == QStringLiteral("streamindex")) { set_stream_index(reader->readElementText().toInt()); } else if (reader->name() == QStringLiteral("videotype")) { @@ -402,6 +410,8 @@ void VideoParams::Save(QXmlStreamWriter *writer) const writer->writeTextElement(QStringLiteral("interlacing"), QString::number(interlacing_)); writer->writeTextElement(QStringLiteral("divider"), QString::number(divider_)); writer->writeTextElement(QStringLiteral("enabled"), QString::number(enabled_)); + writer->writeTextElement(QStringLiteral("x"), QString::number(x_)); + writer->writeTextElement(QStringLiteral("y"), QString::number(y_)); writer->writeTextElement(QStringLiteral("streamindex"), QString::number(stream_index_)); writer->writeTextElement(QStringLiteral("videotype"), QString::number(video_type_)); writer->writeTextElement(QStringLiteral("framerate"), frame_rate_.toString()); diff --git a/app/render/videoparams.h b/app/render/videoparams.h index 4179e7ea0..c86e77d4c 100644 --- a/app/render/videoparams.h +++ b/app/render/videoparams.h @@ -21,6 +21,7 @@ #ifndef VIDEOPARAMS_H #define VIDEOPARAMS_H +#include #include #include @@ -273,6 +274,12 @@ public: enabled_ = e; } + float x() const { return x_; } + void set_x(float x) { x_ = x; } + float y() const { return y_; } + void set_y(float y) { y_ = y; } + QVector2D offset() const { return QVector2D(x_, y_); } + int stream_index() const { return stream_index_; @@ -387,6 +394,8 @@ private: int64_t duration_; bool premultiplied_alpha_; QString colorspace_; + float x_; + float y_; }; diff --git a/app/shaders/noise.frag b/app/shaders/noise.frag index 4a2296e91..7439eea76 100644 --- a/app/shaders/noise.frag +++ b/app/shaders/noise.frag @@ -2,7 +2,9 @@ uniform float time_in; uniform float strength_in; uniform bool color_in; -//uniform bool blend; + +uniform sampler2D base_in; +uniform bool base_in_enabled; in vec2 ove_texcoord; out vec4 frag_color; @@ -22,7 +24,7 @@ bool isNan( float val ) } float gold_noise(vec2 coordinate, float seed){ - float value = fract(tan(distance(coordinate*(seed+PHI), vec2(PHI, PI)))*SQ2)*(strength_in*0.01); + float value = fract(tan(distance(coordinate*(seed+PHI), vec2(PHI, PI)))*SQ2)*(strength_in); return isNan(value) ? 0.0 : value; } @@ -34,5 +36,11 @@ void main(void) { noise = vec3(gold_noise(ove_texcoord, time_in + 69420.0)); } + if (base_in_enabled) { + vec4 base = texture(base_in, ove_texcoord); + base.rgb += noise; + frag_color = base; + } else { frag_color = vec4(noise, 1.0); + } } diff --git a/app/task/project/import/import.cpp b/app/task/project/import/import.cpp index 352a8f175..900cc1d8b 100644 --- a/app/task/project/import/import.cpp +++ b/app/task/project/import/import.cpp @@ -203,7 +203,7 @@ void ProjectImportTask::ValidateImageSequence(Footage *footage, QFileInfoList& i // User has confirmed it is a still image, let's set it accordingly. video_stream.set_video_type(VideoParams::kVideoTypeImageSequence); - rational default_timebase = Config::Current()[QStringLiteral("DefaultSequenceFrameRate")].value(); + rational default_timebase = OLIVE_CONFIG("DefaultSequenceFrameRate").value(); video_stream.set_time_base(default_timebase); video_stream.set_frame_rate(default_timebase.flipped()); diff --git a/app/timeline/timelinemarker.cpp b/app/timeline/timelinemarker.cpp index 32eb98976..5fb5fb1fd 100644 --- a/app/timeline/timelinemarker.cpp +++ b/app/timeline/timelinemarker.cpp @@ -29,7 +29,7 @@ namespace olive { TimelineMarker::TimelineMarker(QObject *parent) : - color_(Config::Current()[QStringLiteral("MarkerColor")].toInt()) + color_(OLIVE_CONFIG("MarkerColor").toInt()) { setParent(parent); } diff --git a/app/ui/style/style.cpp b/app/ui/style/style.cpp index a63845984..af255fa38 100644 --- a/app/ui/style/style.cpp +++ b/app/ui/style/style.cpp @@ -136,7 +136,7 @@ void StyleManager::Init() available_themes_.insert(QStringLiteral("olive-dark"), QStringLiteral("Olive Dark")); available_themes_.insert(QStringLiteral("olive-light"), QStringLiteral("Olive Light")); - QString config_style = Config::Current()["Style"].toString(); + QString config_style = OLIVE_CONFIG("Style").toString(); if (config_style.isEmpty() || !available_themes_.contains(config_style)) { SetStyle(kDefaultStyle); diff --git a/app/widget/colorwheel/colorvalueswidget.cpp b/app/widget/colorwheel/colorvalueswidget.cpp index d65cf6b33..cb0218395 100644 --- a/app/widget/colorwheel/colorvalueswidget.cpp +++ b/app/widget/colorwheel/colorvalueswidget.cpp @@ -233,7 +233,7 @@ ColorValuesTab::ColorValuesTab(bool with_legacy_option, QWidget *parent) : if (with_legacy_option) { legacy_box_ = new QCheckBox(tr("Use legacy (8-bit) values")); - legacy_box_->setChecked(Config::Current()[QStringLiteral("UseLegacyColorInInputTab")].toBool()); + legacy_box_->setChecked(OLIVE_CONFIG("UseLegacyColorInInputTab").toBool()); connect(legacy_box_, &QCheckBox::clicked, this, &ColorValuesTab::LegacyChanged); layout->addWidget(legacy_box_, row, 0, 1, 2); row++; @@ -356,7 +356,7 @@ void ColorValuesTab::SliderChanged() void ColorValuesTab::LegacyChanged(bool legacy) { - Config::Current()[QStringLiteral("UseLegacyColorInInputTab")] = legacy; + OLIVE_CONFIG("UseLegacyColorInInputTab") = legacy; double legacy_multiplier = legacy ? kLegacyMultiplier : 1.0/kLegacyMultiplier; int decimal_places = legacy ? 0 : 5; diff --git a/app/widget/handmovableview/handmovableview.cpp b/app/widget/handmovableview/handmovableview.cpp index 5e0daa151..87086dcdc 100644 --- a/app/widget/handmovableview/handmovableview.cpp +++ b/app/widget/handmovableview/handmovableview.cpp @@ -32,7 +32,7 @@ namespace olive { HandMovableView::HandMovableView(QWidget* parent) : super(parent), dragging_hand_(false), - scroll_zooms_by_default_(Config::Current()[QStringLiteral("ScrollZooms")].toBool()) + scroll_zooms_by_default_(OLIVE_CONFIG("ScrollZooms").toBool()) { connect(Core::instance(), &Core::ToolChanged, this, &HandMovableView::ApplicationToolChanged); } diff --git a/app/widget/nodeparamview/nodeparamview.cpp b/app/widget/nodeparamview/nodeparamview.cpp index f812c121e..2f97d8133 100644 --- a/app/widget/nodeparamview/nodeparamview.cpp +++ b/app/widget/nodeparamview/nodeparamview.cpp @@ -155,10 +155,11 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) : SetScale(120); // Pickup on widget focus changes - connect(qApp, + // DISABLED - we now just handle this with item/titlebar clicking (see ToggleSelect) + /*connect(qApp, &QApplication::focusChanged, this, - &NodeParamView::FocusChanged); + &NodeParamView::FocusChanged);*/ } NodeParamView::~NodeParamView() @@ -297,12 +298,25 @@ void NodeParamView::ItemAboutToBeRemoved(NodeParamViewItem *item) } } - if (focused_node_ == item) { - focused_node_ = nullptr; - emit FocusedNodeChanged(nullptr); + QVector copy = selected_nodes_; + if (copy.removeOne(item)) { + SetSelectedNodes(copy); } } +void NodeParamView::ItemClicked() +{ + ToggleSelect(static_cast(sender())); +} + +void NodeParamView::SelectNodeFromConnectedLink(Node *node) +{ + NodeParamViewItem *item = static_cast(sender()); + + Node::ContextPair p = {node, item->GetContext()}; + SetSelectedNodes({p}); +} + void NodeParamView::SetContexts(const QVector &contexts) { // Setting contexts is expensive, so we queue it here to prevent multiple calls in a short timespan @@ -371,41 +385,138 @@ Node *NodeParamView::GetTimeTarget() const return time_target_; } +void ReconnectOutputsIfNotDeletingNode(MultiUndoCommand *c, NodeViewDeleteCommand *dc, Node *output, Node *deleting, Node *context) +{ + for (auto it=deleting->output_connections().cbegin(); it!=deleting->output_connections().cend(); it++) { + const NodeInput &proposed_reconnect = it->second; + + if (dc->ContainsNode(proposed_reconnect.node(), context)) { + // Uh-oh we're deleting this node too, instead connect to its outputs + ReconnectOutputsIfNotDeletingNode(c, dc, output, proposed_reconnect.node(), context); + } else { + c->add_child(new NodeEdgeAddCommand(output, it->second)); + } + } +} + void NodeParamView::DeleteSelected() { if (keyframe_view_ && keyframe_view_->hasFocus()) { keyframe_view_->DeleteSelected(); - } else if (focused_node_) { + } else if (!selected_nodes_.isEmpty()) { MultiUndoCommand *c = new MultiUndoCommand(); - Node *n = focused_node_->GetNode(); // Create command to delete node from context and/or graph NodeViewDeleteCommand *dc = new NodeViewDeleteCommand(); - dc->AddNode(n, focused_node_->GetContext()); c->add_child(dc); - // Copy any outputs that were connected - if (n->GetEffectInput().IsValid()) { - if (Node *out = n->GetEffectInput().GetConnectedOutput()) { - for (auto it=n->output_connections().cbegin(); it!=n->output_connections().cend(); it++) { - c->add_child(new NodeEdgeAddCommand(out, it->second)); - } - } + // Add all nodes + foreach (NodeParamViewItem *item, selected_nodes_) { + Node *n = item->GetNode(); + dc->AddNode(n, item->GetContext()); } + // Make reconnections where possible + foreach (NodeParamViewItem *item, selected_nodes_) { + Node *n = item->GetNode(); + + Node *node_being_deleted = n; + Node *connected_to_effect_input = n; + + while (true) { + if (node_being_deleted->GetEffectInput().IsValid()) { + if ((connected_to_effect_input = node_being_deleted->GetEffectInput().GetConnectedOutput())) { + if (dc->ContainsNode(connected_to_effect_input, item->GetContext())) { + // Node's getting deleted, recurse + node_being_deleted = connected_to_effect_input; + continue; + } + } + } + + break; + } + + if (connected_to_effect_input) { + ReconnectOutputsIfNotDeletingNode(c, dc, connected_to_effect_input, n, item->GetContext()); + } + } Core::instance()->undo_stack()->push(c); } } -void NodeParamView::SelectNodes(const QVector &nodes) +void NodeParamView::SetSelectedNodes(const QVector &nodes, bool handle_focused_node, bool emit_signal) { - // Do nothing, this is a placeholder if we ever need this to do anything in the future + if (handle_focused_node) { + handle_focused_node = !focused_node_ || selected_nodes_.contains(focused_node_); + } + + foreach (NodeParamViewItem *n, selected_nodes_) { + n->SetHighlighted(false); + } + + selected_nodes_ = nodes; + + QVector p; + if (emit_signal) { + p.resize(selected_nodes_.size()); + } + + for (int i=0; iSetHighlighted(true); + + if (emit_signal) { + p[i] = {n->GetNode(), n->GetContext()}; + } + } + + if (handle_focused_node) { + focused_node_ = nullptr; + + foreach (NodeParamViewItem *n, selected_nodes_) { + if (n->GetNode()->HasGizmos()) { + focused_node_ = n; + break; + } + } + + Node *n = focused_node_ ? focused_node_->GetNode() : nullptr; + emit FocusedNodeChanged(n); + } + + if (emit_signal) { + emit SelectedNodesChanged(p); + } } -void NodeParamView::DeselectNodes(const QVector &nodes) +void NodeParamView::SetSelectedNodes(const QVector &nodes, bool emit_signal) { - // Do nothing, this is a placeholder if we ever need this to do anything in the future + QVector items; + + foreach (const Node::ContextPair &n, nodes) { + for (auto it=context_items_.cbegin(); it!=context_items_.cend(); it++) { + NodeParamViewContext *ctx = *it; + + NodeParamViewItem *item = ctx->GetItem(n.node, n.context); + + if (item) { + items.append(item); + } + } + } + + SetSelectedNodes(items, true, emit_signal); + + if (!selected_nodes_.empty()) { + NodeParamViewItem *scrolled_to = selected_nodes_.front(); + param_scroll_area_->ensureWidgetVisible(scrolled_to, 0, 0); + + QPoint viewport_pos = scrolled_to->mapTo(param_scroll_area_, scrolled_to->geometry().topLeft()); + + param_scroll_area_->verticalScrollBar()->setValue(viewport_pos.y()); + } } void NodeParamView::UpdateItemTime(const rational &time) @@ -461,9 +572,10 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) NodeParamViewItem* item = new NodeParamViewItem(n, IsGroupMode() ? kCheckBoxesOnNonConnected : kNoCheckBoxes, context); connect(item, &NodeParamViewItem::RequestSetTime, this, &NodeParamView::SetTimeAndSignal); - connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::RequestSelectNode); + connect(item, &NodeParamViewItem::RequestSelectNode, this, &NodeParamView::SelectNodeFromConnectedLink); connect(item, &NodeParamViewItem::PinToggled, this, &NodeParamView::PinNode); connect(item, &NodeParamViewItem::InputCheckedChanged, this, &NodeParamView::InputCheckBoxChanged); + connect(item, &NodeParamViewItem::Clicked, this, &NodeParamView::ItemClicked); item->SetContext(ctx); item->SetTimeTarget(GetTimeTarget()); @@ -474,9 +586,7 @@ void NodeParamView::AddNode(Node *n, Node *ctx, NodeParamViewContext *context) if (!focused_node_ && n->HasGizmos()) { // We'll focus this node now - item->SetHighlighted(true); - focused_node_ = item; - emit FocusedNodeChanged(n); + SetSelectedNodes({item}); } if (keyframe_view_) { @@ -561,6 +671,36 @@ NodeParamViewContext *NodeParamView::GetContextItemFromContext(Node *ctx) return context_items_.at(ctx_type); } +void NodeParamView::ToggleSelect(NodeParamViewItem *item) +{ + QVector new_sel; + + if (qApp->keyboardModifiers() & Qt::ShiftModifier) { + new_sel = selected_nodes_; + } + + if (selected_nodes_.contains(item)) { + // De-select this node + if (qApp->keyboardModifiers() & Qt::ShiftModifier) { + new_sel.removeOne(item); + SetSelectedNodes(new_sel, true); + } + } else { + new_sel.append(item); + SetSelectedNodes(new_sel, false); + + if (item->GetNode()->HasGizmos() || !new_sel.contains(focused_node_)) { + if (item->GetNode()->HasGizmos()) { + focused_node_ = item; + } else { + focused_node_ = nullptr; + } + + emit FocusedNodeChanged(focused_node_ ? focused_node_->GetNode() : nullptr); + } + } +} + void NodeParamView::UpdateGlobalScrollBar() { if (keyframe_view_) { @@ -584,7 +724,7 @@ void NodeParamView::PinNode(bool pin) } } -void NodeParamView::FocusChanged(QWidget* old, QWidget* now) +/*void NodeParamView::FocusChanged(QWidget* old, QWidget* now) { Q_UNUSED(old) @@ -592,39 +732,28 @@ void NodeParamView::FocusChanged(QWidget* old, QWidget* now) while (parent) { if (NodeParamViewItem* item = dynamic_cast(parent)) { - if (item != focused_node_) { - // Found a NodeParamViewItem that isn't already focused, see if it belongs to us - bool ours = false; + // Found a NodeParamViewItem that isn't already focused, see if it belongs to us + bool ours = false; - do { - parent = parent->parent(); + do { + parent = parent->parent(); - if (parent == this) { - ours = true; - break; - } - } while (parent); - - if (ours) { - // This item is ours, - if (focused_node_) { - // De-focus current node - focused_node_->SetHighlighted(false); - } - - focused_node_ = item; - - item->SetHighlighted(true); - - emit FocusedNodeChanged(item->GetNode()); + if (parent == this) { + ours = true; + break; } + } while (parent); + + if (ours) { + //ToggleSelect(item); + Q_UNUSED(item) } break; } parent = parent->parent(); } -} +}*/ void NodeParamView::KeyframeViewDragged(int x, int y) { diff --git a/app/widget/nodeparamview/nodeparamview.h b/app/widget/nodeparamview/nodeparamview.h index f04072e52..3b90e22b7 100644 --- a/app/widget/nodeparamview/nodeparamview.h +++ b/app/widget/nodeparamview/nodeparamview.h @@ -61,8 +61,8 @@ public: keyframe_view_->DeselectAll(); } - void SelectNodes(const QVector &nodes); - void DeselectNodes(const QVector &nodes); + void SetSelectedNodes(const QVector &nodes, bool handle_focused_node = true, bool emit_signal = true); + void SetSelectedNodes(const QVector &nodes, bool emit_signal = true); const QVector &GetContexts() const { @@ -75,10 +75,10 @@ public slots: void UpdateElementY(); signals: - void RequestSelectNode(const QVector& target); - void FocusedNodeChanged(Node* n); + void SelectedNodesChanged(const QVector &nodes); + protected: virtual void resizeEvent(QResizeEvent *event) override; @@ -118,6 +118,8 @@ private: return contexts_.size() == 1 && dynamic_cast(contexts_.first()); } + void ToggleSelect(NodeParamViewItem *item); + KeyframeView* keyframe_view_; QVector context_items_; @@ -137,6 +139,7 @@ private: QVector active_nodes_; NodeParamViewItem* focused_node_; + QVector selected_nodes_; Node *time_target_; @@ -150,7 +153,7 @@ private slots: void PinNode(bool pin); - void FocusChanged(QWidget *old, QWidget *now); + //void FocusChanged(QWidget *old, QWidget *now); void KeyframeViewDragged(int x, int y); @@ -168,6 +171,10 @@ private slots: void ItemAboutToBeRemoved(NodeParamViewItem *item); + void ItemClicked(); + + void SelectNodeFromConnectedLink(Node *node); + }; } diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp index 2810113a1..d55fbe103 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.cpp @@ -135,7 +135,7 @@ void NodeParamViewConnectedLabel::ShowLabelContextMenu() void NodeParamViewConnectedLabel::ConnectionClicked() { if (connected_node_) { - emit RequestSelectNode({connected_node_}); + emit RequestSelectNode(connected_node_); } } diff --git a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h index 621a697e1..3e4fc5f55 100644 --- a/app/widget/nodeparamview/nodeparamviewconnectedlabel.h +++ b/app/widget/nodeparamview/nodeparamviewconnectedlabel.h @@ -35,7 +35,7 @@ public: void SetTime(const rational &time); signals: - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *n); private slots: void InputConnected(Node *output, const NodeInput &input); diff --git a/app/widget/nodeparamview/nodeparamviewitem.h b/app/widget/nodeparamview/nodeparamviewitem.h index 95ee238d8..3db8692a1 100644 --- a/app/widget/nodeparamview/nodeparamviewitem.h +++ b/app/widget/nodeparamview/nodeparamviewitem.h @@ -67,7 +67,7 @@ public: signals: void RequestSetTime(const rational& time); - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *node); void ArrayExpandedChanged(bool e); @@ -214,7 +214,7 @@ public: signals: void RequestSetTime(const rational& time); - void RequestSelectNode(const QVector& node); + void RequestSelectNode(Node *node); void ArrayExpandedChanged(bool e); diff --git a/app/widget/nodeparamview/nodeparamviewitembase.cpp b/app/widget/nodeparamview/nodeparamviewitembase.cpp index f29d70702..645ee79f1 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.cpp +++ b/app/widget/nodeparamview/nodeparamviewitembase.cpp @@ -40,6 +40,7 @@ NodeParamViewItemBase::NodeParamViewItemBase(QWidget *parent) : // Connect title bar to this connect(title_bar_, &NodeParamViewItemTitleBar::ExpandedStateChanged, this, &NodeParamViewItemBase::SetExpanded); connect(title_bar_, &NodeParamViewItemTitleBar::PinToggled, this, &NodeParamViewItemBase::PinToggled); + connect(title_bar_, &NodeParamViewItemTitleBar::Clicked, this, &NodeParamViewItemBase::Clicked); // Use dummy QWidget to retain width when not expanded (QDockWidget seems to ignore the titlebar // size hints and will shrink as small as possible if the body is hidden) @@ -115,4 +116,11 @@ void NodeParamViewItemBase::moveEvent(QMoveEvent *event) emit Moved(); } +void NodeParamViewItemBase::mousePressEvent(QMouseEvent *e) +{ + super::mousePressEvent(e); + + emit Clicked(); +} + } diff --git a/app/widget/nodeparamview/nodeparamviewitembase.h b/app/widget/nodeparamview/nodeparamviewitembase.h index d5f570656..a728bb93f 100644 --- a/app/widget/nodeparamview/nodeparamviewitembase.h +++ b/app/widget/nodeparamview/nodeparamviewitembase.h @@ -60,6 +60,8 @@ signals: void Moved(); + void Clicked(); + protected: void SetBody(QWidget *body); @@ -74,6 +76,8 @@ protected: virtual void moveEvent(QMoveEvent *event) override; + virtual void mousePressEvent(QMouseEvent *e) override; + protected slots: virtual void Retranslate(){} diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp index 1d79ff4d9..efe3d2768 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.cpp @@ -85,6 +85,13 @@ void NodeParamViewItemTitleBar::paintEvent(QPaintEvent *event) } } +void NodeParamViewItemTitleBar::mousePressEvent(QMouseEvent *event) +{ + QWidget::mousePressEvent(event); + + emit Clicked(); +} + void NodeParamViewItemTitleBar::mouseDoubleClickEvent(QMouseEvent *event) { QWidget::mouseDoubleClickEvent(event); diff --git a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h index 9bea7f06f..7024c9e82 100644 --- a/app/widget/nodeparamview/nodeparamviewitemtitlebar.h +++ b/app/widget/nodeparamview/nodeparamviewitemtitlebar.h @@ -79,9 +79,12 @@ signals: void EnabledCheckBoxClicked(bool e); + void Clicked(); + protected: virtual void paintEvent(QPaintEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseDoubleClickEvent(QMouseEvent *event) override; private: diff --git a/app/widget/nodeview/nodeview.cpp b/app/widget/nodeview/nodeview.cpp index 07251995d..220a040bf 100644 --- a/app/widget/nodeview/nodeview.cpp +++ b/app/widget/nodeview/nodeview.cpp @@ -51,7 +51,8 @@ NodeView::NodeView(QWidget *parent) : create_edge_output_item_(nullptr), create_edge_input_item_(nullptr), overlay_view_(nullptr), - scale_(1.0) + scale_(1.0), + dont_emit_selection_signals_(false) { setScene(&scene_); SetDefaultDragMode(RubberBandDrag); @@ -171,9 +172,11 @@ void NodeView::DeselectAll() // Just emit all the nodes that are currently selected as no longer selected emit NodesDeselected(selected_nodes_); selected_nodes_.clear(); + emit NodeSelectionChanged(selected_nodes_); + emit NodeSelectionChangedWithContexts(QVector()); } -void NodeView::Select(const QVector &nodes, bool center_view_on_item) +void NodeView::Select(const QVector &nodes, bool center_view_on_item) { // Optimization: rather than respond to every single item being selected, ignore the signal and // then handle them all at the end. @@ -184,18 +187,27 @@ void NodeView::Select(const QVector &nodes, bool center_view_on_item) scene_.DeselectAll(); - foreach (NodeViewContext *context, scene_.context_map()) { - context->Select(nodes); + foreach (const Node::ContextPair &p, nodes) { + NodeViewContext *ctx = scene_.context_map().value(p.context); + if (ctx) { + NodeViewItem *item = ctx->GetItemFromMap(p.node); + if (item) { + item->setSelected(true); + } + } } // Center on something if (center_view_on_item && !nodes.isEmpty()) { - QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first())); + QMetaObject::invokeMethod(this, "CenterOnNode", Qt::QueuedConnection, OLIVE_NS_ARG(Node*, nodes.first().node)); } ConnectSelectionChangedSignal(); + // Don't signal when this function was likely triggered from another widget's signal anyway + dont_emit_selection_signals_ = true; UpdateSelectionCache(); + dont_emit_selection_signals_ = false; } void NodeView::CopySelected(bool cut) @@ -734,13 +746,18 @@ void NodeView::UpdateSelectionCache() QVector selected; QVector deselected; + QVector sel_with_ctx(current_selection.size()); + // Determine which nodes are newly selected - foreach (NodeViewItem* i, current_selection) { + for (int j=0; jGetNode(); if (!selected_nodes_.contains(n)) { selected.append(n); selected_nodes_.append(n); } + + sel_with_ctx[j] = {n, i->GetContext()}; } // Determine which nodes are newly deselected @@ -773,6 +790,11 @@ void NodeView::UpdateSelectionCache() if (!selected.isEmpty()) { emit NodesSelected(selected); } + + if (!dont_emit_selection_signals_) { + emit NodeSelectionChanged(selected_nodes_); + emit NodeSelectionChangedWithContexts(sel_with_ctx); + } } void NodeView::ShowContextMenu(const QPoint &pos) @@ -1344,6 +1366,8 @@ void NodeView::ShowNodeProperties() overlay_view_->setFocus(); emit NodesDeselected(selected_nodes_); + emit NodeSelectionChanged(QVector()); + emit NodeSelectionChangedWithContexts(QVector()); overlay_view_->SelectAll(); emit NodeGroupOpened(group); diff --git a/app/widget/nodeview/nodeview.h b/app/widget/nodeview/nodeview.h index 26894511e..d18d2d185 100644 --- a/app/widget/nodeview/nodeview.h +++ b/app/widget/nodeview/nodeview.h @@ -77,7 +77,7 @@ public: void SelectAll(); void DeselectAll(); - void Select(const QVector &nodes, bool center_view_on_item); + void Select(const QVector &nodes, bool center_view_on_item); void CopySelected(bool cut); void Paste(); @@ -117,6 +117,9 @@ signals: void NodesDeselected(const QVector& nodes); + void NodeSelectionChanged(const QVector& nodes); + void NodeSelectionChangedWithContexts(const QVector& nodes); + void NodeGroupOpened(NodeGroup *group); void NodeGroupClosed(); @@ -218,6 +221,8 @@ private: double scale_; + bool dont_emit_selection_signals_; + static const double kMinimumScale; private slots: diff --git a/app/widget/nodeview/nodeviewundo.cpp b/app/widget/nodeview/nodeviewundo.cpp index 54106070f..2ed0ef28b 100644 --- a/app/widget/nodeview/nodeviewundo.cpp +++ b/app/widget/nodeview/nodeviewundo.cpp @@ -199,13 +199,12 @@ NodeViewDeleteCommand::NodeViewDeleteCommand() void NodeViewDeleteCommand::AddNode(Node *node, Node *context) { - foreach (const NodePair &pair, nodes_) { - if (pair.first == node && pair.second == context) { - return; - } + if (ContainsNode(node, context)) { + return; } - nodes_.append(NodePair({node, context})); + Node::ContextPair p = {node, context}; + nodes_.append(p); for (auto it=node->input_connections().cbegin(); it!=node->input_connections().cend(); it++) { if (context->ContextContainsNode(it->second)) { @@ -231,10 +230,21 @@ void NodeViewDeleteCommand::AddEdge(Node *output, const NodeInput &input) edges_.append({output, input}); } +bool NodeViewDeleteCommand::ContainsNode(Node *node, Node *context) +{ + foreach (const Node::ContextPair &pair, nodes_) { + if (pair.node == node && pair.context == context) { + return true; + } + } + + return false; +} + Project *NodeViewDeleteCommand::GetRelevantProject() const { if (!nodes_.isEmpty()) { - return nodes_.first().first->project(); + return nodes_.first().node->project(); } if (!edges_.isEmpty()) { @@ -250,11 +260,11 @@ void NodeViewDeleteCommand::redo() Node::DisconnectEdge(edge.first, edge.second); } - foreach (const NodePair &pair, nodes_) { + foreach (const Node::ContextPair &pair, nodes_) { RemovedNode rn; - rn.node = pair.first; - rn.context = pair.second; + rn.node = pair.node; + rn.context = pair.context; rn.pos = rn.context->GetNodePositionInContext(rn.node); rn.context->RemoveNodeFromContext(rn.node); diff --git a/app/widget/nodeview/nodeviewundo.h b/app/widget/nodeview/nodeviewundo.h index 567198b5b..bb4588444 100644 --- a/app/widget/nodeview/nodeviewundo.h +++ b/app/widget/nodeview/nodeviewundo.h @@ -372,6 +372,8 @@ public: void AddEdge(Node *output, const NodeInput &input); + bool ContainsNode(Node *node, Node *context); + virtual Project * GetRelevantProject() const override; protected: @@ -380,9 +382,7 @@ protected: virtual void undo() override; private: - using NodePair = QPair; - - QVector nodes_; + QVector nodes_; QVector edges_; diff --git a/app/widget/scope/scopebase/scopebase.cpp b/app/widget/scope/scopebase/scopebase.cpp index 2e152e052..fc7c11774 100644 --- a/app/widget/scope/scopebase/scopebase.cpp +++ b/app/widget/scope/scopebase/scopebase.cpp @@ -53,7 +53,7 @@ void ScopeBase::DrawScope(TexturePtr managed_tex, QVariant pipeline) job.InsertValue(QStringLiteral("ove_maintex"), NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); renderer()->Blit(pipeline, job, VideoParams(width(), height(), - static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount)); } diff --git a/app/widget/scope/waveform/waveform.cpp b/app/widget/scope/waveform/waveform.cpp index 1962be72f..7bd440751 100644 --- a/app/widget/scope/waveform/waveform.cpp +++ b/app/widget/scope/waveform/waveform.cpp @@ -73,7 +73,7 @@ void WaveformScope::DrawScope(TexturePtr managed_tex, QVariant pipeline) NodeValue(NodeValue::kTexture, QVariant::fromValue(managed_tex))); renderer()->Blit(pipeline, job, VideoParams(width(), height(), - static_cast(Config::Current()["OfflinePixelFormat"].toInt()), + static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()), VideoParams::kInternalChannelCount)); float waveform_dim_x = ceil((width() - 1.0) * waveform_scale); diff --git a/app/widget/slider/base/numericsliderbase.cpp b/app/widget/slider/base/numericsliderbase.cpp index 5dc4b7d6f..3e65d83ee 100644 --- a/app/widget/slider/base/numericsliderbase.cpp +++ b/app/widget/slider/base/numericsliderbase.cpp @@ -139,7 +139,7 @@ bool NumericSliderBase::IsDragging() const bool NumericSliderBase::UsingLadders() const { - return ladder_element_count_ > 0 && Config::Current()[QStringLiteral("UseSliderLadders")].toBool(); + return ladder_element_count_ > 0 && OLIVE_CONFIG("UseSliderLadders").toBool(); } QVariant NumericSliderBase::AdjustValue(const QVariant &value) const diff --git a/app/widget/slider/base/sliderladder.cpp b/app/widget/slider/base/sliderladder.cpp index b85ed4d95..c7a5ec7ad 100644 --- a/app/widget/slider/base/sliderladder.cpp +++ b/app/widget/slider/base/sliderladder.cpp @@ -48,7 +48,7 @@ SliderLadder::SliderLadder(double drag_multiplier, int nb_outer_values, QString setFrameShape(QFrame::Box); setLineWidth(1); - if (!Config::Current()[QStringLiteral("UseSliderLadders")].toBool()) { + if (!OLIVE_CONFIG("UseSliderLadders").toBool()) { nb_outer_values = 0; } diff --git a/app/widget/timebased/timebasedwidget.cpp b/app/widget/timebased/timebasedwidget.cpp index 379dd8102..ae9ae8746 100644 --- a/app/widget/timebased/timebasedwidget.cpp +++ b/app/widget/timebased/timebasedwidget.cpp @@ -292,7 +292,7 @@ void TimeBasedWidget::SetTime(const rational &time) QMetaObject::invokeMethod(this, "CatchUpScrollToPlayhead", Qt::QueuedConnection); } else { // Otherwise, assume we jumped to this out of nowhere and must now autoscroll - switch (static_cast(Config::Current()["Autoscroll"].toInt())) { + switch (static_cast(OLIVE_CONFIG("Autoscroll").toInt())) { case AutoScroll::kNone: // Do nothing break; @@ -606,12 +606,12 @@ void TimeBasedWidget::SetMarker() color = closest->color(); } else { // Fallback to default color in preferences - color = Config::Current()[QStringLiteral("MarkerColor")].toInt(); + color = OLIVE_CONFIG("MarkerColor").toInt(); } TimelineMarker *marker = new TimelineMarker(color, TimeRange(GetTime(), GetTime())); - if (Config::Current()[QStringLiteral("SetNameWithMarker")].toBool()) { + if (OLIVE_CONFIG("SetNameWithMarker").toBool()) { MarkerPropertiesDialog mpd({marker}, timebase(), this); if (mpd.exec() != QDialog::Accepted) { delete marker; diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index eba333b85..4f2a67647 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -1079,6 +1079,9 @@ void TimelineWidget::ShowContextMenu() } } + QAction* rename_action = menu.addAction(tr("Rename")); + connect(rename_action, &QAction::triggered, this, &TimelineWidget::RenameSelectedBlocks); + QAction* properties_action = menu.addAction(tr("Properties")); connect(properties_action, &QAction::triggered, this, &TimelineWidget::ShowSpeedDurationDialogForSelectedClips); } @@ -1232,6 +1235,19 @@ void TimelineWidget::RevealInProject() emit RevealViewerInProject(item_to_reveal); } +void TimelineWidget::RenameSelectedBlocks() +{ + MultiUndoCommand *command = new MultiUndoCommand(); + QVector nodes(selected_blocks_.size()); + + for (int i=0; iLabelNodes(nodes); + Core::instance()->undo_stack()->pushIfHasChildren(command); +} + void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost) { ghost_items_.append(ghost); diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index a0b9afaaa..cd515b67f 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -414,6 +414,8 @@ private slots: void RevealInProject(); + void RenameSelectedBlocks(); + }; } diff --git a/app/widget/timelinewidget/tool/import.cpp b/app/widget/timelinewidget/tool/import.cpp index fdcd49afc..ed81a6f8b 100644 --- a/app/widget/timelinewidget/tool/import.cpp +++ b/app/widget/timelinewidget/tool/import.cpp @@ -222,7 +222,7 @@ void ImportTool::FootageToGhosts(rational ghost_start, const DraggedFootageData if (footage_duration.isNull()) { // Fallback to still length if legngth was 0 - footage_duration = Config::Current()[QStringLiteral("DefaultStillLength")].value(); + footage_duration = OLIVE_CONFIG("DefaultStillLength").value(); } } @@ -285,7 +285,7 @@ void ImportTool::DropGhosts(bool insert) } else { // There's no active timeline here, ask the user what to do - DropWithoutSequenceBehavior behavior = static_cast(Config::Current()["DropWithoutSequenceBehavior"].toInt()); + DropWithoutSequenceBehavior behavior = static_cast(OLIVE_CONFIG("DropWithoutSequenceBehavior").toInt()); if (behavior == kDWSAsk) { QCheckBox* dont_ask_again_box = new QCheckBox(QCoreApplication::translate("ImportTool", "Don't ask me again")); @@ -312,7 +312,7 @@ void ImportTool::DropGhosts(bool insert) } if (behavior != kDWSDisable && dont_ask_again_box->isChecked()) { - Config::Current()["DropWithoutSequenceBehavior"] = behavior; + OLIVE_CONFIG("DropWithoutSequenceBehavior") = behavior; } } diff --git a/app/widget/timelinewidget/undo/timelineundogeneral.h b/app/widget/timelinewidget/undo/timelineundogeneral.h index 40396f549..7c3df0a72 100644 --- a/app/widget/timelinewidget/undo/timelineundogeneral.h +++ b/app/widget/timelinewidget/undo/timelineundogeneral.h @@ -107,7 +107,7 @@ private: class TimelineAddTrackCommand : public UndoCommand { public: TimelineAddTrackCommand(TrackList *timeline) : - TimelineAddTrackCommand(timeline, Config::Current()[QStringLiteral("AutoMergeTracks")].toBool()) + TimelineAddTrackCommand(timeline, OLIVE_CONFIG("AutoMergeTracks").toBool()) { } diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index 32f268c03..567d1d0f1 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -158,7 +158,7 @@ void TimelineView::wheelEvent(QWheelEvent *event) QPoint angle_delta = event->angleDelta(); - if (Config::Current()[QStringLiteral("InvertTimelineScrollAxes")].toBool() // Check if config is set to invert timeline axes + if (OLIVE_CONFIG("InvertTimelineScrollAxes").toBool() // Check if config is set to invert timeline axes && event->source() != Qt::MouseEventSynthesizedBySystem) { // Never flip axes on Apple trackpads though angle_delta = QPoint(angle_delta.y(), angle_delta.x()); } @@ -184,7 +184,7 @@ void TimelineView::wheelEvent(QWheelEvent *event) Qt::Orientation orientation = event->orientation(); - if (Config::Current()["InvertTimelineScrollAxes"].toBool()) { + if (OLIVE_CONFIG("InvertTimelineScrollAxes").toBool()) { orientation = (orientation == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal; } @@ -307,7 +307,7 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect) Block *attached = Node::ValueToPtr(ghost->GetData(TimelineViewGhostItem::kAttachedBlock)); - if (attached && Config::Current()[QStringLiteral("ShowClipWhileDragging")].toBool()) { + if (attached && OLIVE_CONFIG("ShowClipWhileDragging").toBool()) { int adj_track = ghost->GetAdjustedTrack().index(); qreal track_top = GetTrackY(adj_track); qreal track_height = GetTrackHeight(adj_track); diff --git a/app/widget/viewer/viewer.cpp b/app/widget/viewer/viewer.cpp index f8b25247a..80fe1a444 100644 --- a/app/widget/viewer/viewer.cpp +++ b/app/widget/viewer/viewer.cpp @@ -741,7 +741,7 @@ void ViewerWidget::PauseInternal() void ViewerWidget::PushScrubbedAudio() { - if (!IsPlaying() && GetConnectedNode() && Config::Current()[QStringLiteral("AudioScrubbing")].toBool()) { + if (!IsPlaying() && GetConnectedNode() && OLIVE_CONFIG("AudioScrubbing").toBool()) { // Get audio src device from renderer const AudioParams& params = GetConnectedNode()->audio_playback_cache()->GetParameters(); @@ -1129,9 +1129,9 @@ void ViewerWidget::ShowContextMenu(const QPoint &pos) { QAction *stop_playback_on_last_frame = menu.addAction(tr("Stop Playback On Last Frame")); stop_playback_on_last_frame->setCheckable(true); - stop_playback_on_last_frame->setChecked(Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")].toBool()); + stop_playback_on_last_frame->setChecked(OLIVE_CONFIG("StopPlaybackOnLastFrame").toBool()); connect(stop_playback_on_last_frame, &QAction::triggered, this, [](bool e){ - Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")] = e; + OLIVE_CONFIG("StopPlaybackOnLastFrame") = e; }); menu.addSeparator(); @@ -1180,7 +1180,7 @@ void ViewerWidget::Play(bool in_to_out_only) recording_filename_ = audio_path.filePath(QStringLiteral("%1.%2").arg( QDateTime::currentDateTime().toString("yyyy-MM-dd hh-mm-ss"), - ExportFormat::GetExtension(static_cast(Config::Current()[QStringLiteral("AudioRecordingFormat")].toInt()))) + ExportFormat::GetExtension(static_cast(OLIVE_CONFIG("AudioRecordingFormat").toInt()))) ); AudioParams ap(OLIVE_CONFIG("AudioRecordingSampleRate").toInt(), OLIVE_CONFIG("AudioRecordingChannelLayout").toULongLong(), static_cast(OLIVE_CONFIG("AudioRecordingSampleFormat").toInt())); @@ -1304,7 +1304,7 @@ void ViewerWidget::PlaybackTimerUpdate() // If we're stopping playback on the last frame rather than after it, subtract our max time // by one timebase unit - if (Config::Current()[QStringLiteral("StopPlaybackOnLastFrame")].toBool()) { + if (OLIVE_CONFIG("StopPlaybackOnLastFrame").toBool()) { max_time = qMax(min_time, max_time - timebase()); } @@ -1329,7 +1329,7 @@ void ViewerWidget::PlaybackTimerUpdate() // or restart playback end_of_line = true; - if (Config::Current()[QStringLiteral("Loop")].toBool() && !recording_) { + if (OLIVE_CONFIG("Loop").toBool() && !recording_) { // If we're looping, jump to the other side of the workarea and continue time_to_set = (tripped_time == min_time) ? max_time : min_time; diff --git a/app/widget/viewer/viewerdisplay.cpp b/app/widget/viewer/viewerdisplay.cpp index aeabbd3af..2d6d0513e 100644 --- a/app/widget/viewer/viewerdisplay.cpp +++ b/app/widget/viewer/viewerdisplay.cpp @@ -428,7 +428,7 @@ void ViewerDisplayWidget::OnPaint() // Draw texture through color transform int device_width = width() * devicePixelRatioF(); int device_height = height() * devicePixelRatioF(); - VideoParams::Format device_format = static_cast(Config::Current()["OfflinePixelFormat"].toInt()); + VideoParams::Format device_format = static_cast(OLIVE_CONFIG("OfflinePixelFormat").toInt()); VideoParams device_params(device_width, device_height, device_format, VideoParams::kInternalChannelCount); if (push_mode_ == kPushBlank) { @@ -488,7 +488,7 @@ void ViewerDisplayWidget::OnPaint() ColorTransformJob ctj; ctj.SetColorProcessor(color_service()); ctj.SetInputTexture(texture_to_draw); - ctj.SetInputAlphaAssociation(Config::Current()[QStringLiteral("ReassocLinToNonLin")].toBool() ? kAlphaAssociated : kAlphaNone); + ctj.SetInputAlphaAssociation(OLIVE_CONFIG("ReassocLinToNonLin").toBool() ? kAlphaAssociated : kAlphaNone); ctj.SetClearDestinationEnabled(false); ctj.SetTransformMatrix(combined_matrix_flipped_); ctj.SetCropMatrix(crop_matrix_); diff --git a/app/window/mainwindow/mainmenu.cpp b/app/window/mainwindow/mainmenu.cpp index c4ba08d5e..dec12a79e 100644 --- a/app/window/mainwindow/mainmenu.cpp +++ b/app/window/mainwindow/mainmenu.cpp @@ -381,7 +381,7 @@ void MainMenu::ToolsMenuAboutToShow() void MainMenu::PlaybackMenuAboutToShow() { - playback_loop_item_->setChecked(Config::Current()["Loop"].toBool()); + playback_loop_item_->setChecked(OLIVE_CONFIG("Loop").toBool()); } void MainMenu::SequenceMenuAboutToShow() @@ -506,7 +506,7 @@ void MainMenu::PlayInToOutTriggered() void MainMenu::LoopTriggered(bool enabled) { - Config::Current()["Loop"] = enabled; + OLIVE_CONFIG("Loop") = enabled; } void MainMenu::NextFrameTriggered() diff --git a/app/window/mainwindow/mainwindow.cpp b/app/window/mainwindow/mainwindow.cpp index 6e02ffc07..1bf868ffd 100644 --- a/app/window/mainwindow/mainwindow.cpp +++ b/app/window/mainwindow/mainwindow.cpp @@ -92,15 +92,12 @@ MainWindow::MainWindow(QWidget *parent) : scope_panel_ = new ScopePanel(this); // Make node-related connections - connect(node_panel_, &NodePanel::NodesSelected, param_panel_, &ParamPanel::SelectNodes); - connect(node_panel_, &NodePanel::NodesDeselected, param_panel_, &ParamPanel::DeselectNodes); + connect(node_panel_, &NodePanel::NodeSelectionChangedWithContexts, param_panel_, &ParamPanel::SetSelectedNodes); connect(node_panel_, &NodePanel::NodeGroupOpened, this, &MainWindow::NodePanelGroupOpenedOrClosed); connect(node_panel_, &NodePanel::NodeGroupClosed, this, &MainWindow::NodePanelGroupOpenedOrClosed); - connect(param_panel_, &ParamPanel::RequestSelectNode, this, [this](const QVector& target){ - node_panel_->Select(target, true); - }); connect(param_panel_, &ParamPanel::FocusedNodeChanged, sequence_viewer_panel_, &ViewerPanel::SetGizmos); connect(param_panel_, &ParamPanel::FocusedNodeChanged, curve_panel_, &CurvePanel::SetNode); + connect(param_panel_, &ParamPanel::SelectedNodesChanged, node_panel_, &NodePanel::Select); // Connect time signals together connect(sequence_viewer_panel_, &SequenceViewerPanel::TimeChanged, param_panel_, &ParamPanel::SetTime); @@ -473,7 +470,7 @@ void MainWindow::TimelinePanelSelectionChanged(const QVector &blocks) void MainWindow::ShowWelcomeDialog() { - if (Config::Current()[QStringLiteral("ShowWelcomeDialog")].toBool()) { + if (OLIVE_CONFIG("ShowWelcomeDialog").toBool()) { AboutDialog ad(true, this); ad.exec(); }