UI: Add Multiview Layout Options

master
Shaolin 2017-12-13 19:42:19 -02:00
parent 864caee16c
commit abc26b87fe
4 changed files with 255 additions and 42 deletions

View File

@ -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"

View File

@ -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>

View File

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

View File

@ -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,26 +656,86 @@ 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;
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 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;
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;
}
minY = halfY;
if (x < minX || x > maxX || y < minY || y > maxY)
return -1;
int quarterX = (maxX - minX) / 4;
int pos = (x - minX) / quarterX;
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()