From d790d5d51e087fe4a6968a68a8c25dcfe7e4c391 Mon Sep 17 00:00:00 2001 From: Exeldro Date: Fri, 17 Feb 2023 15:08:46 +0100 Subject: [PATCH] UI: Add frontend copy paste functions --- UI/api-interface.cpp | 18 +++ UI/obs-frontend-api/obs-frontend-api.cpp | 19 +++ UI/obs-frontend-api/obs-frontend-api.h | 4 + UI/obs-frontend-api/obs-frontend-internal.hpp | 5 + UI/window-basic-main.cpp | 113 +++++++++--------- UI/window-basic-main.hpp | 3 + docs/sphinx/reference-frontend-api.rst | 26 ++++ 7 files changed, 131 insertions(+), 57 deletions(-) diff --git a/UI/api-interface.cpp b/UI/api-interface.cpp index 8fb3bea3a..6f5447422 100644 --- a/UI/api-interface.cpp +++ b/UI/api-interface.cpp @@ -747,6 +747,24 @@ struct OBSStudioAPI : obs_frontend_callbacks { undo_data, redo_data, repeatable); } + void obs_frontend_copy_sceneitem(obs_sceneitem_t *item) override + { + main->clipboard.clear(); + main->CopySceneItem(item); + main->UpdateEditMenu(); + } + + bool obs_frontend_can_paste_sceneitem(bool duplicate) override + { + return main->CanPasteSceneItem(duplicate); + } + + void obs_frontend_paste_sceneitem(obs_scene_t *scene, + bool duplicate) override + { + main->PasteSceneItem(scene, duplicate); + } + void on_load(obs_data_t *settings) override { for (size_t i = saveCallbacks.size(); i > 0; i--) { diff --git a/UI/obs-frontend-api/obs-frontend-api.cpp b/UI/obs-frontend-api/obs-frontend-api.cpp index df753551b..b2be09a71 100644 --- a/UI/obs-frontend-api/obs-frontend-api.cpp +++ b/UI/obs-frontend-api/obs-frontend-api.cpp @@ -631,3 +631,22 @@ void obs_frontend_add_undo_redo_action(const char *name, c->obs_frontend_add_undo_redo_action( name, undo, redo, undo_data, redo_data, repeatable); } + +void obs_frontend_copy_sceneitem(obs_sceneitem_t *item) +{ + if (callbacks_valid()) + return c->obs_frontend_copy_sceneitem(item); +} + +bool obs_frontend_can_paste_sceneitem(bool duplicate) +{ + if (!callbacks_valid()) + return false; + return c->obs_frontend_can_paste_sceneitem(duplicate); +} + +void obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate) +{ + if (callbacks_valid()) + return c->obs_frontend_paste_sceneitem(scene, duplicate); +} diff --git a/UI/obs-frontend-api/obs-frontend-api.h b/UI/obs-frontend-api/obs-frontend-api.h index a0913e683..2453f4fde 100644 --- a/UI/obs-frontend-api/obs-frontend-api.h +++ b/UI/obs-frontend-api/obs-frontend-api.h @@ -252,6 +252,10 @@ EXPORT void obs_frontend_add_undo_redo_action( const char *name, const undo_redo_cb undo, const undo_redo_cb redo, const char *undo_data, const char *redo_data, bool repeatable); +EXPORT void obs_frontend_copy_sceneitem(obs_sceneitem_t *item); +EXPORT bool obs_frontend_can_paste_sceneitem(bool duplicate); +EXPORT void obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate); + /* ------------------------------------------------------------------------- */ #ifdef __cplusplus diff --git a/UI/obs-frontend-api/obs-frontend-internal.hpp b/UI/obs-frontend-api/obs-frontend-internal.hpp index 90a0e06ea..f0d1c2fe9 100644 --- a/UI/obs-frontend-api/obs-frontend-internal.hpp +++ b/UI/obs-frontend-api/obs-frontend-internal.hpp @@ -167,6 +167,11 @@ struct obs_frontend_callbacks { const char *undo_data, const char *redo_data, bool repeatable) = 0; + + virtual void obs_frontend_copy_sceneitem(obs_sceneitem_t *item) = 0; + virtual bool obs_frontend_can_paste_sceneitem(bool duplicate) = 0; + virtual void obs_frontend_paste_sceneitem(obs_scene_t *scene, + bool duplicate) = 0; }; EXPORT void diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 0621d039c..d186034dd 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -8579,22 +8579,6 @@ void OBSBasic::UpdateEditMenu() filter_count = obs_source_filter_count(source); } - bool allowPastingDuplicate = !!clipboard.size(); - for (size_t i = clipboard.size(); i > 0; i--) { - const size_t idx = i - 1; - OBSWeakSource &weak = clipboard[idx].weak_source; - if (obs_weak_source_expired(weak)) { - clipboard.erase(clipboard.begin() + idx); - continue; - } - OBSSourceAutoRelease strong = - obs_weak_source_get_source(weak.Get()); - if (allowPastingDuplicate && - obs_source_get_output_flags(strong) & - OBS_SOURCE_DO_NOT_DUPLICATE) - allowPastingDuplicate = false; - } - int videoCount = 0; bool canTransformMultiple = false; for (int i = 0; i < totalCount; i++) { @@ -8621,8 +8605,8 @@ void OBSBasic::UpdateEditMenu() ui->actionCopyFilters->setEnabled(filter_count > 0); ui->actionPasteFilters->setEnabled( !obs_weak_source_expired(copyFiltersSource) && totalCount > 0); - ui->actionPasteRef->setEnabled(!!clipboard.size()); - ui->actionPasteDup->setEnabled(allowPastingDuplicate); + ui->actionPasteRef->setEnabled(CanPasteSceneItem(false)); + ui->actionPasteDup->setEnabled(CanPasteSceneItem(true)); ui->actionMoveUp->setEnabled(totalCount > 0); ui->actionMoveDown->setEnabled(totalCount > 0); @@ -8642,6 +8626,29 @@ void OBSBasic::UpdateEditMenu() ui->actionHorizontalCenter->setEnabled(canTransformMultiple); } +bool OBSBasic::CanPasteSceneItem(bool duplicate) +{ + if (!duplicate) + return !!clipboard.size(); + + bool allowPastingDuplicate = !!clipboard.size(); + for (size_t i = clipboard.size(); i > 0; i--) { + const size_t idx = i - 1; + OBSWeakSource &weak = clipboard[idx].weak_source; + if (obs_weak_source_expired(weak)) { + clipboard.erase(clipboard.begin() + idx); + continue; + } + OBSSourceAutoRelease strong = + obs_weak_source_get_source(weak.Get()); + if (allowPastingDuplicate && + obs_source_get_output_flags(strong) & + OBS_SOURCE_DO_NOT_DUPLICATE) + allowPastingDuplicate = false; + } + return allowPastingDuplicate; +} + void OBSBasic::on_actionEditTransform_triggered() { const auto item = GetCurrentSceneItem(); @@ -10014,31 +10021,39 @@ void OBSBasic::on_actionCopySource_triggered() clipboard.clear(); for (auto &selectedSource : GetAllSelectedSourceItems()) { - OBSSceneItem item = ui->sources->Get(selectedSource.row()); - if (!item) - continue; - - OBSSource source = obs_sceneitem_get_source(item); - - SourceCopyInfo copyInfo; - copyInfo.weak_source = OBSGetWeakRef(source); - obs_sceneitem_get_info2(item, ©Info.transform); - obs_sceneitem_get_crop(item, ©Info.crop); - copyInfo.blend_method = obs_sceneitem_get_blending_method(item); - copyInfo.blend_mode = obs_sceneitem_get_blending_mode(item); - copyInfo.visible = obs_sceneitem_visible(item); - - clipboard.push_back(copyInfo); + CopySceneItem(ui->sources->Get(selectedSource.row())); } - UpdateEditMenu(); } +void OBSBasic::CopySceneItem(OBSSceneItem item) +{ + if (!item) + return; + OBSSource source = obs_sceneitem_get_source(item); + + SourceCopyInfo copyInfo; + copyInfo.weak_source = OBSGetWeakRef(source); + obs_sceneitem_get_info2(item, ©Info.transform); + obs_sceneitem_get_crop(item, ©Info.crop); + copyInfo.blend_method = obs_sceneitem_get_blending_method(item); + copyInfo.blend_mode = obs_sceneitem_get_blending_mode(item); + copyInfo.visible = obs_sceneitem_visible(item); + + clipboard.push_back(copyInfo); +} + void OBSBasic::on_actionPasteRef_triggered() { - OBSSource scene_source = GetCurrentSceneSource(); + PasteSceneItem(GetCurrentScene(), false); +} + +void OBSBasic::PasteSceneItem(OBSScene scene, bool duplicate) +{ + if (!scene || !clipboard.size()) + return; + OBSSource scene_source = obs_scene_get_source(scene); OBSData undo_data = BackupScene(scene_source); - OBSScene scene = GetCurrentScene(); undo_s.push_disabled(); @@ -10053,16 +10068,17 @@ void OBSBasic::on_actionPasteRef_triggered() /* do not allow duplicate refs of the same group in the same * scene */ - if (!!obs_scene_get_group(scene, name)) { + if (!duplicate && !!obs_scene_get_group(scene, name)) { continue; } - OBSBasicSourceSelect::SourcePaste(copyInfo, false); + OBSBasicSourceSelect::SourcePaste(copyInfo, duplicate); } undo_s.pop_disabled(); - QString action_name = QTStr("Undo.PasteSourceRef"); + QString action_name = + QTStr(duplicate ? "Undo.PasteSource" : "Undo.PasteSourceRef"); const char *scene_name = obs_source_get_name(scene_source); OBSData redo_data = BackupScene(scene_source); @@ -10072,24 +10088,7 @@ void OBSBasic::on_actionPasteRef_triggered() void OBSBasic::on_actionPasteDup_triggered() { - OBSSource scene_source = GetCurrentSceneSource(); - OBSData undo_data = BackupScene(scene_source); - - undo_s.push_disabled(); - - for (size_t i = clipboard.size(); i > 0; i--) { - SourceCopyInfo ©Info = clipboard[i - 1]; - OBSBasicSourceSelect::SourcePaste(copyInfo, true); - } - - undo_s.pop_disabled(); - - QString action_name = QTStr("Undo.PasteSource"); - const char *scene_name = obs_source_get_name(scene_source); - - OBSData redo_data = BackupScene(scene_source); - CreateSceneUndoRedoAction(action_name.arg(scene_name), undo_data, - redo_data); + PasteSceneItem(GetCurrentScene(), true); } void OBSBasic::AudioMixerCopyFilters() diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 8c4104c11..8bb046adc 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -1039,6 +1039,9 @@ public: obs_data_array_t *redo_array); void UpdateEditMenu(); + void CopySceneItem(OBSSceneItem item); + bool CanPasteSceneItem(bool duplicate); + void PasteSceneItem(OBSScene scene, bool duplicate); void SetDisplayAffinity(QWindow *window); diff --git a/docs/sphinx/reference-frontend-api.rst b/docs/sphinx/reference-frontend-api.rst index 241ad7e61..1343435a2 100644 --- a/docs/sphinx/reference-frontend-api.rst +++ b/docs/sphinx/reference-frontend-api.rst @@ -932,3 +932,29 @@ Functions This uses the undo action from the first and the redo action from the last action. .. versionadded:: 29.1 + +--------------------------------------- + +.. function:: void obs_frontend_copy_sceneitem(obs_sceneitem_t *item) + + :param item: The scene item to copy + + .. versionadded:: 31.0 + +--------------------------------------- + +.. function:: bool obs_frontend_can_paste_sceneitem(bool duplicate) + + :param duplicate: Check if the copied source allows duplication. + :return: Whether there is a scene item copied and can be pasted + + .. versionadded:: 31.0 + +--------------------------------------- + +.. function:: void obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate) + + :param scene: The scene to paste on + :param duplicate: *true* for paste duplicate, *false* for paste reference + + .. versionadded:: 31.0