From 02e797a3dba4fa8bd4cda44322bba9a6dfc76cab Mon Sep 17 00:00:00 2001 From: WarmUpTill Date: Sun, 4 Oct 2020 16:28:36 +0200 Subject: [PATCH] first draft of UI improvements group settings of the general tab highlight if the scene switcher is inactive add draft of allowing editing in place define additional populate functions for audio and media --- forms/advanced-scene-switcher.ui | 1096 +++++++++++------------ src/advanced-scene-switcher.cpp | 114 ++- src/general.cpp | 38 + src/headers/advanced-scene-switcher.hpp | 12 +- src/headers/switch-audio.hpp | 29 + src/switch-audio.cpp | 94 +- src/switch-media.cpp | 15 +- 7 files changed, 738 insertions(+), 660 deletions(-) diff --git a/forms/advanced-scene-switcher.ui b/forms/advanced-scene-switcher.ui index ea4f2908..d4a2496f 100644 --- a/forms/advanced-scene-switcher.ui +++ b/forms/advanced-scene-switcher.ui @@ -44,597 +44,521 @@ General - - - - - - - WARNING! Condition checking interval must be greater than the duration of transitions to avoid scene locking - - - - - - - - - Qt::Horizontal - - - - - - - - - Qt::Vertical - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 0 - - - - - - - - - - Start - - - - - - - Check switch conditions every - - - - - - - Not Active - - - - - - - Advanced Scene Switcher is: - - - - - - - - 100 - 0 - - - - ms - - - 50 - - - 20000 - - - 300 - - - - - - - - - - - - - Don't switch - - - true - - - - - - - - - - - Switch to any scene in Random tab - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Switch to: - - - - - - - true - - - - 100 - 0 - - - - - - - - - - - - - 0 - 0 - - - - If no switch condition is met - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 0 - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 10 - 0 - - - - - - - - Qt::Vertical - - - - - - - On startup: - - - - - - - - - Qt::Horizontal - - - + - - - Order the different switching methods in order of their priority (with the highest priority being at the top): - - + + + + + Status + + + + + + + + Hotkeys can be defined in the OBS settings + + + + + + + Advanced Scene Switcher is: + + + + + + + On startup: + + + + + + + Start + + + + + + + + + + + 100 + 0 + + + + ms + + + 50 + + + 20000 + + + 300 + + + + + + + Check switch conditions every + + + + + + + + + Not Active + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + General behavior + + + + + + + + Automatically start + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + + on scene + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Automatically stop streaming/recording on scene + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Enable verbose logging (Only needed for debugging) + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Don't switch + + + true + + + + + + + + + + + Switch to any scene in Random tab + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Switch to: + + + + + + + true + + + + 100 + 0 + + + + + + + + + + + + + 0 + 0 + + + + If no switch condition is met + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + + + + + + Qt::Horizontal + + + + + + + - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - 22 - 22 - - - - - ../../../forms/images/up.png../../../forms/images/up.png - - - true - - - upArrowIconSmall - - - - - - - - 22 - 22 - - - - - ../../../forms/images/down.png../../../forms/images/down.png - - - true - - - downArrowIconSmall - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Automatically stop streaming/recording on scene - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - Automatically start - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - - - - on scene - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Horizontal - - - - - - - - - Use thread priority - - - - - - - - 0 - 0 - - - - - 100 - 0 - - - - - - - - (raising the priority higher than "Normal" is usually not recommended) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Horizontal - - - - - - - - - Export settings to file - - - - - - - Import settings from file - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Horizontal - - - - - - - (You can set a Hotkey to start and stop the scene switcher under Settings / Hotkeys / Toggle Start Stop for the Advanced Scene Switcher) - - - - - - - Qt::Horizontal - - - - - - - - - Enable verbose logging (Only needed for debugging) - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - + + + + + Priority + + + + + + Switching methods priority (Highest priority is at the top) + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + 22 + 22 + + + + + ../../../forms/images/up.png../../../forms/images/up.png + + + true + + + upArrowIconSmall + + + + + + + + 22 + 22 + + + + + ../../../forms/images/down.png../../../forms/images/down.png + + + true + + + downArrowIconSmall + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Use thread priority + + + + + + + + 0 + 0 + + + + + 100 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + (Raising the priority above "Normal" is not recommended) + + + + + + + + + + Save / load settings + + + + + + Export + + + + + + + Import + + + + + + + diff --git a/src/advanced-scene-switcher.cpp b/src/advanced-scene-switcher.cpp index b246eef6..8fc3da57 100644 --- a/src/advanced-scene-switcher.cpp +++ b/src/advanced-scene-switcher.cpp @@ -34,45 +34,6 @@ SceneSwitcher::SceneSwitcher(QWidget *parent) loadUI(); } -void SceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious) -{ - BPtr scenes = obs_frontend_get_scene_names(); - char **temp = scenes; - while (*temp) { - const char *name = *temp; - sel->addItem(name); - temp++; - } - - if (addPrevious) - sel->addItem(previous_scene_name); -} - -void SceneSwitcher::populateTransitionSelection(QComboBox *sel) -{ - obs_frontend_source_list *transitions = new obs_frontend_source_list(); - obs_frontend_get_transitions(transitions); - - for (size_t i = 0; i < transitions->sources.num; i++) { - const char *name = - obs_source_get_name(transitions->sources.array[i]); - sel->addItem(name); - } - - obs_frontend_source_list_free(transitions); -} - -void SceneSwitcher::populateWindowSelection(QComboBox *sel) -{ - std::vector windows; - GetWindowList(windows); - sort(windows.begin(), windows.end()); - - for (std::string &window : windows) { - sel->addItem(window.c_str()); - } -} - void SceneSwitcher::loadUI() { #if __APPLE__ @@ -237,7 +198,7 @@ void SwitcherData::Thread() break; case round_trip_func: checkSceneSequence(match, scene, transition, - lock); + lock); if (sceneChangedDuringWait()) //scene might have changed during the sleep { goto startLoop; @@ -343,6 +304,79 @@ void SwitcherData::Stop() } } +void SceneSwitcher::populateSceneSelection(QComboBox *sel, bool addPrevious) +{ + BPtr scenes = obs_frontend_get_scene_names(); + char **temp = scenes; + while (*temp) { + const char *name = *temp; + sel->addItem(name); + temp++; + } + + if (addPrevious) + sel->addItem(previous_scene_name); +} + +void SceneSwitcher::populateTransitionSelection(QComboBox *sel) +{ + obs_frontend_source_list *transitions = new obs_frontend_source_list(); + obs_frontend_get_transitions(transitions); + + for (size_t i = 0; i < transitions->sources.num; i++) { + const char *name = + obs_source_get_name(transitions->sources.array[i]); + sel->addItem(name); + } + + obs_frontend_source_list_free(transitions); +} + +void SceneSwitcher::populateWindowSelection(QComboBox *sel) +{ + std::vector windows; + GetWindowList(windows); + sort(windows.begin(), windows.end()); + + for (std::string &window : windows) { + sel->addItem(window.c_str()); + } +} + +void SceneSwitcher::populateAudioSelection(QComboBox *sel) +{ + auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ + { + QComboBox *combo = reinterpret_cast(data); + uint32_t flags = obs_source_get_output_flags(source); + + if ((flags & OBS_SOURCE_AUDIO) != 0) { + const char *name = obs_source_get_name(source); + combo->addItem(name); + } + return true; + }; + + obs_enum_sources(sourceEnum, sel); +} + +void SceneSwitcher::populateMediaSelection(QComboBox *sel) +{ + auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ + { + QComboBox *combo = reinterpret_cast(data); + std::string sourceId = obs_source_get_id(source); + if (sourceId.compare("ffmpeg_source") == 0 || + sourceId.compare("vlc_source") == 0) { + const char *name = obs_source_get_name(source); + combo->addItem(name); + } + return true; + }; + + obs_enum_sources(sourceEnum, sel); +} + /******************************************************************************** * OBS module setup ********************************************************************************/ diff --git a/src/general.cpp b/src/general.cpp index 6111a74c..6c2e4137 100644 --- a/src/general.cpp +++ b/src/general.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include "headers/advanced-scene-switcher.hpp" @@ -79,16 +81,52 @@ void SceneSwitcher::on_checkInterval_valueChanged(int value) switcher->interval = value; } +void SceneSwitcher::StartInactivePulse() +{ + ui->pluginRunningText->setStyleSheet("QLabel { \ + border-style: outset; \ + border-width: 2px; \ + border-radius: 10px; \ + border-color: rgb(0,0,0,0) \ + }"); + + QGraphicsColorizeEffect *eEffect = + new QGraphicsColorizeEffect(ui->pluginRunningText); + ui->pluginRunningText->setGraphicsEffect(eEffect); + QPropertyAnimation *paAnimation = + new QPropertyAnimation(eEffect, "color"); + paAnimation->setStartValue(QColor(0, 0, 0, 0)); + paAnimation->setEndValue(QColor(Qt::red)); + paAnimation->setDuration(1000); + + connect(paAnimation, &QPropertyAnimation::finished, [paAnimation]() { + if (switcher->stop) + QTimer::singleShot(1000, [paAnimation] { + paAnimation->start(); + }); + }); + + paAnimation->start(); +} + +void SceneSwitcher::ResetInactivePulse() +{ + ui->pluginRunningText->setStyleSheet( + "QLabel { background-color: rgb(0,0,0,0); }"); +} + void SceneSwitcher::SetStarted() { ui->toggleStartButton->setText("Stop"); ui->pluginRunningText->setText("Active"); + ResetInactivePulse(); } void SceneSwitcher::SetStopped() { ui->toggleStartButton->setText("Start"); ui->pluginRunningText->setText("Inactive"); + StartInactivePulse(); } void SceneSwitcher::on_toggleStartButton_clicked() diff --git a/src/headers/advanced-scene-switcher.hpp b/src/headers/advanced-scene-switcher.hpp index 8dc31914..509ca26d 100644 --- a/src/headers/advanced-scene-switcher.hpp +++ b/src/headers/advanced-scene-switcher.hpp @@ -55,9 +55,6 @@ public: void SetAudioVolumeMeter(const QString &name); void loadUI(); - void populateSceneSelection(QComboBox *sel, bool addPrevious); - void populateTransitionSelection(QComboBox *sel); - void populateWindowSelection(QComboBox *sel); void setupGeneralTab(); void setupTitleTab(); void setupExecutableTab(); @@ -73,6 +70,13 @@ public: void setupAudioTab(); void setTabOrder(); + static void populateSceneSelection(QComboBox *sel, + bool addPrevious = false); + static void populateTransitionSelection(QComboBox *sel); + static void populateWindowSelection(QComboBox *sel); + static void populateAudioSelection(QComboBox *sel); + static void populateMediaSelection(QComboBox *sel); + public slots: void on_switches_currentRowChanged(int idx); void on_up_clicked(); @@ -85,6 +89,8 @@ public slots: void on_startupBehavior_currentIndexChanged(int index); void on_noMatchSwitchScene_currentTextChanged(const QString &text); void on_checkInterval_valueChanged(int value); + void StartInactivePulse(); + void ResetInactivePulse(); void on_toggleStartButton_clicked(); void on_tabMoved(int from, int to); diff --git a/src/headers/switch-audio.hpp b/src/headers/switch-audio.hpp index d7627fb9..c1fb6b75 100644 --- a/src/headers/switch-audio.hpp +++ b/src/headers/switch-audio.hpp @@ -1,7 +1,12 @@ #pragma once +#include +#include +#include #include + #include "utility.hpp" #include "switch-generic.hpp" +#include "volume-control.hpp" constexpr auto audio_func = 8; constexpr auto default_priority_8 = audio_func; @@ -113,3 +118,27 @@ static inline QString MakeAudioSwitchName(const QString &scene, const QString &transition, const QString &audioSrouce, const int &volume); + +class AudioSwitchWidget : public QWidget { + Q_OBJECT + +public: + AudioSwitchWidget(QWidget *parent = nullptr, + const QString &audioScene = "", + const QString &audioTransition = "", + const QString &audioSource = "", + const int &threshold = 0); + +private: + QComboBox *audioScenes; + QComboBox *audioTransitions; + QComboBox *audioSources; + QSpinBox *audioVolumeThreshold; + + VolControl *volMeter; + + QLabel *whenLabel; + QLabel *aboveLabel; + QLabel *switchLabel; + QLabel *usingLabel; +}; diff --git a/src/switch-audio.cpp b/src/switch-audio.cpp index 60812ddd..f32cb5f9 100644 --- a/src/switch-audio.cpp +++ b/src/switch-audio.cpp @@ -1,3 +1,6 @@ +#include +#include + #include "headers/advanced-scene-switcher.hpp" #include "headers/volume-control.hpp" @@ -289,20 +292,7 @@ void SceneSwitcher::setupAudioTab() { populateSceneSelection(ui->audioScenes, true); populateTransitionSelection(ui->audioTransitions); - - auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ - { - QComboBox *combo = reinterpret_cast(data); - uint32_t flags = obs_source_get_output_flags(source); - - if ((flags & OBS_SOURCE_AUDIO) != 0) { - const char *name = obs_source_get_name(source); - combo->addItem(name); - } - return true; - }; - - obs_enum_sources(sourceEnum, ui->audioSources); + populateAudioSelection(ui->audioSources); for (auto &s : switcher->audioSwitches) { std::string sceneName = (s.usePreviousScene) @@ -315,9 +305,18 @@ void SceneSwitcher::setupAudioTab() audioSourceName.c_str(), s.volumeThreshold); - QListWidgetItem *item = - new QListWidgetItem(listText, ui->audioSwitches); - item->setData(Qt::UserRole, listText); + //QListWidgetItem *item = + // new QListWidgetItem(listText, ui->audioSwitches); + //item->setData(Qt::UserRole, listText); + + QListWidgetItem *item; + item = new QListWidgetItem(ui->audioSwitches); + ui->audioSwitches->addItem(item); + AudioSwitchWidget *sw = new AudioSwitchWidget( + nullptr, sceneName.c_str(), transitionName.c_str(), + audioSourceName.c_str(), s.volumeThreshold); + item->setSizeHint(sw->minimumSizeHint()); + ui->audioSwitches->setItemWidget(item, sw); } } @@ -333,3 +332,64 @@ static inline QString MakeAudioSwitchName(const QString &scene, QStringLiteral(" using ") + transition; return switchName; } + +AudioSwitchWidget::AudioSwitchWidget(QWidget *parent, const QString &audioScene, + const QString &audioTransition, + const QString &audioSource, + const int &threshold) + : QWidget(parent) +{ + audioScenes = new QComboBox(); + audioTransitions = new QComboBox(); + audioSources = new QComboBox(); + audioVolumeThreshold = new QSpinBox(); + + obs_source_t *soruce = + obs_get_source_by_name(audioSource.toUtf8().constData()); + volMeter = new VolControl(soruce); + obs_source_release(soruce); + + whenLabel = new QLabel("When the volume of"); + aboveLabel = new QLabel("is above"); + switchLabel = new QLabel("switch to"); + usingLabel = new QLabel("using"); + + audioVolumeThreshold->setSuffix("%"); + audioVolumeThreshold->setMaximum(100); + audioVolumeThreshold->setMinimum(0); + + QWidget::connect(volMeter->GetSlider(), SIGNAL(valueChanged(int)), + audioVolumeThreshold, SLOT(setValue(int))); + QWidget::connect(audioVolumeThreshold, SIGNAL(valueChanged(int)), + volMeter->GetSlider(), SLOT(setValue(int))); + + SceneSwitcher::populateSceneSelection(audioScenes, true); + SceneSwitcher::populateTransitionSelection(audioTransitions); + SceneSwitcher::populateAudioSelection(audioSources); + + audioScenes->setCurrentText(audioScene); + audioTransitions->setCurrentText(audioTransition); + audioSources->setCurrentText(audioSource); + audioVolumeThreshold->setValue(threshold); + + setStyleSheet("* { background-color: transparent; }"); + + QHBoxLayout *switchLayout = new QHBoxLayout; + + switchLayout->addWidget(whenLabel); + switchLayout->addWidget(audioSources); + switchLayout->addWidget(aboveLabel); + switchLayout->addWidget(audioVolumeThreshold); + switchLayout->addWidget(switchLabel); + switchLayout->addWidget(audioScenes); + switchLayout->addWidget(usingLabel); + switchLayout->addWidget(audioTransitions); + switchLayout->addStretch(); + + QVBoxLayout *mainLayout = new QVBoxLayout; + + mainLayout->addLayout(switchLayout); + mainLayout->addWidget(volMeter); + + setLayout(mainLayout); +} diff --git a/src/switch-media.cpp b/src/switch-media.cpp index 26574aeb..b5e7e552 100644 --- a/src/switch-media.cpp +++ b/src/switch-media.cpp @@ -254,20 +254,7 @@ void SceneSwitcher::setupMediaTab() { populateSceneSelection(ui->mediaScenes, true); populateTransitionSelection(ui->mediaTransitions); - - auto sourceEnum = [](void *data, obs_source_t *source) -> bool /* -- */ - { - QComboBox *combo = reinterpret_cast(data); - std::string sourceId = obs_source_get_id(source); - if (sourceId.compare("ffmpeg_source") == 0 || - sourceId.compare("vlc_source") == 0) { - const char *name = obs_source_get_name(source); - combo->addItem(name); - } - return true; - }; - - obs_enum_sources(sourceEnum, ui->mediaSources); + populateMediaSelection(ui->mediaSources); ui->mediaStates->addItem("None"); ui->mediaStates->addItem("Playing");