From 9fce1621378c1563f7f37dced9582ffdaa28885f Mon Sep 17 00:00:00 2001 From: Ryan Foster Date: Wed, 8 Nov 2017 22:38:44 -0500 Subject: [PATCH] UI: Add Studio Preview Projector This commit allows a user to create projectors for the preview scene instead of the program/live scene. Close jp9000/obs-studio#1071 --- UI/data/locale/en-US.ini | 2 + UI/window-basic-main-transitions.cpp | 3 + UI/window-basic-main.cpp | 136 +++++++++++++++++++++++++-- UI/window-basic-main.hpp | 10 +- UI/window-projector.cpp | 29 +++++- UI/window-projector.hpp | 4 +- 6 files changed, 170 insertions(+), 14 deletions(-) diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 2520ab6e2..ef12a94a2 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -33,9 +33,11 @@ Browse="Browse" Mono="Mono" Stereo="Stereo" DroppedFrames="Dropped Frames %1 (%2%)" +StudioProgramProjector="Fullscreen Projector (Program)" PreviewProjector="Fullscreen Projector (Preview)" SceneProjector="Fullscreen Projector (Scene)" SourceProjector="Fullscreen Projector (Source)" +StudioProgramWindow="Windowed Projector (Program)" PreviewWindow="Windowed Projector (Preview)" SceneWindow="Windowed Projector (Scene)" SourceWindow="Windowed Projector (Source)" diff --git a/UI/window-basic-main-transitions.cpp b/UI/window-basic-main-transitions.cpp index aac2a9bf2..63a4bf37c 100644 --- a/UI/window-basic-main-transitions.cpp +++ b/UI/window-basic-main-transitions.cpp @@ -604,6 +604,9 @@ void OBSBasic::SetCurrentScene(OBSSource scene, bool force, bool direct) void OBSBasic::CreateProgramDisplay() { program = new OBSQTDisplay(); + program->setContextMenuPolicy(Qt::CustomContextMenu); + connect(program.data(), &QWidget::customContextMenuRequested, + this, &OBSBasic::on_program_customContextMenuRequested); auto displayResize = [this]() { struct obs_video_info ovi; diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index f61000054..d6a03fc33 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -139,6 +139,7 @@ OBSBasic::OBSBasic(QWidget *parent) projectorArray.resize(10, ""); previewProjectorArray.resize(10, 0); + studioProgramProjectorArray.resize(10, ""); setAcceptDrops(true); @@ -318,7 +319,8 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder, obs_data_array_t *transitions, OBSScene &scene, OBSSource &curProgramScene, obs_data_array_t *savedProjectorList, - obs_data_array_t *savedPreviewProjectorList) + obs_data_array_t *savedPreviewProjectorList, + obs_data_array_t *savedStudioProgramProjectorList) { obs_data_t *saveData = obs_data_create(); @@ -362,6 +364,8 @@ static obs_data_t *GenerateSaveData(obs_data_array_t *sceneOrder, obs_data_set_array(saveData, "saved_projectors", savedProjectorList); obs_data_set_array(saveData, "saved_preview_projectors", savedPreviewProjectorList); + obs_data_set_array(saveData, "saved_studio_preview_projectors", + savedStudioProgramProjectorList); obs_data_array_release(sourcesArray); obs_data_set_string(saveData, "current_transition", @@ -449,6 +453,21 @@ obs_data_array_t *OBSBasic::SavePreviewProjectors() return saveProjector; } +obs_data_array_t *OBSBasic::SaveStudioProgramProjectors() +{ + obs_data_array_t *saveProjector = obs_data_array_create(); + + for (size_t i = 0; i < studioProgramProjectorArray.size(); i++) { + obs_data_t *data = obs_data_create(); + obs_data_set_string(data, "saved_studio_preview_projectors", + studioProgramProjectorArray.at(i).c_str()); + obs_data_array_push_back(saveProjector, data); + obs_data_release(data); + } + + return saveProjector; +} + void OBSBasic::Save(const char *file) { OBSScene scene = GetCurrentScene(); @@ -461,10 +480,13 @@ void OBSBasic::Save(const char *file) obs_data_array_t *quickTrData = SaveQuickTransitions(); obs_data_array_t *savedProjectorList = SaveProjectors(); obs_data_array_t *savedPreviewProjectorList = SavePreviewProjectors(); - obs_data_t *saveData = GenerateSaveData(sceneOrder, quickTrData, + obs_data_array_t *savedStudioProgramProjectorList = + SaveStudioProgramProjectors(); + obs_data_t *saveData = GenerateSaveData(sceneOrder, quickTrData, ui->transitionDuration->value(), transitions, scene, curProgramScene, savedProjectorList, - savedPreviewProjectorList); + savedPreviewProjectorList, + savedStudioProgramProjectorList); obs_data_set_bool(saveData, "preview_locked", ui->preview->Locked()); obs_data_set_bool(saveData, "scaling_enabled", @@ -492,6 +514,7 @@ void OBSBasic::Save(const char *file) obs_data_array_release(transitions); obs_data_array_release(savedProjectorList); obs_data_array_release(savedPreviewProjectorList); + obs_data_array_release(savedStudioProgramProjectorList); } static void LoadAudioDevice(const char *name, int channel, obs_data_t *parent) @@ -617,6 +640,19 @@ void OBSBasic::LoadSavedPreviewProjectors(obs_data_array_t *array) } } +void OBSBasic::LoadSavedStudioProgramProjectors(obs_data_array_t *array) +{ + size_t num = obs_data_array_count(array); + + for (size_t i = 0; i < num; i++) { + obs_data_t *data = obs_data_array_item(array, i); + studioProgramProjectorArray.at(i) = obs_data_get_string(data, + "saved_studio_preview_projectors"); + + obs_data_release(data); + } +} + static void LogFilter(obs_source_t*, obs_source_t *filter, void *v_val) { const char *name = obs_source_get_name(filter); @@ -764,6 +800,14 @@ void OBSBasic::Load(const char *file) obs_data_array_release(savedPreviewProjectors); + obs_data_array_t *savedStudioProgramProjectors = obs_data_get_array(data, + "saved_studio_preview_projectors"); + + if (savedStudioProgramProjectors) + LoadSavedStudioProgramProjectors(savedStudioProgramProjectors); + + obs_data_array_release(savedStudioProgramProjectors); + retryScene: curScene = obs_get_source_by_name(sceneName); @@ -3673,15 +3717,23 @@ void OBSBasic::CreateSourcePopupMenu(QListWidgetItem *item, bool preview) popup.addAction(ui->actionLockPreview); popup.addMenu(ui->scalingMenu); + const char *slot = IsPreviewProgramMode() + ? SLOT(OpenStudioProgramProjector()) + : SLOT(OpenPreviewProjector()); + previewProjector = new QMenu(QTStr("PreviewProjector")); AddProjectorMenuMonitors(previewProjector, this, - SLOT(OpenPreviewProjector())); + slot); popup.addMenu(previewProjector); + slot = IsPreviewProgramMode() + ? SLOT(OpenStudioProgramWindow()) + : SLOT(OpenPreviewWindow()); + QAction *previewWindow = popup.addAction( QTStr("PreviewWindow"), - this, SLOT(OpenPreviewWindow())); + this, slot); popup.addAction(previewWindow); @@ -4875,6 +4927,27 @@ void OBSBasic::on_preview_customContextMenuRequested(const QPoint &pos) UNUSED_PARAMETER(pos); } +void OBSBasic::on_program_customContextMenuRequested(const QPoint&) +{ + QMenu popup(this); + QPointer studioProgramProjector; + + studioProgramProjector = new QMenu( + QTStr("StudioProgramProjector")); + AddProjectorMenuMonitors(studioProgramProjector, this, + SLOT(OpenPreviewProjector())); + + popup.addMenu(studioProgramProjector); + + QAction *studioProgramWindow = popup.addAction( + QTStr("StudioProgramWindow"), + this, SLOT(OpenPreviewWindow())); + + popup.addAction(studioProgramWindow); + + popup.exec(QCursor::pos()); +} + void OBSBasic::on_previewDisabledLabel_customContextMenuRequested( const QPoint &pos) { @@ -5336,7 +5409,7 @@ void OBSBasic::NudgeLeft() {Nudge(1, MoveDir::Left);} void OBSBasic::NudgeRight() {Nudge(1, MoveDir::Right);} void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window, - QString title) + QString title, bool studioProgram) { /* seriously? 10 monitors? */ if (monitor > 9 || monitor > QGuiApplication::screens().size() - 1) @@ -5357,7 +5430,9 @@ void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window, const char *name = obs_source_get_name(source); if (!window) { - if (isPreview) { + if (studioProgram) { + studioProgramProjectorArray.at((size_t)monitor) = name; + } else if (isPreview) { previewProjectorArray.at((size_t)monitor) = 1; } else { projectorArray.at((size_t)monitor) = name; @@ -5365,10 +5440,10 @@ void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window, } if (!window) { - projector->Init(monitor, false, nullptr); + projector->Init(monitor, false, nullptr, studioProgram); projectors[monitor] = projector; } else { - projector->Init(monitor, true, title); + projector->Init(monitor, true, title, studioProgram); for (auto &projPtr : windowProjectors) { if (!projPtr) { @@ -5382,6 +5457,16 @@ void OBSBasic::OpenProjector(obs_source_t *source, int monitor, bool window, } } +void OBSBasic::OpenStudioProgramProjector() +{ + int monitor = sender()->property("monitor").toInt(); + obs_source_t *source = GetCurrentSceneSource(); + if (!source) + return; + + OpenProjector(source, monitor, false, nullptr, true); +} + void OBSBasic::OpenPreviewProjector() { int monitor = sender()->property("monitor").toInt(); @@ -5408,6 +5493,17 @@ void OBSBasic::OpenSceneProjector() OpenProjector(obs_scene_get_source(scene), monitor, false); } +void OBSBasic::OpenStudioProgramWindow() +{ + int monitor = sender()->property("monitor").toInt(); + QString title = QTStr("StudioProgramWindow"); + obs_source_t *source = GetCurrentSceneSource(); + if (!source) + return; + + OpenProjector(source, monitor, true, title, true); +} + void OBSBasic::OpenPreviewWindow() { int monitor = sender()->property("monitor").toInt(); @@ -5467,6 +5563,22 @@ void OBSBasic::OpenSavedProjectors() } } + for (size_t i = 0; i < studioProgramProjectorArray.size(); i++) { + if (studioProgramProjectorArray.at(i).empty() == false) { + OBSSource source = obs_get_source_by_name( + studioProgramProjectorArray.at(i).c_str()); + + if (!source) { + RemoveSavedProjectors((int)i); + obs_source_release(source); + continue; + } + + OpenProjector(source, (int)i, false, nullptr, true); + obs_source_release(source); + } + } + for (size_t i = 0; i < previewProjectorArray.size(); i++) { if (previewProjectorArray.at(i) == 1) { OpenProjector(nullptr, (int)i, false); @@ -5477,6 +5589,7 @@ void OBSBasic::OpenSavedProjectors() void OBSBasic::RemoveSavedProjectors(int monitor) { + studioProgramProjectorArray.at((size_t)monitor) = ""; previewProjectorArray.at((size_t)monitor) = 0; projectorArray.at((size_t)monitor) = ""; } @@ -5771,10 +5884,15 @@ void OBSBasic::SystemTrayInit() QMenu *previewProjector = new QMenu(QTStr("PreviewProjector")); AddProjectorMenuMonitors(previewProjector, this, SLOT(OpenPreviewProjector())); + QMenu *studioProgramProjector = new QMenu( + QTStr("StudioProgramProjector")); + AddProjectorMenuMonitors(studioProgramProjector, this, + SLOT(OpenStudioProgramProjector())); trayMenu = new QMenu; trayMenu->addAction(showHide); trayMenu->addMenu(previewProjector); + trayMenu->addMenu(studioProgramProjector); trayMenu->addAction(sysTrayStream); trayMenu->addAction(sysTrayRecord); trayMenu->addAction(sysTrayReplayBuffer); diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 3320258be..d52059bae 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -114,6 +114,7 @@ private: std::vector signalHandlers; std::vector projectorArray; + std::vector studioProgramProjectorArray; std::vector previewProjectorArray; bool loaded = false; @@ -240,7 +241,7 @@ private: void Nudge(int dist, MoveDir dir); void OpenProjector(obs_source_t *source, int monitor, bool window, - QString title = nullptr); + QString title = nullptr, bool studioProgram = false); void GetAudioSourceFilters(); void GetAudioSourceProperties(); @@ -358,6 +359,10 @@ private: void LoadSavedPreviewProjectors( obs_data_array_t *savedPreviewProjectors); + obs_data_array_t *SaveStudioProgramProjectors(); + void LoadSavedStudioProgramProjectors( + obs_data_array_t *savedStudioProgramProjectors); + public slots: void StartStreaming(); void StopStreaming(); @@ -609,6 +614,7 @@ private slots: void on_actionWebsite_triggered(); void on_preview_customContextMenuRequested(const QPoint &pos); + void on_program_customContextMenuRequested(const QPoint &pos); void on_previewDisabledLabel_customContextMenuRequested( const QPoint &pos); @@ -675,10 +681,12 @@ private slots: void NudgeLeft(); void NudgeRight(); + void OpenStudioProgramProjector(); void OpenPreviewProjector(); void OpenSourceProjector(); void OpenSceneProjector(); + void OpenStudioProgramWindow(); void OpenPreviewWindow(); void OpenSourceWindow(); void OpenSceneWindow(); diff --git a/UI/window-projector.cpp b/UI/window-projector.cpp index 16860bb24..50b9bd990 100644 --- a/UI/window-projector.cpp +++ b/UI/window-projector.cpp @@ -55,7 +55,8 @@ OBSProjector::~OBSProjector() App()->DecrementSleepInhibition(); } -void OBSProjector::Init(int monitor, bool window, QString title) +void OBSProjector::Init(int monitor, bool window, QString title, + bool studioProgram) { QScreen *screen = QGuiApplication::screens()[monitor]; @@ -72,6 +73,12 @@ void OBSProjector::Init(int monitor, bool window, QString title) show(); + if (studioProgram && !source) { + OBSBasic *main = + reinterpret_cast(App()->GetMainWindow()); + source = main->GetCurrentSceneSource(); + } + if (source) obs_source_inc_showing(source); @@ -86,6 +93,7 @@ void OBSProjector::Init(int monitor, bool window, QString title) savedMonitor = monitor; isWindow = window; + useStudioProgram = studioProgram; } void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy) @@ -118,10 +126,25 @@ void OBSProjector::OBSRender(void *data, uint32_t cx, uint32_t cy) gs_ortho(0.0f, float(targetCX), 0.0f, float(targetCY), -100.0f, 100.0f); gs_set_viewport(x, y, newCX, newCY); - if (window->source) + if (window->useStudioProgram) { + OBSBasic *main = + reinterpret_cast(App()->GetMainWindow()); + OBSSource curSource = main->GetCurrentSceneSource(); + + if (window->source != curSource) { + blog(LOG_INFO, "new scene for studio preview projector: '%s'", + obs_source_get_name(curSource)); + obs_source_dec_showing(window->source); + obs_source_inc_showing(curSource); + window->source = curSource; + } + } + + if (window->source) { obs_source_video_render(window->source); - else + } else { obs_render_main_view(); + } gs_projection_pop(); gs_viewport_pop(); diff --git a/UI/window-projector.hpp b/UI/window-projector.hpp index 48205dd7a..accc5dbbc 100644 --- a/UI/window-projector.hpp +++ b/UI/window-projector.hpp @@ -20,6 +20,7 @@ private: int savedMonitor = 0; bool isWindow = false; + bool useStudioProgram = false; private slots: void EscapeTriggered(); @@ -28,5 +29,6 @@ public: OBSProjector(QWidget *parent, obs_source_t *source, bool window); ~OBSProjector(); - void Init(int monitor, bool window, QString title); + void Init(int monitor, bool window, QString title, + bool studioProgram = false); };