diff --git a/UI/CMakeLists.txt b/UI/CMakeLists.txt index ae007eac00f6a20ace68fb17a4c612e224f5fc97..9ef923abd07e717db9e2477798e792107e37d554 100644 --- a/UI/CMakeLists.txt +++ b/UI/CMakeLists.txt @@ -245,6 +245,7 @@ set(obs_SOURCES combobox-ignorewheel.cpp spinbox-ignorewheel.cpp record-button.cpp + ui-validation.cpp url-push-button.cpp volume-control.cpp adv-audio-control.cpp @@ -302,6 +303,7 @@ set(obs_HEADERS menu-button.hpp mute-checkbox.hpp record-button.hpp + ui-validation.hpp url-push-button.hpp volume-control.hpp adv-audio-control.hpp diff --git a/UI/data/locale/en-US.ini b/UI/data/locale/en-US.ini index 7daf8f420d59aeacd974f64d119c2a77714a837a..44978dd8cb39e57b94abc3e96c11267325fda72d 100644 --- a/UI/data/locale/en-US.ini +++ b/UI/data/locale/en-US.ini @@ -679,6 +679,11 @@ Basic.Settings.Stream.TTVAddon.None="None" Basic.Settings.Stream.TTVAddon.BTTV="BetterTTV" Basic.Settings.Stream.TTVAddon.FFZ="FrankerFaceZ" Basic.Settings.Stream.TTVAddon.Both="BetterTTV and FrankerFaceZ" +Basic.Settings.Stream.MissingSettingAlert="Missing Stream Setup" +Basic.Settings.Stream.StreamSettingsWarning="Open Settings" +Basic.Settings.Stream.MissingUrlAndApiKey="URL and Stream Key are missing.\n\nOpen settings to enter the URL and Stream Key in the 'stream' tab." +Basic.Settings.Stream.MissingUrl="Stream URL is missing.\n\nOpen settings to enter the URL in the 'Stream' tab." +Basic.Settings.Stream.MissingStreamKey="Stream key is missing.\n\nOpen settings to enter the stream key in the 'Stream' tab." # basic mode 'output' settings Basic.Settings.Output="Output" diff --git a/UI/ui-validation.cpp b/UI/ui-validation.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e441cbb6a491255bf205e8caeae9aed06c60bd48 --- /dev/null +++ b/UI/ui-validation.cpp @@ -0,0 +1,119 @@ +#include "ui-validation.hpp" + +#include +#include +#include +#include + +#include +#include + +static int CountVideoSources() +{ + int count = 0; + auto countSources = [](void *param, obs_source_t *source) { + if (!source) + return true; + + uint32_t flags = obs_source_get_output_flags(source); + if ((flags & OBS_SOURCE_VIDEO) != 0) + (*reinterpret_cast(param))++; + + return true; + }; + + obs_enum_sources(countSources, &count); + return count; +} + +bool UIValidation::NoSourcesConfirmation(QWidget *parent) +{ + // There are sources, don't need confirmation + if (CountVideoSources() != 0) + return true; + + // Ignore no video if no parent is visible to alert on + if (!parent->isVisible()) + return true; + + QString msg = QTStr("NoSources.Text"); + msg += "\n\n"; + msg += QTStr("NoSources.Text.AddSource"); + + QMessageBox messageBox(parent); + messageBox.setWindowTitle(QTStr("NoSources.Title")); + messageBox.setText(msg); + + QAbstractButton *yesButton = + messageBox.addButton(QTStr("Yes"), QMessageBox::YesRole); + messageBox.addButton(QTStr("No"), QMessageBox::NoRole); + messageBox.setIcon(QMessageBox::Question); + messageBox.exec(); + + if (messageBox.clickedButton() != yesButton) + return false; + else + return true; +} + +StreamSettingsAction +UIValidation::StreamSettingsConfirmation(QWidget *parent, OBSService service) +{ + // Custom services can user API key in URL or user/pass combo. + // So only check there is a URL + char const *serviceType = obs_service_get_type(service); + bool isCustomUrlService = (strcmp(serviceType, "rtmp_custom") == 0); + + char const *streamUrl = obs_service_get_url(service); + char const *streamKey = obs_service_get_key(service); + + bool hasStreamUrl = (streamUrl != NULL && streamUrl[0] != '\0'); + bool hasStreamKey = ((streamKey != NULL && streamKey[0] != '\0') || + isCustomUrlService); + + if (hasStreamUrl && hasStreamKey) + return StreamSettingsAction::ContinueStream; + + QString msg; + + if (!hasStreamUrl && !hasStreamKey) { + msg = QTStr("Basic.Settings.Stream.MissingUrlAndApiKey"); + } else if (!hasStreamKey) { + msg = QTStr("Basic.Settings.Stream.MissingStreamKey"); + } else { + msg = QTStr("Basic.Settings.Stream.MissingUrl"); + } + + QMessageBox messageBox(parent); + messageBox.setWindowTitle( + QTStr("Basic.Settings.Stream.MissingSettingAlert")); + messageBox.setText(msg); + + QPushButton *cancel; + QPushButton *settings; + +#ifdef __APPLE__ +#define ACCEPT_BUTTON QMessageBox::AcceptRole +#define REJECT_BUTTON QMessageBox::ResetRole +#else +#define ACCEPT_BUTTON QMessageBox::NoRole +#define REJECT_BUTTON QMessageBox::NoRole +#endif + settings = messageBox.addButton( + QTStr("Basic.Settings.Stream.StreamSettingsWarning"), + ACCEPT_BUTTON); + cancel = messageBox.addButton(QTStr("Cancel"), REJECT_BUTTON); + + messageBox.setDefaultButton(settings); + messageBox.setEscapeButton(cancel); + + messageBox.setIcon(QMessageBox::Warning); + messageBox.exec(); + + if (messageBox.clickedButton() == settings) + return StreamSettingsAction::OpenSettings; + if (messageBox.clickedButton() == cancel) + return StreamSettingsAction::Cancel; + + return StreamSettingsAction::ContinueStream; +} diff --git a/UI/ui-validation.hpp b/UI/ui-validation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5dbe14b639e1a25148c8a8213c52cf97d559bb46 --- /dev/null +++ b/UI/ui-validation.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +#include + +enum class StreamSettingsAction { + OpenSettings, + Cancel, + ContinueStream, +}; + +class UIValidation : public QObject { + Q_OBJECT + +public: + /* Confirm video about to record or stream has sources. Shows alert + * box notifying there are no video sources Returns true if user clicks + * "Yes" Returns false if user clicks "No" */ + static bool NoSourcesConfirmation(QWidget *parent); + + /* Check streaming requirements, shows warning with options to open + * settings, cancel stream, or attempt connection anyways. If setup + * basics is missing in stream, explain missing fields and offer to + * open settings, cancel, or continue. Returns Continue if all + * settings are valid. */ + static StreamSettingsAction + StreamSettingsConfirmation(QWidget *parent, OBSService service); +}; diff --git a/UI/window-basic-main.cpp b/UI/window-basic-main.cpp index 51a0d539b30130fe8506da95859f78f0afd1dec6..a54f95785b2779dc39cb409acc39a64aa6a79d30 100644 --- a/UI/window-basic-main.cpp +++ b/UI/window-basic-main.cpp @@ -54,6 +54,7 @@ #include "display-helpers.hpp" #include "volume-control.hpp" #include "remote-text.hpp" +#include "ui-validation.hpp" #include #include @@ -163,25 +164,6 @@ static void AddExtraModulePaths() extern obs_frontend_callbacks *InitializeAPIInterface(OBSBasic *main); -static int CountVideoSources() -{ - int count = 0; - - auto countSources = [](void *param, obs_source_t *source) { - if (!source) - return true; - - uint32_t flags = obs_source_get_output_flags(source); - if ((flags & OBS_SOURCE_VIDEO) != 0) - (*reinterpret_cast(param))++; - - return true; - }; - - obs_enum_sources(countSources, &count); - return count; -} - void assignDockToggle(QDockWidget *dock, QAction *action) { auto handleWindowToggle = [action](bool vis) { @@ -5600,7 +5582,7 @@ void OBSBasic::StartReplayBuffer() if (disableOutputsRef) return; - if (!NoSourcesConfirmation()) { + if (!UIValidation::NoSourcesConfirmation(this)) { replayBufferButton->setChecked(false); return; } @@ -5745,30 +5727,6 @@ void OBSBasic::ReplayBufferStop(int code) OnDeactivate(); } -bool OBSBasic::NoSourcesConfirmation() -{ - if (CountVideoSources() == 0 && isVisible()) { - QString msg; - msg = QTStr("NoSources.Text"); - msg += "\n\n"; - msg += QTStr("NoSources.Text.AddSource"); - - QMessageBox messageBox(this); - messageBox.setWindowTitle(QTStr("NoSources.Title")); - messageBox.setText(msg); - QAbstractButton *Yes = messageBox.addButton( - QTStr("Yes"), QMessageBox::YesRole); - messageBox.addButton(QTStr("No"), QMessageBox::NoRole); - messageBox.setIcon(QMessageBox::Question); - messageBox.exec(); - - if (messageBox.clickedButton() != Yes) - return false; - } - - return true; -} - void OBSBasic::on_streamButton_clicked() { if (outputHandler->StreamingActive()) { @@ -5791,7 +5749,21 @@ void OBSBasic::on_streamButton_clicked() StopStreaming(); } else { - if (!NoSourcesConfirmation()) { + if (!UIValidation::NoSourcesConfirmation(this)) { + ui->streamButton->setChecked(false); + return; + } + + auto action = + UIValidation::StreamSettingsConfirmation(this, service); + switch (action) { + case StreamSettingsAction::ContinueStream: + break; + case StreamSettingsAction::OpenSettings: + on_action_Settings_triggered(); + ui->streamButton->setChecked(false); + return; + case StreamSettingsAction::Cancel: ui->streamButton->setChecked(false); return; } @@ -5852,7 +5824,7 @@ void OBSBasic::on_recordButton_clicked() } StopRecording(); } else { - if (!NoSourcesConfirmation()) { + if (!UIValidation::NoSourcesConfirmation(this)) { ui->recordButton->setChecked(false); return; } diff --git a/UI/window-basic-main.hpp b/UI/window-basic-main.hpp index 83e0ca08c7c4051b83f17abd37f553ae207cd1bd..935e553baf141578b7703cebb56adaa030163999 100644 --- a/UI/window-basic-main.hpp +++ b/UI/window-basic-main.hpp @@ -456,8 +456,6 @@ private: void ReceivedIntroJson(const QString &text); - bool NoSourcesConfirmation(); - #ifdef BROWSER_AVAILABLE QList> extraBrowserDocks; QList> extraBrowserDockActions;