diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini
index bceab1d32..50dd9cf62 100644
--- a/obs/data/locale/en-US.ini
+++ b/obs/data/locale/en-US.ini
@@ -355,6 +355,9 @@ Basic.Settings.General.Theme="Theme"
Basic.Settings.General.Language="Language"
Basic.Settings.General.WarnBeforeStartingStream="Show confirmation dialog when starting streams"
Basic.Settings.General.WarnBeforeStoppingStream="Show confirmation dialog when stopping streams"
+Basic.Settings.General.Snapping="Source Alignment Snapping"
+Basic.Settings.General.ScreenSnapping="Snap Sources to edge of screen"
+Basic.Settings.General.SnapDistance="Snap Sensitivity"
# basic mode 'stream' settings
Basic.Settings.Stream="Stream"
diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui
index fae897a91..bd38e2185 100644
--- a/obs/forms/OBSBasicSettings.ui
+++ b/obs/forms/OBSBasicSettings.ui
@@ -185,6 +185,86 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+ Basic.Settings.General.Snapping
+
+
+ false
+
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+ Enable
+
+
+ true
+
+
+
+ -
+
+
+ Basic.Settings.General.ScreenSnapping
+
+
+ true
+
+
+
+ -
+
+
+ 1
+
+
+ 0.500000000000000
+
+
+ 10.000000000000000
+
+
+
+ -
+
+
+
+ 170
+ 0
+
+
+
+ Basic.Settings.General.SnapDistance
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
@@ -3485,8 +3565,56 @@
setEnabled(bool)
- 517
- 267
+ 690
+ 454
+
+
+ 690
+ 506
+
+
+
+
+ snappingEnabled
+ toggled(bool)
+ label_9
+ setEnabled(bool)
+
+
+ 376
+ 196
+
+
+ 305
+ 224
+
+
+
+
+ snappingEnabled
+ toggled(bool)
+ snapDistance
+ setEnabled(bool)
+
+
+ 417
+ 204
+
+
+ 434
+ 234
+
+
+
+
+ snappingEnabled
+ toggled(bool)
+ screenSnapping
+ setEnabled(bool)
+
+
+ 476
+ 202
777
diff --git a/obs/obs-app.cpp b/obs/obs-app.cpp
index da24ce8a9..86368e714 100644
--- a/obs/obs-app.cpp
+++ b/obs/obs-app.cpp
@@ -339,6 +339,12 @@ bool OBSApp::InitGlobalConfigDefaults()
"SceneDuplicationMode", true);
config_set_default_bool(globalConfig, "BasicWindow",
"SwapScenesMode", true);
+ config_set_default_bool(globalConfig, "BasicWindow",
+ "SnappingEnabled", true);
+ config_set_default_bool(globalConfig, "BasicWindow",
+ "ScreenSnapping", true);
+ config_set_default_double(globalConfig, "BasicWindow",
+ "SnapDistance", 10.0);
#ifdef __APPLE__
config_set_default_bool(globalConfig, "Video", "DisableOSXVSync", true);
diff --git a/obs/window-basic-preview.cpp b/obs/window-basic-preview.cpp
index 5d3017698..cdc25e17f 100644
--- a/obs/window-basic-preview.cpp
+++ b/obs/window-basic-preview.cpp
@@ -11,7 +11,6 @@
#define HANDLE_RADIUS 4.0f
#define HANDLE_SEL_RADIUS (HANDLE_RADIUS * 1.5f)
-#define CLAMP_DISTANCE 10.0f
/* TODO: make C++ math classes and clean up code here later */
@@ -133,7 +132,7 @@ static inline vec2 GetOBSScreenSize()
return size;
}
-vec3 OBSBasicPreview::GetScreenSnapOffset(const vec3 &tl, const vec3 &br)
+vec3 OBSBasicPreview::GetSnapOffset(const vec3 &tl, const vec3 &br)
{
OBSBasic *main = reinterpret_cast(App()->GetMainWindow());
vec2 screenSize = GetOBSScreenSize();
@@ -141,17 +140,34 @@ vec3 OBSBasicPreview::GetScreenSnapOffset(const vec3 &tl, const vec3 &br)
vec3_zero(&clampOffset);
- const float clampDist = CLAMP_DISTANCE / main->previewScale;
+ const bool snap = config_get_bool(GetGlobalConfig(),
+ "BasicWindow", "SnappingEnabled");
+ if (snap == false)
+ return clampOffset;
- if (fabsf(tl.x) < clampDist)
+ const bool screenSnap = config_get_bool(GetGlobalConfig(),
+ "BasicWindow", "ScreenSnapping");
+
+ const float clampDist = config_get_double(GetGlobalConfig(),
+ "BasicWindow", "SnapDistance") / main->previewScale;
+
+ // Left screen edge.
+ if (screenSnap &&
+ fabsf(tl.x) < clampDist)
clampOffset.x = -tl.x;
- if (fabsf(clampOffset.x) < EPSILON &&
+ // Right screen edge.
+ if (screenSnap &&
+ fabsf(clampOffset.x) < EPSILON &&
fabsf(screenSize.x - br.x) < clampDist)
clampOffset.x = screenSize.x - br.x;
- if (fabsf(tl.y) < clampDist)
+ // Top screen edge.
+ if (screenSnap &&
+ fabsf(tl.y) < clampDist)
clampOffset.y = -tl.y;
- if (fabsf(clampOffset.y) < EPSILON &&
+ // Bottom screen edge.
+ if (screenSnap &&
+ fabsf(clampOffset.y) < EPSILON &&
fabsf(screenSize.y - br.y) < clampDist)
clampOffset.y = screenSize.y - br.y;
@@ -485,7 +501,13 @@ void OBSBasicPreview::SnapItemMovement(vec2 &offset)
data.br.x += offset.x;
data.br.y += offset.y;
- vec3 snapOffset = GetScreenSnapOffset(data.tl, data.br);
+ vec3 snapOffset = GetSnapOffset(data.tl, data.br);
+
+ const bool snap = config_get_bool(GetGlobalConfig(),
+ "BasicWindow", "SnappingEnabled");
+ if (snap == false)
+ return;
+
offset.x += snapOffset.x;
offset.y += snapOffset.y;
}
@@ -606,7 +628,7 @@ void OBSBasicPreview::SnapStretchingToScreen(vec3 &tl, vec3 &br)
vec3_max(&boundingBR, &boundingBR, &newBL);
vec3_max(&boundingBR, &boundingBR, &newBR);
- vec3 offset = GetScreenSnapOffset(boundingTL, boundingBR);
+ vec3 offset = GetSnapOffset(boundingTL, boundingBR);
vec3_add(&offset, &offset, &newTL);
vec3_transform(&offset, &offset, &screenToItem);
vec3_sub(&offset, &offset, &tl);
diff --git a/obs/window-basic-preview.hpp b/obs/window-basic-preview.hpp
index 4507f61b2..1a2524532 100644
--- a/obs/window-basic-preview.hpp
+++ b/obs/window-basic-preview.hpp
@@ -56,7 +56,7 @@ private:
static void DoSelect(const vec2 &pos);
static void DoCtrlSelect(const vec2 &pos);
- static vec3 GetScreenSnapOffset(const vec3 &tl, const vec3 &br);
+ static vec3 GetSnapOffset(const vec3 &tl, const vec3 &br);
void GetStretchHandleData(const vec2 &pos);
diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp
index 86d459330..52f5a3c85 100644
--- a/obs/window-basic-settings.cpp
+++ b/obs/window-basic-settings.cpp
@@ -266,6 +266,9 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
HookWidget(ui->theme, COMBO_CHANGED, GENERAL_CHANGED);
HookWidget(ui->warnBeforeStreamStart,CHECK_CHANGED, GENERAL_CHANGED);
HookWidget(ui->warnBeforeStreamStop, CHECK_CHANGED, GENERAL_CHANGED);
+ HookWidget(ui->snappingEnabled, CHECK_CHANGED, GENERAL_CHANGED);
+ HookWidget(ui->screenSnapping, CHECK_CHANGED, GENERAL_CHANGED);
+ HookWidget(ui->snapDistance, SCROLL_CHANGED, GENERAL_CHANGED);
HookWidget(ui->outputMode, COMBO_CHANGED, OUTPUTS_CHANGED);
HookWidget(ui->streamType, COMBO_CHANGED, STREAM1_CHANGED);
HookWidget(ui->simpleOutputPath, EDIT_CHANGED, OUTPUTS_CHANGED);
@@ -763,6 +766,19 @@ void OBSBasicSettings::LoadGeneralSettings()
LoadLanguageList();
LoadThemeList();
+ bool snappingEnabled = config_get_bool(GetGlobalConfig(),
+ "BasicWindow", "SnappingEnabled");
+ ui->snappingEnabled->setChecked(snappingEnabled);
+
+ bool screenSnapping = config_get_bool(GetGlobalConfig(),
+ "BasicWindow", "ScreenSnapping");
+ ui->screenSnapping->setChecked(screenSnapping);
+
+ double snapDistance = config_get_double(GetGlobalConfig(),
+ "BasicWindow", "SnapDistance");
+ ui->snapDistance->setValue(snapDistance);
+
+
bool warnBeforeStreamStart = config_get_bool(GetGlobalConfig(),
"BasicWindow", "WarnBeforeStartingStream");
ui->warnBeforeStreamStart->setChecked(warnBeforeStreamStart);
@@ -2038,6 +2054,19 @@ void OBSBasicSettings::SaveGeneralSettings()
App()->SetTheme(theme);
}
+ if (WidgetChanged(ui->snappingEnabled))
+ config_set_bool(GetGlobalConfig(), "BasicWindow",
+ "SnappingEnabled",
+ ui->snappingEnabled->isChecked());
+ if (WidgetChanged(ui->screenSnapping))
+ config_set_bool(GetGlobalConfig(), "BasicWindow",
+ "ScreenSnapping",
+ ui->screenSnapping->isChecked());
+ if (WidgetChanged(ui->snapDistance))
+ config_set_double(GetGlobalConfig(), "BasicWindow",
+ "SnapDistance",
+ ui->snapDistance->value());
+
config_set_bool(GetGlobalConfig(), "BasicWindow",
"WarnBeforeStartingStream",
ui->warnBeforeStreamStart->isChecked());