diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini
index a8ebb2b15..c16b6714a 100644
--- a/UI/data/locale/en-US.ini
+++ b/UI/data/locale/en-US.ini
@@ -342,6 +342,8 @@ Basic.MainMenu.Edit.Scale.Canvas="Canvas (%1x%2)"
Basic.MainMenu.Edit.Scale.Output="Output (%1x%2)"
Basic.MainMenu.Edit.Transform="&Transform"
Basic.MainMenu.Edit.Transform.EditTransform="&Edit Transform..."
+Basic.MainMenu.Edit.Transform.CopyTransform="Copy Transform"
+Basic.MainMenu.Edit.Transform.PasteTransform="Paste Transform"
Basic.MainMenu.Edit.Transform.ResetTransform="&Reset Transform"
Basic.MainMenu.Edit.Transform.Rotate90CW="Rotate 90 degrees CW"
Basic.MainMenu.Edit.Transform.Rotate90CCW="Rotate 90 degrees CCW"
diff --git a/UI/forms/OBSBasic.ui b/UI/forms/OBSBasic.ui
index 041aa5897..d89016294 100644
--- a/UI/forms/OBSBasic.ui
+++ b/UI/forms/OBSBasic.ui
@@ -850,6 +850,8 @@
Basic.MainMenu.Edit.Transform
+
+
@@ -1129,6 +1131,19 @@
Basic.MainMenu.Edit.Transform.EditTransform
+
+
+ Basic.MainMenu.Edit.Transform.CopyTransform
+
+
+
+
+ false
+
+
+ Basic.MainMenu.Edit.Transform.PasteTransform
+
+
Basic.MainMenu.Edit.Transform.Rotate90CW
diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp
index f2827aa67..cd326b2b1 100644
--- a/UI/window-basic-main.cpp
+++ b/UI/window-basic-main.cpp
@@ -4387,6 +4387,50 @@ 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);
+}
+
+void OBSBasic::on_actionPasteTransform_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_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);
+}
+
void OBSBasic::on_actionResetTransform_triggered()
{
auto func = [] (obs_scene_t *scene, obs_sceneitem_t *item, void *param)
diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp
index 8cc5ef20a..1cdf9c0e8 100644
--- a/UI/window-basic-main.hpp
+++ b/UI/window-basic-main.hpp
@@ -498,6 +498,8 @@ private slots:
void on_actionCheckForUpdates_triggered();
void on_actionEditTransform_triggered();
+ void on_actionCopyTransform_triggered();
+ void on_actionPasteTransform_triggered();
void on_actionRotate90CW_triggered();
void on_actionRotate90CCW_triggered();
void on_actionRotate180_triggered();