浏览代码

UI: Add Multiview Layout Options

Shaolin 7 年之前
父节点
当前提交
abc26b87fe
共有 4 个文件被更改,包括 253 次插入40 次删除
  1. 5 0
      UI/data/locale/en-US.ini
  2. 17 1
      UI/forms/OBSBasicSettings.ui
  3. 35 0
      UI/window-basic-settings.cpp
  4. 196 39
      UI/window-projector.cpp

+ 5 - 0
UI/data/locale/en-US.ini

@@ -566,6 +566,11 @@ Basic.Settings.General.SystemTrayHideMinimize="Always minimize to system tray in
 Basic.Settings.General.SaveProjectors="Save projectors on exit"
 Basic.Settings.General.SwitchOnDoubleClick="Transition to scene when double-clicked"
 Basic.Settings.General.StudioPortraitLayout="Enable portrait/vertical layout"
+Basic.Settings.General.MultiviewLayout="Multiview Layout"
+Basic.Settings.General.MultiviewLayout.Horizontal.Top="Horizontal, Top"
+Basic.Settings.General.MultiviewLayout.Horizontal.Bottom="Horizontal, Bottom"
+Basic.Settings.General.MultiviewLayout.Vertical.Left="Vertical, Left"
+Basic.Settings.General.MultiviewLayout.Vertical.Right="Vertical, Right"
 
 # basic mode 'stream' settings
 Basic.Settings.Stream="Stream"

+ 17 - 1
UI/forms/OBSBasicSettings.ui

@@ -146,7 +146,7 @@
               <x>0</x>
               <y>0</y>
               <width>801</width>
-              <height>715</height>
+              <height>1044</height>
              </rect>
             </property>
             <layout class="QVBoxLayout" name="verticalLayout_19">
@@ -549,6 +549,9 @@
                    <property name="fieldGrowthPolicy">
                     <enum>QFormLayout::AllNonFixedFieldsGrow</enum>
                    </property>
+                   <property name="labelAlignment">
+                    <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+                   </property>
                    <property name="topMargin">
                     <number>2</number>
                    </property>
@@ -579,6 +582,19 @@
                      </property>
                     </widget>
                    </item>
+                   <item row="2" column="1">
+                    <widget class="QComboBox" name="multiviewLayout"/>
+                   </item>
+                   <item row="2" column="0">
+                    <widget class="QLabel" name="label_64">
+                     <property name="text">
+                      <string>Basic.Settings.General.MultiviewLayout</string>
+                     </property>
+                     <property name="buddy">
+                      <cstring>multiviewLayout</cstring>
+                     </property>
+                    </widget>
+                   </item>
                   </layout>
                  </widget>
                 </item>

+ 35 - 0
UI/window-basic-settings.cpp

@@ -45,6 +45,7 @@
 #include "window-basic-main.hpp"
 #include "window-basic-settings.hpp"
 #include "window-basic-main-outputs.hpp"
+#include "window-projector.hpp"
 
 #include <util/platform.h>
 
@@ -317,6 +318,7 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent)
 	HookWidget(ui->snapDistance,         DSCROLL_CHANGED,GENERAL_CHANGED);
 	HookWidget(ui->doubleClickSwitch,    CHECK_CHANGED,  GENERAL_CHANGED);
 	HookWidget(ui->studioPortraitLayout, CHECK_CHANGED,  GENERAL_CHANGED);
+	HookWidget(ui->multiviewLayout,      COMBO_CHANGED,  GENERAL_CHANGED);
 	HookWidget(ui->outputMode,           COMBO_CHANGED,  OUTPUTS_CHANGED);
 	HookWidget(ui->streamType,           COMBO_CHANGED,  STREAM1_CHANGED);
 	HookWidget(ui->simpleOutputPath,     EDIT_CHANGED,   OUTPUTS_CHANGED);
@@ -1087,6 +1089,31 @@ void OBSBasicSettings::LoadGeneralSettings()
 			"BasicWindow", "StudioPortraitLayout");
 	ui->studioPortraitLayout->setChecked(studioPortraitLayout);
 
+	ui->multiviewLayout->addItem(QTStr(
+			"Basic.Settings.General.MultiviewLayout.Horizontal.Top"),
+			QT_UTF8("horizontaltop"));
+	ui->multiviewLayout->addItem(QTStr(
+			"Basic.Settings.General.MultiviewLayout.Horizontal.Bottom"),
+			QT_UTF8("horizontalbottom"));
+	ui->multiviewLayout->addItem(QTStr(
+			"Basic.Settings.General.MultiviewLayout.Vertical.Left"),
+			QT_UTF8("verticalleft"));
+	ui->multiviewLayout->addItem(QTStr(
+			"Basic.Settings.General.MultiviewLayout.Vertical.Right"),
+			QT_UTF8("verticalright"));
+
+	const char *multiviewLayoutText = config_get_string(GetGlobalConfig(),
+			"BasicWindow", "MultiviewLayout");
+
+	if (astrcmpi(multiviewLayoutText, "horizontalbottom") == 0)
+		ui->multiviewLayout->setCurrentIndex(1);
+	else if (astrcmpi(multiviewLayoutText, "verticalleft") == 0)
+		ui->multiviewLayout->setCurrentIndex(2);
+	else if (astrcmpi(multiviewLayoutText, "verticalright") == 0)
+		ui->multiviewLayout->setCurrentIndex(3);
+	else
+		ui->multiviewLayout->setCurrentIndex(0);
+
 	loading = false;
 }
 
@@ -2656,6 +2683,14 @@ void OBSBasicSettings::SaveGeneralSettings()
 
 		main->ResetUI();
 	}
+
+	if (WidgetChanged(ui->multiviewLayout)) {
+		config_set_string(GetGlobalConfig(), "BasicWindow",
+				"MultiviewLayout",
+				QT_TO_UTF8(GetComboData(ui->multiviewLayout)));
+
+		OBSProjector::UpdateMultiviewProjectors();
+	}
 }
 
 void OBSBasicSettings::SaveStream1Settings()

+ 196 - 39
UI/window-projector.cpp

@@ -8,8 +8,14 @@
 #include "qt-wrappers.hpp"
 #include "platform.hpp"
 
+#define HORIZONTAL_TOP    0
+#define HORIZONTAL_BOTTOM 1
+#define VERTICAL_LEFT     2
+#define VERTICAL_RIGHT    3
+
 static QList<OBSProjector *> multiviewProjectors;
 static bool updatingMultiview = false;
+static int multiviewLayout = HORIZONTAL_TOP;
 
 OBSProjector::OBSProjector(QWidget *widget, obs_source_t *source_, bool window)
 	: OBSQTDisplay                 (widget,
@@ -245,10 +251,10 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 	OBSBasic     *main   = (OBSBasic *)obs_frontend_get_main_window();
 	uint32_t     targetCX, targetCY;
 	int          x, y;
-	float        fX, fY, halfCX, halfCY, sourceX, sourceY,
-	             quarterCX, quarterCY, scale, targetCXF, targetCYF,
-		     hiCX, hiCY, qiX, qiY, qiCX, qiCY,
-		     hiScaleX, hiScaleY, qiScaleX, qiScaleY;
+	float        fX, fY, halfCX, halfCY, sourceX, sourceY, labelX, labelY,
+		     quarterCX, quarterCY, scale, targetCXF, targetCYF,
+		     hiCX, hiCY, qiX, qiY, qiCX, qiCY, hiScaleX, hiScaleY,
+		     qiScaleX, qiScaleY;
 	uint32_t     offset;
 
 	gs_effect_t  *solid = obs_get_base_effect(OBS_EFFECT_SOLID);
@@ -317,6 +323,86 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 		gs_projection_pop();
 	};
 
+	auto calcBaseSource = [&](int i)
+	{
+		switch (multiviewLayout) {
+		case VERTICAL_LEFT:
+			sourceX = halfCX;
+			sourceY = (i / 2 ) * quarterCY;
+			if (i % 2 != 0)
+				sourceX = halfCX + quarterCX;
+			break;
+		case VERTICAL_RIGHT:
+			sourceX = 0;
+			sourceY = (i / 2 ) * quarterCY;
+			if (i % 2 != 0)
+				sourceX = quarterCX;
+			break;
+		case HORIZONTAL_BOTTOM:
+			if (i < 4) {
+				sourceX = (float(i) * quarterCX);
+				sourceY = 0;
+			} else {
+				sourceX = (float(i - 4) * quarterCX);
+				sourceY = quarterCY;
+			}
+			break;
+		default: //HORIZONTAL_TOP:
+			if (i < 4) {
+				sourceX = (float(i) * quarterCX);
+				sourceY = halfCY;
+			} else {
+				sourceX = (float(i - 4) * quarterCX);
+				sourceY = halfCY + quarterCY;
+			}
+		}
+	};
+
+	auto calcPreviewProgram = [&](bool program)
+	{
+		switch (multiviewLayout) {
+		case VERTICAL_LEFT:
+			sourceX = 2.0f;
+			sourceY = halfCY + 2.0f;
+			labelX = offset;
+			labelY = halfCY * 1.8f;
+			if (program) {
+				sourceY = 2.0f;
+				labelY = halfCY * 0.8f;
+			}
+			break;
+		case VERTICAL_RIGHT:
+			sourceX = halfCX + 2.0f;
+			sourceY = halfCY + 2.0f;
+			labelX = halfCX + offset;
+			labelY = halfCY * 1.8f;
+			if (program) {
+				sourceY = 2.0f;
+				labelY = halfCY * 0.8f;
+			}
+			break;
+		case HORIZONTAL_BOTTOM:
+			sourceX = 2.0f;
+			sourceY = halfCY + 2.0f;
+			labelX = offset;
+			labelY = halfCY * 1.8f;
+			if (program) {
+				sourceX = halfCX + 2.0f;
+				labelX = halfCX + offset;
+			}
+			break;
+		default: //HORIZONTAL_TOP:
+			sourceX = 2.0f;
+			sourceY = 2.0f;
+			labelX = offset;
+			labelY = halfCY * 0.8f;
+			if (program) {
+				sourceX = halfCX + 2.0f;
+				labelX = halfCX + offset;
+			}
+		}
+	};
+
 	/* ----------------------------- */
 	/* draw sources                  */
 
@@ -334,13 +420,7 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 		if (!label)
 			continue;
 
-		if (i < 4) {
-			sourceX = (float(i) * quarterCX);
-			sourceY = halfCY;
-		} else {
-			sourceX = (float(i - 4) * quarterCX);
-			sourceY = halfCY + quarterCY;
-		}
+		calcBaseSource(i);
 
 		qiX = sourceX + 4.0f;
 		qiY = sourceY + 4.0f;
@@ -399,11 +479,15 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 	/* ----------------------------- */
 	/* draw preview                  */
 
+	obs_source_t *previewLabel = window->multiviewLabels[0];
+	offset = labelOffset(previewLabel, halfCX);
+	calcPreviewProgram(false);
+
 	gs_matrix_push();
-	gs_matrix_translate3f(2.0f, 2.0f, 0.0f);
+	gs_matrix_translate3f(sourceX, sourceY, 0.0f);
 	gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f);
 
-	setRegion(2.0f, 2.0f, hiCX, hiCY);
+	setRegion(sourceX, sourceY, hiCX, hiCY);
 
 	if (studioMode) {
 		obs_source_video_render(previewSrc);
@@ -418,7 +502,8 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 	/* ----------- */
 
 	gs_matrix_push();
-	gs_matrix_scale3f(0.5f, 0.5f, 1.0f);
+	gs_matrix_translate3f(sourceX, sourceY, 0.0f);
+	gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f);
 
 	renderVB(solid, window->outerBox, targetCX, targetCY);
 	renderVB(solid, window->innerBox, targetCX, targetCY);
@@ -432,13 +517,11 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 
 	/* ----------- */
 
-	obs_source_t *previewLabel = window->multiviewLabels[0];
-	offset = labelOffset(previewLabel, halfCX);
 	cx = obs_source_get_width(previewLabel);
 	cy = obs_source_get_height(previewLabel);
 
 	gs_matrix_push();
-	gs_matrix_translate3f(offset, (halfCY * 0.8f), 0.0f);
+	gs_matrix_translate3f(labelX, labelY, 0.0f);
 
 	drawBox(cx, cy + int(halfCX * 0.015f), 0xD91F1F1F);
 	obs_source_video_render(previewLabel);
@@ -448,11 +531,15 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 	/* ----------------------------- */
 	/* draw program                  */
 
+	obs_source_t *programLabel = window->multiviewLabels[1];
+	offset = labelOffset(programLabel, halfCX);
+	calcPreviewProgram(true);
+
 	gs_matrix_push();
-	gs_matrix_translate3f(halfCX + 2.0, 2.0f, 0.0f);
+	gs_matrix_translate3f(sourceX, sourceY, 0.0f);
 	gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f);
 
-	setRegion(halfCX + 2.0f, 2.0f, hiCX, hiCY);
+	setRegion(sourceX, sourceY, hiCX, hiCY);
 	obs_render_main_texture();
 	resetRegion();
 
@@ -461,8 +548,8 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 	/* ----------- */
 
 	gs_matrix_push();
-	gs_matrix_translate3f(halfCX, 0.0f, 0.0f);
-	gs_matrix_scale3f(0.5f, 0.5f, 1.0f);
+	gs_matrix_translate3f(sourceX, sourceY, 0.0f);
+	gs_matrix_scale3f(hiScaleX, hiScaleY, 1.0f);
 
 	renderVB(solid, window->outerBox, targetCX, targetCY);
 
@@ -470,13 +557,11 @@ void OBSProjector::OBSRenderMultiview(void *data, uint32_t cx, uint32_t cy)
 
 	/* ----------- */
 
-	obs_source_t *programLabel = window->multiviewLabels[1];
-	offset = labelOffset(programLabel, halfCX);
 	cx = obs_source_get_width(programLabel);
 	cy = obs_source_get_height(programLabel);
 
 	gs_matrix_push();
-	gs_matrix_translate3f(halfCX + offset, (halfCY * 0.8f), 0.0f);
+	gs_matrix_translate3f(labelX, labelY, 0.0f);
 
 	drawBox(cx, cy + int(halfCX * 0.015f), 0xD91F1F1F);
 	obs_source_video_render(programLabel);
@@ -571,25 +656,85 @@ static int getSourceByPosition(int x, int y)
 	int     maxY  = cy;
 	int     halfX = cx / 2;
 	int     halfY = cy / 2;
+	int     pos   = -1;
 
-	if (float(cx) / float(cy) > ratio) {
-		int validX = cy * ratio;
-		minX = halfX - (validX / 2);
-		maxX = halfX + (validX / 2);
-	} else {
-		int validY = cx / ratio;
-		maxY = halfY + (validY / 2);
-	}
+	switch (multiviewLayout) {
+	case VERTICAL_LEFT:
+		if (float(cx) / float(cy) > ratio) {
+			int validX = cy * ratio;
+			maxX = halfX + (validX / 2);
+		} else {
+			int validY = cx / ratio;
+			minY = halfY - (validY / 2);
+			maxY = halfY + (validY / 2);
+		}
+
+		minX = halfX;
+
+		if (x < minX || x > maxX || y < minY || y > maxY)
+			break;
+
+		pos = 2 * ((y - minY) / ((maxY - minY) / 4));
+		if (x > minX + ((maxX - minX) / 2))
+			pos++;
+		break;
+	case VERTICAL_RIGHT:
+		if (float(cx) / float(cy) > ratio) {
+			int validX = cy * ratio;
+			minX = halfX - (validX / 2);
+		} else {
+			int validY = cx / ratio;
+			minY = halfY - (validY / 2);
+			maxY = halfY + (validY / 2);
+		}
+
+		maxX = halfX;
 
-	minY = halfY;
+		if (x < minX || x > maxX || y < minY || y > maxY)
+			break;
 
-	if (x < minX || x > maxX || y < minY || y > maxY)
-		return -1;
+		pos = 2 * ((y - minY) / ((maxY - minY) / 4));
+		if (x > minX + ((maxX - minX) / 2))
+			pos++;
+		break;
+	case HORIZONTAL_BOTTOM:
+		if (float(cx) / float(cy) > ratio) {
+			int validX = cy * ratio;
+			minX = halfX - (validX / 2);
+			maxX = halfX + (validX / 2);
+		} else {
+			int validY = cx / ratio;
+			minY = halfY - (validY / 2);
+		}
+
+		maxY = halfY;
 
-	int quarterX = (maxX - minX) / 4;
-	int pos = (x - minX) / quarterX;
-	if (y > minY + ((maxY - minY) / 2))
-		pos += 4;
+		if (x < minX || x > maxX || y < minY || y > maxY)
+			break;
+
+		pos = (x - minX) / ((maxX - minX) / 4);
+		if (y > minY + ((maxY - minY) / 2))
+			pos += 4;
+		break;
+	default: // HORIZONTAL_TOP
+		if (float(cx) / float(cy) > ratio) {
+			int validX = cy * ratio;
+			minX = halfX - (validX / 2);
+			maxX = halfX + (validX / 2);
+		} else {
+			int validY = cx / ratio;
+			maxY = halfY + (validY / 2);
+		}
+
+		minY = halfY;
+
+		if (x < minX || x > maxX || y < minY || y > maxY)
+			break;
+
+		pos = (x - minX) / ((maxX - minX) / 4);
+		if (y > minY + ((maxY - minY) / 2))
+			pos += 4;
+	}
 
 	return pos;
 }
@@ -699,6 +844,18 @@ void OBSProjector::UpdateMultiview()
 	}
 
 	obs_frontend_source_list_free(&scenes);
+
+	const char *multiviewLayoutText = config_get_string(GetGlobalConfig(),
+			"BasicWindow", "MultiviewLayout");
+
+	if (astrcmpi(multiviewLayoutText, "horizontalbottom") == 0)
+		multiviewLayout = HORIZONTAL_BOTTOM;
+	else if (astrcmpi(multiviewLayoutText, "verticalleft") == 0)
+		multiviewLayout = VERTICAL_LEFT;
+	else if (astrcmpi(multiviewLayoutText, "verticalright") == 0)
+		multiviewLayout = VERTICAL_RIGHT;
+	else
+		multiviewLayout = HORIZONTAL_TOP;
 }
 
 void OBSProjector::UpdateMultiviewProjectors()