UI: Apply transforms/crops correctly to sources on paste
Applies transformations correctly to copy/pasted sources when copy and pasting multiple. Previously the transformation/crop state was stored in a single variable on copy so it would only apply the transformations to one of the selected sources on paste instead of what the state was when copied.master
parent
aee6d813f1
commit
fd500f15a3
|
@ -4485,7 +4485,7 @@ void OBSBasic::ClearSceneData()
|
|||
programScene = nullptr;
|
||||
prevFTBSource = nullptr;
|
||||
|
||||
copySources.clear();
|
||||
clipboard.clear();
|
||||
copyFiltersSource = nullptr;
|
||||
copyFilter = nullptr;
|
||||
|
||||
|
@ -7662,11 +7662,11 @@ void OBSBasic::UpdateEditMenu()
|
|||
filter_count = obs_source_filter_count(source);
|
||||
}
|
||||
|
||||
for (size_t i = copySources.size(); i > 0; i--) {
|
||||
for (size_t i = clipboard.size(); i > 0; i--) {
|
||||
const size_t idx = i - 1;
|
||||
OBSWeakSource &weak = copySources[idx];
|
||||
OBSWeakSource &weak = clipboard[idx].weak_source;
|
||||
if (obs_weak_source_expired(weak))
|
||||
copySources.erase(copySources.begin() + idx);
|
||||
clipboard.erase(clipboard.begin() + idx);
|
||||
}
|
||||
|
||||
ui->actionCopySource->setEnabled(idx != -1);
|
||||
|
@ -7675,8 +7675,8 @@ void OBSBasic::UpdateEditMenu()
|
|||
ui->actionCopyFilters->setEnabled(filter_count > 0);
|
||||
ui->actionPasteFilters->setEnabled(
|
||||
!obs_weak_source_expired(copyFiltersSource) && idx != -1);
|
||||
ui->actionPasteRef->setEnabled(!!copySources.size());
|
||||
ui->actionPasteDup->setEnabled(!!copySources.size());
|
||||
ui->actionPasteRef->setEnabled(!!clipboard.size());
|
||||
ui->actionPasteDup->setEnabled(!!clipboard.size());
|
||||
|
||||
ui->actionMoveUp->setEnabled(idx != -1);
|
||||
ui->actionMoveDown->setEnabled(idx != -1);
|
||||
|
@ -7720,26 +7720,8 @@ void OBSBasic::on_actionEditTransform_triggered()
|
|||
transformWindow->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
}
|
||||
|
||||
static obs_transform_info copiedTransformInfo;
|
||||
static obs_sceneitem_crop copiedCropInfo;
|
||||
|
||||
void OBSBasic::on_actionCopyTransform_triggered()
|
||||
{
|
||||
auto func = [](obs_scene_t *scene, obs_sceneitem_t *item, void *param) {
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
obs_sceneitem_defer_update_begin(item);
|
||||
obs_sceneitem_get_info(item, &copiedTransformInfo);
|
||||
obs_sceneitem_get_crop(item, &copiedCropInfo);
|
||||
obs_sceneitem_defer_update_end(item);
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
UNUSED_PARAMETER(param);
|
||||
return true;
|
||||
};
|
||||
|
||||
obs_scene_enum_items(GetCurrentScene(), func, nullptr);
|
||||
ui->actionPasteTransform->setEnabled(true);
|
||||
}
|
||||
|
||||
|
@ -7756,40 +7738,6 @@ void undo_redo(const std::string &data)
|
|||
obs_scene_load_transform_states(data.c_str());
|
||||
}
|
||||
|
||||
void OBSBasic::on_actionPasteTransform_triggered()
|
||||
{
|
||||
obs_data_t *wrapper =
|
||||
obs_scene_save_transform_states(GetCurrentScene(), false);
|
||||
auto func = [](obs_scene_t *scene, obs_sceneitem_t *item, void *param) {
|
||||
if (!obs_sceneitem_selected(item))
|
||||
return true;
|
||||
|
||||
obs_sceneitem_defer_update_begin(item);
|
||||
obs_sceneitem_set_info(item, &copiedTransformInfo);
|
||||
obs_sceneitem_set_crop(item, &copiedCropInfo);
|
||||
obs_sceneitem_defer_update_end(item);
|
||||
|
||||
UNUSED_PARAMETER(scene);
|
||||
UNUSED_PARAMETER(param);
|
||||
return true;
|
||||
};
|
||||
|
||||
obs_scene_enum_items(GetCurrentScene(), func, nullptr);
|
||||
|
||||
obs_data_t *rwrapper =
|
||||
obs_scene_save_transform_states(GetCurrentScene(), false);
|
||||
|
||||
std::string undo_data(obs_data_get_json(wrapper));
|
||||
std::string redo_data(obs_data_get_json(rwrapper));
|
||||
undo_s.add_action(
|
||||
QTStr("Undo.Transform.Paste")
|
||||
.arg(obs_source_get_name(GetCurrentSceneSource())),
|
||||
undo_redo, undo_redo, undo_data, redo_data);
|
||||
|
||||
obs_data_release(wrapper);
|
||||
obs_data_release(rwrapper);
|
||||
}
|
||||
|
||||
static bool reset_tr(obs_scene_t *scene, obs_sceneitem_t *item, void *param)
|
||||
{
|
||||
if (obs_sceneitem_is_group(item))
|
||||
|
@ -9011,7 +8959,7 @@ void OBSBasic::on_actionMainRedo_triggered()
|
|||
|
||||
void OBSBasic::on_actionCopySource_triggered()
|
||||
{
|
||||
copySources.clear();
|
||||
clipboard.clear();
|
||||
bool allowPastingDuplicate = true;
|
||||
|
||||
for (auto &selectedSource : GetAllSelectedSourceItems()) {
|
||||
|
@ -9023,11 +8971,15 @@ void OBSBasic::on_actionCopySource_triggered()
|
|||
|
||||
OBSSource source = obs_sceneitem_get_source(item);
|
||||
|
||||
obs_weak_source *weak = obs_source_get_weak_source(source);
|
||||
copySources.emplace_front(weak);
|
||||
obs_weak_source_release(weak);
|
||||
SourceCopyInfo copyInfo;
|
||||
copyInfo.weak_source = OBSGetWeakRef(source);
|
||||
copyInfo.transform = std::make_shared<obs_transform_info>();
|
||||
obs_sceneitem_get_info(item, copyInfo.transform.get());
|
||||
copyInfo.crop = std::make_shared<obs_sceneitem_crop>();
|
||||
obs_sceneitem_get_crop(item, copyInfo.crop.get());
|
||||
copyInfo.visible = obs_sceneitem_visible(item);
|
||||
|
||||
copyVisible = obs_sceneitem_visible(item);
|
||||
clipboard.push_back(copyInfo);
|
||||
|
||||
uint32_t output_flags = obs_source_get_output_flags(source);
|
||||
if (output_flags & OBS_SOURCE_DO_NOT_DUPLICATE)
|
||||
|
@ -9046,20 +8998,22 @@ void OBSBasic::on_actionPasteRef_triggered()
|
|||
|
||||
undo_s.push_disabled();
|
||||
|
||||
for (auto ©Source : copySources) {
|
||||
obs_source_t *source = obs_weak_source_get_source(copySource);
|
||||
for (size_t i = clipboard.size(); i > 0; i--) {
|
||||
SourceCopyInfo ©Info = clipboard[i - 1];
|
||||
|
||||
OBSSource source = OBSGetStrongRef(copyInfo.weak_source);
|
||||
if (!source)
|
||||
continue;
|
||||
|
||||
const char *name = obs_source_get_name(source);
|
||||
|
||||
/* do not allow duplicate refs of the same group in the same scene */
|
||||
if (!!obs_scene_get_group(scene, name))
|
||||
/* do not allow duplicate refs of the same group in the same
|
||||
* scene */
|
||||
if (!!obs_scene_get_group(scene, name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
OBSBasicSourceSelect::SourcePaste(name, copyVisible, false);
|
||||
on_actionPasteTransform_triggered();
|
||||
obs_source_release(source);
|
||||
OBSBasicSourceSelect::SourcePaste(copyInfo, false);
|
||||
}
|
||||
|
||||
undo_s.pop_disabled();
|
||||
|
@ -9079,15 +9033,9 @@ void OBSBasic::on_actionPasteDup_triggered()
|
|||
|
||||
undo_s.push_disabled();
|
||||
|
||||
for (auto ©Source : copySources) {
|
||||
obs_source_t *source = obs_weak_source_get_source(copySource);
|
||||
if (!source)
|
||||
continue;
|
||||
|
||||
const char *name = obs_source_get_name(source);
|
||||
OBSBasicSourceSelect::SourcePaste(name, copyVisible, true);
|
||||
on_actionPasteTransform_triggered();
|
||||
obs_source_release(source);
|
||||
for (size_t i = clipboard.size(); i > 0; i--) {
|
||||
SourceCopyInfo ©Info = clipboard[i - 1];
|
||||
OBSBasicSourceSelect::SourcePaste(copyInfo, true);
|
||||
}
|
||||
|
||||
undo_s.pop_disabled();
|
||||
|
|
|
@ -89,6 +89,13 @@ struct SavedProjectorInfo {
|
|||
bool alwaysOnTopOverridden;
|
||||
};
|
||||
|
||||
struct SourceCopyInfo {
|
||||
OBSWeakSource weak_source;
|
||||
bool visible;
|
||||
std::shared_ptr<obs_sceneitem_crop> crop;
|
||||
std::shared_ptr<obs_transform_info> transform;
|
||||
};
|
||||
|
||||
struct QuickTransition {
|
||||
QPushButton *button = nullptr;
|
||||
OBSSource source;
|
||||
|
@ -204,7 +211,7 @@ private:
|
|||
bool projectChanged = false;
|
||||
bool previewEnabled = true;
|
||||
|
||||
std::deque<OBSWeakSource> copySources;
|
||||
std::deque<SourceCopyInfo> clipboard;
|
||||
OBSWeakSource copyFiltersSource;
|
||||
bool copyVisible = true;
|
||||
|
||||
|
@ -946,7 +953,6 @@ private slots:
|
|||
|
||||
void on_actionEditTransform_triggered();
|
||||
void on_actionCopyTransform_triggered();
|
||||
void on_actionPasteTransform_triggered();
|
||||
void on_actionRotate90CW_triggered();
|
||||
void on_actionRotate90CCW_triggered();
|
||||
void on_actionRotate180_triggered();
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
struct AddSourceData {
|
||||
obs_source_t *source;
|
||||
bool visible;
|
||||
obs_transform_info *transform = nullptr;
|
||||
obs_sceneitem_crop *crop = nullptr;
|
||||
};
|
||||
|
||||
bool OBSBasicSourceSelect::EnumSources(void *data, obs_source_t *source)
|
||||
|
@ -116,6 +118,13 @@ static void AddSource(void *_data, obs_scene_t *scene)
|
|||
obs_sceneitem_t *sceneitem;
|
||||
|
||||
sceneitem = obs_scene_add(scene, data->source);
|
||||
|
||||
if (data->transform != nullptr)
|
||||
obs_sceneitem_set_info(sceneitem, data->transform);
|
||||
|
||||
if (data->crop != nullptr)
|
||||
obs_sceneitem_set_crop(sceneitem, data->crop);
|
||||
|
||||
obs_sceneitem_set_visible(sceneitem, data->visible);
|
||||
}
|
||||
|
||||
|
@ -140,34 +149,43 @@ static char *get_new_source_name(const char *name)
|
|||
return new_name.array;
|
||||
}
|
||||
|
||||
static void AddExisting(const char *name, bool visible, bool duplicate)
|
||||
static void AddExisting(OBSSource source, bool visible, bool duplicate,
|
||||
obs_transform_info *transform, obs_sceneitem_crop *crop)
|
||||
{
|
||||
OBSBasic *main = reinterpret_cast<OBSBasic *>(App()->GetMainWindow());
|
||||
OBSScene scene = main->GetCurrentScene();
|
||||
if (!scene)
|
||||
return;
|
||||
|
||||
if (duplicate) {
|
||||
OBSSource from = source;
|
||||
char *new_name =
|
||||
get_new_source_name(obs_source_get_name(source));
|
||||
source = obs_source_duplicate(from, new_name, false);
|
||||
obs_source_release(source);
|
||||
bfree(new_name);
|
||||
|
||||
if (!source)
|
||||
return;
|
||||
}
|
||||
|
||||
AddSourceData data;
|
||||
data.source = source;
|
||||
data.visible = visible;
|
||||
data.transform = transform;
|
||||
data.crop = crop;
|
||||
|
||||
obs_enter_graphics();
|
||||
obs_scene_atomic_update(scene, AddSource, &data);
|
||||
obs_leave_graphics();
|
||||
}
|
||||
|
||||
static void AddExisting(const char *name, bool visible, bool duplicate,
|
||||
obs_transform_info *transform, obs_sceneitem_crop *crop)
|
||||
{
|
||||
obs_source_t *source = obs_get_source_by_name(name);
|
||||
if (source) {
|
||||
if (duplicate) {
|
||||
obs_source_t *from = source;
|
||||
char *new_name = get_new_source_name(name);
|
||||
source = obs_source_duplicate(from, new_name, false);
|
||||
bfree(new_name);
|
||||
obs_source_release(from);
|
||||
|
||||
if (!source)
|
||||
return;
|
||||
}
|
||||
|
||||
AddSourceData data;
|
||||
data.source = source;
|
||||
data.visible = visible;
|
||||
|
||||
obs_enter_graphics();
|
||||
obs_scene_atomic_update(scene, AddSource, &data);
|
||||
obs_leave_graphics();
|
||||
|
||||
AddExisting(source, visible, duplicate, transform, crop);
|
||||
obs_source_release(source);
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +245,8 @@ void OBSBasicSourceSelect::on_buttonBox_accepted()
|
|||
if (!item)
|
||||
return;
|
||||
|
||||
AddExisting(QT_TO_UTF8(item->text()), visible, false);
|
||||
AddExisting(QT_TO_UTF8(item->text()), visible, false, nullptr,
|
||||
nullptr);
|
||||
} else {
|
||||
if (ui->sourceName->text().isEmpty()) {
|
||||
OBSMessageBox::warning(this,
|
||||
|
@ -378,7 +397,12 @@ OBSBasicSourceSelect::OBSBasicSourceSelect(OBSBasic *parent, const char *id_,
|
|||
}
|
||||
}
|
||||
|
||||
void OBSBasicSourceSelect::SourcePaste(const char *name, bool visible, bool dup)
|
||||
void OBSBasicSourceSelect::SourcePaste(SourceCopyInfo &info, bool dup)
|
||||
{
|
||||
AddExisting(name, visible, dup);
|
||||
OBSSource source = OBSGetStrongRef(info.weak_source);
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
AddExisting(source, info.visible, dup, info.transform.get(),
|
||||
info.crop.get());
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "ui_OBSBasicSourceSelect.h"
|
||||
#include "undo-stack-obs.hpp"
|
||||
#include "window-basic-main.hpp"
|
||||
|
||||
class OBSBasic;
|
||||
|
||||
|
@ -52,5 +53,5 @@ public:
|
|||
|
||||
OBSSource newSource;
|
||||
|
||||
static void SourcePaste(const char *name, bool visible, bool duplicate);
|
||||
static void SourcePaste(SourceCopyInfo &info, bool duplicate);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue