diff --git a/UI/window-basic-filters.cpp b/UI/window-basic-filters.cpp index 63d57f8f6..5ceb638ef 100644 --- a/UI/window-basic-filters.cpp +++ b/UI/window-basic-filters.cpp @@ -732,12 +732,18 @@ void OBSBasicFilters::CustomContextMenu(const QPoint &pos, bool async) popup.addMenu(addMenu); if (item) { + const char *dulpicateSlot = + async ? SLOT(DuplicateAsyncFilter()) + : SLOT(DuplicateEffectFilter()); + const char *renameSlot = async ? SLOT(RenameAsyncFilter()) : SLOT(RenameEffectFilter()); const char *removeSlot = async ? SLOT(on_removeAsyncFilter_clicked()) : SLOT(on_removeEffectFilter_clicked()); + popup.addSeparator(); + popup.addAction(QTStr("Duplicate"), this, dulpicateSlot); popup.addSeparator(); popup.addAction(QTStr("Rename"), this, renameSlot); popup.addAction(QTStr("Remove"), this, removeSlot); @@ -781,6 +787,58 @@ void OBSBasicFilters::EditItem(QListWidgetItem *item, bool async) editActive = true; } +void OBSBasicFilters::DuplicateItem(QListWidgetItem *item) +{ + OBSSource filter = item->data(Qt::UserRole).value(); + string name = obs_source_get_name(filter); + obs_source_t *existing_filter; + + QString placeholder = QString::fromStdString(name); + QString text{placeholder}; + int i = 2; + while ((existing_filter = obs_source_get_filter_by_name( + source, QT_TO_UTF8(text)))) { + obs_source_release(existing_filter); + text = QString("%1 %2").arg(placeholder).arg(i++); + } + + bool success = NameDialog::AskForName( + this, QTStr("Basic.Filters.AddFilter.Title"), + QTStr("Basic.Filters.AddFilter.Text"), name, text); + if (!success) + return; + + if (name.empty()) { + OBSMessageBox::warning(this, QTStr("NoNameEntered.Title"), + QTStr("NoNameEntered.Text")); + DuplicateItem(item); + return; + } + + existing_filter = obs_source_get_filter_by_name(source, name.c_str()); + if (existing_filter) { + OBSMessageBox::warning(this, QTStr("NameExists.Title"), + QTStr("NameExists.Text")); + obs_source_release(existing_filter); + DuplicateItem(item); + return; + } + bool enabled = obs_source_enabled(filter); + obs_source_t *new_filter = + obs_source_duplicate(filter, name.c_str(), false); + if (new_filter) { + const char *sourceName = obs_source_get_name(source); + const char *id = obs_source_get_id(new_filter); + blog(LOG_INFO, + "User duplicated filter '%s' (%s) from '%s' " + "to source '%s'", + name.c_str(), id, name.c_str(), sourceName); + obs_source_set_enabled(new_filter, enabled); + obs_source_filter_add(source, new_filter); + obs_source_release(new_filter); + } +} + void OBSBasicFilters::on_asyncFilters_customContextMenuRequested( const QPoint &pos) { @@ -803,6 +861,16 @@ void OBSBasicFilters::RenameEffectFilter() EditItem(ui->effectFilters->currentItem(), false); } +void OBSBasicFilters::DuplicateAsyncFilter() +{ + DuplicateItem(ui->asyncFilters->currentItem()); +} + +void OBSBasicFilters::DuplicateEffectFilter() +{ + DuplicateItem(ui->effectFilters->currentItem()); +} + void OBSBasicFilters::FilterNameEdited(QWidget *editor, QListWidget *list) { QListWidgetItem *listItem = list->currentItem(); diff --git a/UI/window-basic-filters.hpp b/UI/window-basic-filters.hpp index 6932836b1..06ce940dd 100644 --- a/UI/window-basic-filters.hpp +++ b/UI/window-basic-filters.hpp @@ -67,6 +67,7 @@ private: void CustomContextMenu(const QPoint &pos, bool async); void EditItem(QListWidgetItem *item, bool async); + void DuplicateItem(QListWidgetItem *item); void FilterNameEdited(QWidget *editor, QListWidget *list); @@ -82,6 +83,8 @@ private slots: void ReorderFilters(); void RenameAsyncFilter(); void RenameEffectFilter(); + void DuplicateAsyncFilter(); + void DuplicateEffectFilter(); void ResetFilters(); void AddFilterFromAction();