mirror of
https://github.com/obsproject/obs-studio.git
synced 2026-08-24 02:34:23 -05:00
frontend: Add copy paste functions
This commit is contained in:
@@ -959,3 +959,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:: 32.2
|
||||
|
||||
---------------------------------------
|
||||
|
||||
.. 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:: 32.2
|
||||
|
||||
---------------------------------------
|
||||
|
||||
.. 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:: 32.2
|
||||
|
||||
@@ -682,6 +682,28 @@ bool OBSStudioAPI::obs_frontend_remove_canvas(obs_canvas_t *canvas)
|
||||
return main->RemoveCanvas(canvas);
|
||||
}
|
||||
|
||||
void OBSStudioAPI::obs_frontend_copy_sceneitem(obs_sceneitem_t *item)
|
||||
{
|
||||
main->clipboard.clear();
|
||||
main->copySceneItem(item);
|
||||
main->UpdateEditMenu();
|
||||
}
|
||||
|
||||
bool OBSStudioAPI::obs_frontend_can_paste_sceneitem(bool duplicate)
|
||||
{
|
||||
auto pasteType = main->getItemPasteType();
|
||||
if (duplicate) {
|
||||
return pasteType == OBS::ItemPasteType::Duplicate || pasteType == OBS::ItemPasteType::Both;
|
||||
} else {
|
||||
return pasteType == OBS::ItemPasteType::Reference || pasteType == OBS::ItemPasteType::Both;
|
||||
}
|
||||
}
|
||||
|
||||
void OBSStudioAPI::obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate)
|
||||
{
|
||||
main->pasteSceneItem(scene, duplicate);
|
||||
}
|
||||
|
||||
void OBSStudioAPI::on_load(obs_data_t *settings)
|
||||
{
|
||||
for (size_t i = saveCallbacks.size(); i > 0; i--) {
|
||||
|
||||
@@ -224,6 +224,12 @@ struct OBSStudioAPI : obs_frontend_callbacks {
|
||||
|
||||
bool obs_frontend_remove_canvas(obs_canvas_t *canvas) override;
|
||||
|
||||
void obs_frontend_copy_sceneitem(obs_sceneitem_t *item) override;
|
||||
|
||||
bool obs_frontend_can_paste_sceneitem(bool duplicate) override;
|
||||
|
||||
void obs_frontend_paste_sceneitem(obs_scene_t *scene, bool duplicate) override;
|
||||
|
||||
void on_load(obs_data_t *settings) override;
|
||||
|
||||
void on_preload(obs_data_t *settings) override;
|
||||
|
||||
@@ -608,3 +608,22 @@ bool obs_frontend_remove_canvas(obs_canvas_t *canvas)
|
||||
{
|
||||
return !!callbacks_valid() ? c->obs_frontend_remove_canvas(canvas) : false;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -254,6 +254,10 @@ EXPORT void obs_frontend_get_canvases(struct obs_frontend_canvas_list *canvas_li
|
||||
EXPORT obs_canvas_t *obs_frontend_add_canvas(const char *name, struct obs_video_info *ovi, int flags);
|
||||
EXPORT bool obs_frontend_remove_canvas(obs_canvas_t *canvas);
|
||||
|
||||
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
|
||||
|
||||
@@ -138,6 +138,10 @@ struct obs_frontend_callbacks {
|
||||
virtual obs_canvas_t *obs_frontend_add_canvas(const char *name, obs_video_info *ovi, int flags) = 0;
|
||||
virtual bool obs_frontend_remove_canvas(obs_canvas_t *canvas) = 0;
|
||||
virtual void obs_frontend_get_canvases(obs_frontend_canvas_list *canvas_list) = 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 obs_frontend_set_callbacks_internal(obs_frontend_callbacks *callbacks);
|
||||
|
||||
@@ -2022,19 +2022,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++) {
|
||||
@@ -2059,8 +2046,11 @@ void OBSBasic::UpdateEditMenu()
|
||||
ui->actionPasteTransform->setEnabled(canTransformMultiple && hasCopiedTransform && videoCount > 0);
|
||||
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);
|
||||
auto pasteType = getItemPasteType();
|
||||
ui->actionPasteRef->setEnabled(pasteType == OBS::ItemPasteType::Reference ||
|
||||
pasteType == OBS::ItemPasteType::Both);
|
||||
ui->actionPasteDup->setEnabled(pasteType == OBS::ItemPasteType::Duplicate ||
|
||||
pasteType == OBS::ItemPasteType::Both);
|
||||
|
||||
ui->actionMoveUp->setEnabled(totalCount > 0);
|
||||
ui->actionMoveDown->setEnabled(totalCount > 0);
|
||||
|
||||
@@ -69,6 +69,7 @@ namespace OBS {
|
||||
class SceneCollection;
|
||||
struct Rect;
|
||||
enum class LogFileType;
|
||||
enum class ItemPasteType { Invalid, Reference, Duplicate, Both };
|
||||
} // namespace OBS
|
||||
|
||||
#define SIMPLE_ENCODER_X264 "x264"
|
||||
@@ -406,6 +407,10 @@ public:
|
||||
void CreateFilterPasteUndoRedoAction(const QString &text, obs_source_t *source, obs_data_array_t *undo_array,
|
||||
obs_data_array_t *redo_array);
|
||||
|
||||
void copySceneItem(OBSSceneItem item);
|
||||
OBS::ItemPasteType getItemPasteType();
|
||||
void pasteSceneItem(OBSScene scene, bool duplicate);
|
||||
|
||||
/* -------------------------------------
|
||||
* MARK: - OBSBasic_ContextToolbar
|
||||
* -------------------------------------
|
||||
|
||||
@@ -70,52 +70,64 @@ void OBSBasic::on_actionCopySource_triggered()
|
||||
clipboard.clear();
|
||||
|
||||
for (auto &selectedSource : GetAllSelectedSourceItems()) {
|
||||
OBSSceneItem item = ui->sources->Get(selectedSource.row());
|
||||
if (!item)
|
||||
continue;
|
||||
copySceneItem(ui->sources->Get(selectedSource.row()));
|
||||
}
|
||||
UpdateEditMenu();
|
||||
}
|
||||
|
||||
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);
|
||||
copyInfo.scale_type = obs_sceneitem_get_scale_filter(item);
|
||||
copyInfo.show_transition_id = obs_source_get_id(obs_sceneitem_get_transition(item, true));
|
||||
copyInfo.hide_transition_id = obs_source_get_id(obs_sceneitem_get_transition(item, false));
|
||||
|
||||
OBSDataAutoRelease newShowData = obs_data_create();
|
||||
OBSDataAutoRelease oldShowData = obs_source_get_settings(obs_sceneitem_get_transition(item, true));
|
||||
obs_data_apply(newShowData, oldShowData);
|
||||
copyInfo.show_transition_settings = newShowData.Get();
|
||||
|
||||
OBSDataAutoRelease newHideData = obs_data_create();
|
||||
OBSDataAutoRelease oldHideData = obs_source_get_settings(obs_sceneitem_get_transition(item, false));
|
||||
obs_data_apply(newHideData, oldHideData);
|
||||
copyInfo.hide_transition_settings = newHideData.Get();
|
||||
|
||||
copyInfo.show_transition_duration = obs_sceneitem_get_transition_duration(item, true);
|
||||
copyInfo.hide_transition_duration = obs_sceneitem_get_transition_duration(item, false);
|
||||
|
||||
OBSDataAutoRelease newPrivData = obs_data_create();
|
||||
OBSDataAutoRelease oldPrivData = obs_sceneitem_get_private_settings(item);
|
||||
obs_data_apply(newPrivData, oldPrivData);
|
||||
copyInfo.private_settings = newPrivData.Get();
|
||||
|
||||
clipboard.push_back(copyInfo);
|
||||
void OBSBasic::copySceneItem(OBSSceneItem item)
|
||||
{
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateEditMenu();
|
||||
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);
|
||||
copyInfo.scale_type = obs_sceneitem_get_scale_filter(item);
|
||||
copyInfo.show_transition_id = obs_source_get_id(obs_sceneitem_get_transition(item, true));
|
||||
copyInfo.hide_transition_id = obs_source_get_id(obs_sceneitem_get_transition(item, false));
|
||||
|
||||
OBSDataAutoRelease newShowData = obs_data_create();
|
||||
OBSDataAutoRelease oldShowData = obs_source_get_settings(obs_sceneitem_get_transition(item, true));
|
||||
obs_data_apply(newShowData, oldShowData);
|
||||
copyInfo.show_transition_settings = newShowData.Get();
|
||||
|
||||
OBSDataAutoRelease newHideData = obs_data_create();
|
||||
OBSDataAutoRelease oldHideData = obs_source_get_settings(obs_sceneitem_get_transition(item, false));
|
||||
obs_data_apply(newHideData, oldHideData);
|
||||
copyInfo.hide_transition_settings = newHideData.Get();
|
||||
|
||||
copyInfo.show_transition_duration = obs_sceneitem_get_transition_duration(item, true);
|
||||
copyInfo.hide_transition_duration = obs_sceneitem_get_transition_duration(item, false);
|
||||
|
||||
OBSDataAutoRelease newPrivData = obs_data_create();
|
||||
OBSDataAutoRelease oldPrivData = obs_sceneitem_get_private_settings(item);
|
||||
obs_data_apply(newPrivData, oldPrivData);
|
||||
copyInfo.private_settings = newPrivData.Get();
|
||||
|
||||
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();
|
||||
|
||||
@@ -130,17 +142,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);
|
||||
RefreshSources(scene);
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -149,24 +161,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);
|
||||
RefreshSources(GetCurrentScene());
|
||||
}
|
||||
|
||||
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::SourcePasteFilters(OBSSource source, OBSSource dstSource)
|
||||
@@ -276,3 +271,25 @@ void OBSBasic::on_actionPasteFilters_triggered()
|
||||
|
||||
SourcePasteFilters(source.Get(), dstSource);
|
||||
}
|
||||
|
||||
OBS::ItemPasteType OBSBasic::getItemPasteType()
|
||||
{
|
||||
if (clipboard.empty()) {
|
||||
return OBS::ItemPasteType::Invalid;
|
||||
}
|
||||
|
||||
bool allowPastingDuplicate = true;
|
||||
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 ? OBS::ItemPasteType::Both : OBS::ItemPasteType::Reference;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user