diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini
index 4c3eaed7e..f9b2b61ba 100644
--- a/obs/data/locale/en-US.ini
+++ b/obs/data/locale/en-US.ini
@@ -324,6 +324,7 @@ Basic.MainMenu.Edit.Undo="&Undo"
Basic.MainMenu.Edit.Redo="&Redo"
Basic.MainMenu.Edit.UndoAction="&Undo $1"
Basic.MainMenu.Edit.RedoAction="&Redo $1"
+Basic.MainMenu.Edit.LockPreview="&Lock Preview"
Basic.MainMenu.Edit.Transform="&Transform"
Basic.MainMenu.Edit.Transform.EditTransform="&Edit Transform..."
Basic.MainMenu.Edit.Transform.ResetTransform="&Reset Transform"
diff --git a/obs/forms/OBSBasic.ui b/obs/forms/OBSBasic.ui
index ca0e35fd9..76d8e5517 100644
--- a/obs/forms/OBSBasic.ui
+++ b/obs/forms/OBSBasic.ui
@@ -7,7 +7,7 @@
0
0
- 957
+ 1110
724
@@ -804,7 +804,7 @@
0
0
- 957
+ 1110
21
@@ -875,6 +875,7 @@
+
@@ -1310,6 +1311,14 @@
Basic.MainMenu.View.StatusBar
+
+
+ true
+
+
+ Basic.MainMenu.Edit.LockPreview
+
+
diff --git a/obs/window-basic-main.cpp b/obs/window-basic-main.cpp
index 558994459..eb3f7cfc4 100644
--- a/obs/window-basic-main.cpp
+++ b/obs/window-basic-main.cpp
@@ -374,6 +374,8 @@ void OBSBasic::Save(const char *file)
ui->transitionDuration->value(), transitions,
scene, curProgramScene);
+ obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked());
+
if (!obs_data_save_json_safe(saveData, file, "tmp", "bak"))
blog(LOG_ERROR, "Could not save scene data to %s", file);
@@ -607,6 +609,10 @@ retryScene:
RefreshQuickTransitions();
+ bool previewLocked = obs_data_get_bool(data, "preview_locked");
+ ui->preview->SetLocked(previewLocked);
+ ui->actionLockPreview->setChecked(previewLocked);
+
obs_data_release(data);
if (!opt_starting_scene.empty())
@@ -2958,6 +2964,12 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview)
if (IsPreviewProgramMode())
action->setEnabled(false);
+ action = popup.addAction(
+ QTStr("Basic.MainMenu.Edit.LockPreview"),
+ this, SLOT(on_actionLockPreview_triggered()));
+ action->setCheckable(true);
+ action->setChecked(ui->preview->Locked());
+
previewProjector = new QMenu(QTStr("PreviewProjector"));
AddProjectorMenuMonitors(previewProjector, this,
SLOT(OpenPreviewProjector()));
@@ -4306,3 +4318,9 @@ void OBSBasic::on_toggleStatusBar_toggled(bool visible)
config_set_bool(App()->GlobalConfig(), "BasicWindow",
"ShowStatusBar", visible);
}
+
+void OBSBasic::on_actionLockPreview_triggered()
+{
+ ui->preview->ToggleLocked();
+ ui->actionLockPreview->setChecked(ui->preview->Locked());
+}
diff --git a/obs/window-basic-main.hpp b/obs/window-basic-main.hpp
index b84d16432..0fe477e88 100644
--- a/obs/window-basic-main.hpp
+++ b/obs/window-basic-main.hpp
@@ -460,6 +460,8 @@ private slots:
void on_actionMoveToTop_triggered();
void on_actionMoveToBottom_triggered();
+ void on_actionLockPreview_triggered();
+
void on_streamButton_clicked();
void on_recordButton_clicked();
void on_settingsButton_clicked();
diff --git a/obs/window-basic-preview.cpp b/obs/window-basic-preview.cpp
index 8e7725c11..dc2c4f310 100644
--- a/obs/window-basic-preview.cpp
+++ b/obs/window-basic-preview.cpp
@@ -379,6 +379,11 @@ void OBSBasicPreview::GetStretchHandleData(const vec2 &pos)
void OBSBasicPreview::mousePressEvent(QMouseEvent *event)
{
+ if (locked) {
+ OBSQTDisplay::mousePressEvent(event);
+ return;
+ }
+
OBSBasic *main = reinterpret_cast(App()->GetMainWindow());
float pixelRatio = main->devicePixelRatio();
float x = float(event->x()) - main->previewX / pixelRatio;
@@ -451,6 +456,11 @@ void OBSBasicPreview::ProcessClick(const vec2 &pos)
void OBSBasicPreview::mouseReleaseEvent(QMouseEvent *event)
{
+ if (locked) {
+ OBSQTDisplay::mouseReleaseEvent(event);
+ return;
+ }
+
if (mouseDown) {
vec2 pos = GetMouseEventPos(event);
@@ -941,6 +951,9 @@ void OBSBasicPreview::StretchItem(const vec2 &pos)
void OBSBasicPreview::mouseMoveEvent(QMouseEvent *event)
{
+ if (locked)
+ return;
+
if (mouseDown) {
vec2 pos = GetMouseEventPos(event);
@@ -1076,6 +1089,9 @@ bool OBSBasicPreview::DrawSelectedItem(obs_scene_t *scene,
void OBSBasicPreview::DrawSceneEditing()
{
+ if (locked)
+ return;
+
OBSBasic *main = reinterpret_cast(App()->GetMainWindow());
gs_effect_t *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
diff --git a/obs/window-basic-preview.hpp b/obs/window-basic-preview.hpp
index 1a2524532..c11581b67 100644
--- a/obs/window-basic-preview.hpp
+++ b/obs/window-basic-preview.hpp
@@ -45,6 +45,7 @@ private:
bool mouseMoved = false;
bool mouseOverItems = false;
bool cropping = false;
+ bool locked = false;
static vec2 GetMouseEventPos(QMouseEvent *event);
static bool DrawSelectedItem(obs_scene_t *scene, obs_sceneitem_t *item,
@@ -80,6 +81,10 @@ public:
void DrawSceneEditing();
+ inline void SetLocked(bool newLockedVal) {locked = newLockedVal;}
+ inline void ToggleLocked() {locked = !locked;}
+ inline bool Locked() const {return locked;}
+
/* use libobs allocator for alignment because the matrices itemToScreen
* and screenToItem may contain SSE data, which will cause SSE
* instructions to crash if the data is not aligned to at least a 16