瀏覽代碼

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.
Anthony Torres 4 年之前
父節點
當前提交
fd500f15a3
共有 4 個文件被更改,包括 83 次插入104 次删除
  1. 27 79
      UI/window-basic-main.cpp
  2. 8 2
      UI/window-basic-main.hpp
  3. 46 22
      UI/window-basic-source-select.cpp
  4. 2 1
      UI/window-basic-source-select.hpp

+ 27 - 79
UI/window-basic-main.cpp

@@ -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 &copySource : copySources) {
-		obs_source_t *source = obs_weak_source_get_source(copySource);
+	for (size_t i = clipboard.size(); i > 0; i--) {
+		SourceCopyInfo &copyInfo = 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 &copySource : 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 &copyInfo = clipboard[i - 1];
+		OBSBasicSourceSelect::SourcePaste(copyInfo, true);
 	}
 
 	undo_s.pop_disabled();

+ 8 - 2
UI/window-basic-main.hpp

@@ -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();

+ 46 - 22
UI/window-basic-source-select.cpp

@@ -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;
 
-	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;
-		}
+	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;
+	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();
+	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) {
+		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());
 }

+ 2 - 1
UI/window-basic-source-select.hpp

@@ -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);
 };