Compare commits

...

2 commits

Author SHA1 Message Date
Exeldro 8bc31dc453
Merge d790d5d51e into 0ea90380b4 2024-06-13 12:36:29 +00:00
Exeldro d790d5d51e UI: Add frontend copy paste functions 2024-04-05 09:52:44 +02:00
7 changed files with 131 additions and 57 deletions

View file

@ -774,6 +774,24 @@ struct OBSStudioAPI : obs_frontend_callbacks {
undo_data, redo_data, repeatable); 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 void on_load(obs_data_t *settings) override
{ {
for (size_t i = saveCallbacks.size(); i > 0; i--) { for (size_t i = saveCallbacks.size(); i > 0; i--) {

View file

@ -637,3 +637,22 @@ void obs_frontend_add_undo_redo_action(const char *name,
c->obs_frontend_add_undo_redo_action( c->obs_frontend_add_undo_redo_action(
name, undo, redo, undo_data, redo_data, repeatable); 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);
}

View file

@ -253,6 +253,10 @@ EXPORT void obs_frontend_add_undo_redo_action(
const char *name, const undo_redo_cb undo, const undo_redo_cb redo, const char *name, const undo_redo_cb undo, const undo_redo_cb redo,
const char *undo_data, const char *redo_data, bool repeatable); 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 #ifdef __cplusplus

View file

@ -168,6 +168,11 @@ struct obs_frontend_callbacks {
const char *undo_data, const char *undo_data,
const char *redo_data, const char *redo_data,
bool repeatable) = 0; 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 EXPORT void

View file

@ -8599,22 +8599,6 @@ void OBSBasic::UpdateEditMenu()
filter_count = obs_source_filter_count(source); 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; int videoCount = 0;
bool canTransformMultiple = false; bool canTransformMultiple = false;
for (int i = 0; i < totalCount; i++) { for (int i = 0; i < totalCount; i++) {
@ -8641,8 +8625,8 @@ void OBSBasic::UpdateEditMenu()
ui->actionCopyFilters->setEnabled(filter_count > 0); ui->actionCopyFilters->setEnabled(filter_count > 0);
ui->actionPasteFilters->setEnabled( ui->actionPasteFilters->setEnabled(
!obs_weak_source_expired(copyFiltersSource) && totalCount > 0); !obs_weak_source_expired(copyFiltersSource) && totalCount > 0);
ui->actionPasteRef->setEnabled(!!clipboard.size()); ui->actionPasteRef->setEnabled(CanPasteSceneItem(false));
ui->actionPasteDup->setEnabled(allowPastingDuplicate); ui->actionPasteDup->setEnabled(CanPasteSceneItem(true));
ui->actionMoveUp->setEnabled(totalCount > 0); ui->actionMoveUp->setEnabled(totalCount > 0);
ui->actionMoveDown->setEnabled(totalCount > 0); ui->actionMoveDown->setEnabled(totalCount > 0);
@ -8662,6 +8646,29 @@ void OBSBasic::UpdateEditMenu()
ui->actionHorizontalCenter->setEnabled(canTransformMultiple); 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() void OBSBasic::on_actionEditTransform_triggered()
{ {
const auto item = GetCurrentSceneItem(); const auto item = GetCurrentSceneItem();
@ -10037,31 +10044,39 @@ void OBSBasic::on_actionCopySource_triggered()
clipboard.clear(); clipboard.clear();
for (auto &selectedSource : GetAllSelectedSourceItems()) { for (auto &selectedSource : GetAllSelectedSourceItems()) {
OBSSceneItem item = ui->sources->Get(selectedSource.row()); CopySceneItem(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, &copyInfo.transform);
obs_sceneitem_get_crop(item, &copyInfo.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);
} }
UpdateEditMenu(); 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, &copyInfo.transform);
obs_sceneitem_get_crop(item, &copyInfo.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() 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); OBSData undo_data = BackupScene(scene_source);
OBSScene scene = GetCurrentScene();
undo_s.push_disabled(); undo_s.push_disabled();
@ -10076,16 +10091,17 @@ void OBSBasic::on_actionPasteRef_triggered()
/* do not allow duplicate refs of the same group in the same /* do not allow duplicate refs of the same group in the same
* scene */ * scene */
if (!!obs_scene_get_group(scene, name)) { if (!duplicate && !!obs_scene_get_group(scene, name)) {
continue; continue;
} }
OBSBasicSourceSelect::SourcePaste(copyInfo, false); OBSBasicSourceSelect::SourcePaste(copyInfo, duplicate);
} }
undo_s.pop_disabled(); 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); const char *scene_name = obs_source_get_name(scene_source);
OBSData redo_data = BackupScene(scene_source); OBSData redo_data = BackupScene(scene_source);
@ -10095,24 +10111,7 @@ void OBSBasic::on_actionPasteRef_triggered()
void OBSBasic::on_actionPasteDup_triggered() void OBSBasic::on_actionPasteDup_triggered()
{ {
OBSSource scene_source = GetCurrentSceneSource(); PasteSceneItem(GetCurrentScene(), true);
OBSData undo_data = BackupScene(scene_source);
undo_s.push_disabled();
for (size_t i = clipboard.size(); i > 0; i--) {
SourceCopyInfo &copyInfo = 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);
} }
void OBSBasic::SourcePasteFilters(OBSSource source, OBSSource dstSource) void OBSBasic::SourcePasteFilters(OBSSource source, OBSSource dstSource)

View file

@ -1039,6 +1039,9 @@ public:
obs_data_array_t *redo_array); obs_data_array_t *redo_array);
void UpdateEditMenu(); void UpdateEditMenu();
void CopySceneItem(OBSSceneItem item);
bool CanPasteSceneItem(bool duplicate);
void PasteSceneItem(OBSScene scene, bool duplicate);
void SetDisplayAffinity(QWindow *window); void SetDisplayAffinity(QWindow *window);

View file

@ -949,3 +949,29 @@ Functions
This uses the undo action from the first and the redo action from the last action. This uses the undo action from the first and the redo action from the last action.
.. versionadded:: 29.1 .. 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