SceneSwitcher/lib/general.cpp
WarmUpTill 77528520d9 Change settings defaults
* Start plugin by default
* Highlight condittions, actions, and recently executed macros by
  default
* Open Macro tab instead of General tab when opening settings window
* No longer start legacy websocket server and client
2024-01-27 14:10:34 +01:00

1044 lines
28 KiB
C++

#include "advanced-scene-switcher.hpp"
#include "file-selection.hpp"
#include "filter-combo-box.hpp"
#include "macro.hpp"
#include "status-control.hpp"
#include "switcher-data.hpp"
#include "utility.hpp"
#include "variable.hpp"
#include "version.h"
#include <QFileDialog>
namespace advss {
void AdvSceneSwitcher::reject()
{
close();
}
void AdvSceneSwitcher::UpdateNonMatchingScene(const QString &name)
{
obs_source_t *scene = obs_get_source_by_name(name.toUtf8().constData());
obs_weak_source_t *ws = obs_source_get_weak_source(scene);
switcher->nonMatchingScene = ws;
obs_weak_source_release(ws);
obs_source_release(scene);
}
void AdvSceneSwitcher::on_noMatchDontSwitch_clicked()
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NoMatchBehavior::NO_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
ui->randomDisabledWarning->setVisible(true);
}
void AdvSceneSwitcher::on_noMatchSwitch_clicked()
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NoMatchBehavior::SWITCH;
ui->noMatchSwitchScene->setEnabled(true);
UpdateNonMatchingScene(ui->noMatchSwitchScene->currentText());
ui->randomDisabledWarning->setVisible(true);
}
void AdvSceneSwitcher::on_noMatchRandomSwitch_clicked()
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->switchIfNotMatching = NoMatchBehavior::RANDOM_SWITCH;
ui->noMatchSwitchScene->setEnabled(false);
ui->randomDisabledWarning->setVisible(false);
}
void AdvSceneSwitcher::NoMatchDelayDurationChanged(const Duration &dur)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->noMatchDelay = dur;
}
void AdvSceneSwitcher::CooldownDurationChanged(const Duration &dur)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->cooldown = dur;
}
void AdvSceneSwitcher::on_startupBehavior_currentIndexChanged(int index)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->startupBehavior =
static_cast<SwitcherData::StartupBehavior>(index);
}
void AdvSceneSwitcher::on_autoStartEvent_currentIndexChanged(int index)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->autoStartEvent = static_cast<SwitcherData::AutoStart>(index);
}
void AdvSceneSwitcher::on_noMatchSwitchScene_currentTextChanged(
const QString &text)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
UpdateNonMatchingScene(text);
}
void AdvSceneSwitcher::on_checkInterval_valueChanged(int value)
{
if (loading) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->interval = value;
}
void AdvSceneSwitcher::closeEvent(QCloseEvent *)
{
if (!switcher) {
return;
}
switcher->windowPos = this->pos();
switcher->windowSize = this->size();
switcher->macroListMacroEditSplitterPosition =
ui->macroListMacroEditSplitter->sizes();
MacroSelectionAboutToChange(); // Trigger saving of splitter states
obs_frontend_save();
}
void AdvSceneSwitcher::on_verboseLogging_stateChanged(int state)
{
if (loading) {
return;
}
switcher->verbose = state;
}
void AdvSceneSwitcher::on_saveWindowGeo_stateChanged(int state)
{
if (loading) {
return;
}
switcher->saveWindowGeo = state;
}
void AdvSceneSwitcher::on_showTrayNotifications_stateChanged(int state)
{
if (loading) {
return;
}
switcher->showSystemTrayNotifications = state;
}
void AdvSceneSwitcher::on_uiHintsDisable_stateChanged(int state)
{
if (loading) {
return;
}
switcher->disableHints = state;
}
void AdvSceneSwitcher::on_disableComboBoxFilter_stateChanged(int state)
{
if (loading) {
return;
}
switcher->disableFilterComboboxFilter = state;
FilterComboBox::SetFilterBehaviourEnabled(!state);
}
void AdvSceneSwitcher::on_warnPluginLoadFailure_stateChanged(int state)
{
if (loading) {
return;
}
switcher->warnPluginLoadFailure = state;
}
static bool isLegacyTab(const QString &name)
{
return name == obs_module_text(
"AdvSceneSwitcher.sceneGroupTab.title") ||
name == obs_module_text("AdvSceneSwitcher.networkTab.title") ||
name == obs_module_text(
"AdvSceneSwitcher.transitionTab.title") ||
name == obs_module_text(
"AdvSceneSwitcher.windowTitleTab.title") ||
name == obs_module_text(
"AdvSceneSwitcher.executableTab.title") ||
name == obs_module_text(
"AdvSceneSwitcher.screenRegionTab.title") ||
name == obs_module_text("AdvSceneSwitcher.mediaTab.title") ||
name == obs_module_text("AdvSceneSwitcher.fileTab.title") ||
name == obs_module_text("AdvSceneSwitcher.randomTab.title") ||
name == obs_module_text("AdvSceneSwitcher.timeTab.title") ||
name == obs_module_text("AdvSceneSwitcher.idleTab.title") ||
name == obs_module_text(
"AdvSceneSwitcher.sceneSequenceTab.title") ||
name == obs_module_text("AdvSceneSwitcher.audioTab.title") ||
name == obs_module_text("AdvSceneSwitcher.videoTab.title") ||
name == obs_module_text("AdvSceneSwitcher.pauseTab.title") ||
name == obs_module_text(
"AdvSceneSwitcher.sceneTriggerTab.title");
}
void AdvSceneSwitcher::on_hideLegacyTabs_stateChanged(int state)
{
switcher->hideLegacyTabs = state;
for (int idx = 0; idx < ui->tabWidget->count(); idx++) {
if (isLegacyTab(ui->tabWidget->tabText(idx))) {
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// TODO: Switch to setTabVisible() once QT 5.15 is more wide spread
ui->tabWidget->setTabEnabled(idx, !state);
ui->tabWidget->setStyleSheet(
"QTabBar::tab::disabled {width: 0; height: 0; margin: 0; padding: 0; border: none;} ");
#else
ui->tabWidget->setTabVisible(idx, !state);
#endif
}
}
}
void AdvSceneSwitcher::SetDeprecationWarnings()
{
QString toolTip =
switcher->disableHints
? ""
: obs_module_text(
"AdvSceneSwitcher.deprecatedTabWarning");
for (int idx = 0; idx < ui->tabWidget->count(); idx++) {
if (isLegacyTab(ui->tabWidget->tabText(idx))) {
ui->tabWidget->widget(idx)->setToolTip(toolTip);
}
}
}
void AdvSceneSwitcher::on_exportSettings_clicked()
{
QString directory = QFileDialog::getSaveFileName(
this,
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.exportWindowTitle")),
GetDefaultSettingsSaveLocation(),
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (directory.isEmpty()) {
return;
}
QFile file(directory);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return;
}
obs_data_t *obj = obs_data_create();
switcher->SaveSettings(obj);
obs_data_save_json(obj, file.fileName().toUtf8().constData());
obs_data_release(obj);
}
void AdvSceneSwitcher::on_importSettings_clicked()
{
// Scene switcher could be stuck in a sequence
// so it needs to be stopped before importing new settings
bool start = !switcher->stop;
switcher->Stop();
auto basePath = FileSelection::ValidPathOrDesktop(
QString::fromStdString(switcher->lastImportPath));
QString path = QFileDialog::getOpenFileName(
this,
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.importWindowTitle")),
basePath,
tr(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.textType")));
if (path.isEmpty()) {
return;
}
QFile file(path);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
return;
}
obs_data_t *obj = obs_data_create_from_json_file(
file.fileName().toUtf8().constData());
if (!obj) {
(void)DisplayMessage(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadFail"));
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->LoadSettings(obj);
obs_data_release(obj);
switcher->lastImportPath = path.toStdString();
(void)DisplayMessage(obs_module_text(
"AdvSceneSwitcher.generalTab.saveOrLoadsettings.loadSuccess"));
// Just close the UI and let the user reopen it to not have to
// implement updating each setting
close();
// Restart scene switcher if it was active
if (start) {
switcher->Start();
}
}
static int findTabIndex(QTabWidget *tabWidget, int pos)
{
int at = -1;
QString tabName = "";
switch (pos) {
case 0:
tabName = "generalTab";
break;
case 1:
tabName = "macroTab";
break;
case 2:
tabName = "transitionsTab";
break;
case 3:
tabName = "pauseTab";
break;
case 4:
tabName = "windowTitleTab";
break;
case 5:
tabName = "executableTab";
break;
case 6:
tabName = "screenRegionTab";
break;
case 7:
tabName = "mediaTab";
break;
case 8:
tabName = "fileTab";
break;
case 9:
tabName = "randomTab";
break;
case 10:
tabName = "timeTab";
break;
case 11:
tabName = "idleTab";
break;
case 12:
tabName = "sceneSequenceTab";
break;
case 13:
tabName = "audioTab";
break;
case 14:
tabName = "videoTab";
break;
case 15:
tabName = "networkTab";
break;
case 16:
tabName = "sceneGroupTab";
break;
case 17:
tabName = "sceneTriggerTab";
break;
}
QWidget *page = tabWidget->findChild<QWidget *>(tabName);
if (page) {
at = tabWidget->indexOf(page);
}
if (at == -1) {
blog(LOG_INFO, "failed to find tab %s",
tabName.toUtf8().constData());
}
return at;
}
void AdvSceneSwitcher::SetTabOrder()
{
if (!switcher->TabOrderValid()) {
switcher->ResetTabOrder();
}
QTabBar *bar = ui->tabWidget->tabBar();
for (int i = 0; i < bar->count(); ++i) {
int curPos = findTabIndex(ui->tabWidget, switcher->tabOrder[i]);
if (i != curPos && curPos != -1) {
bar->moveTab(curPos, i);
}
}
connect(bar, &QTabBar::tabMoved, this, &AdvSceneSwitcher::on_tabMoved);
}
void AdvSceneSwitcher::SetCurrentTab()
{
if (switcher->lastOpenedTab >= 0) {
ui->tabWidget->setCurrentIndex(switcher->lastOpenedTab);
}
}
static bool windowPosValid(QPoint pos)
{
return !!QGuiApplication::screenAt(pos);
}
void AdvSceneSwitcher::RestoreWindowGeo()
{
if (switcher->saveWindowGeo && windowPosValid(switcher->windowPos)) {
this->resize(switcher->windowSize);
this->move(switcher->windowPos);
}
}
void AdvSceneSwitcher::CheckFirstTimeSetup()
{
if (switcher->firstBoot && !switcher->disableHints) {
switcher->firstBoot = false;
DisplayMessage(
obs_module_text("AdvSceneSwitcher.firstBootMessage"));
}
}
void AdvSceneSwitcher::on_tabMoved(int from, int to)
{
if (loading) {
return;
}
std::swap(switcher->tabOrder[from], switcher->tabOrder[to]);
}
void AdvSceneSwitcher::on_tabWidget_currentChanged(int)
{
switcher->showFrame = false;
ClearFrames(ui->screenRegionSwitches);
SetShowFrames();
}
void AdvSceneSwitcher::on_transitionOverridecheckBox_stateChanged(int state)
{
if (loading) {
return;
}
if (!state && !switcher->adjustActiveTransitionType) {
DisplayMessage(obs_module_text(
"AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError"));
ui->adjustActiveTransitionType->setChecked(true);
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->transitionOverrideOverride = state;
}
void AdvSceneSwitcher::on_adjustActiveTransitionType_stateChanged(int state)
{
if (loading) {
return;
}
// This option only makes sense if we are allowed to use transition overrides
if (!state && !switcher->transitionOverrideOverride) {
DisplayMessage(obs_module_text(
"AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError"));
ui->transitionOverridecheckBox->setChecked(true);
}
std::lock_guard<std::mutex> lock(switcher->m);
switcher->adjustActiveTransitionType = state;
}
void SwitcherData::LoadSettings(obs_data_t *obj)
{
if (!obj) {
return;
}
// New post load steps to be declared during load
postLoadSteps.clear();
// Needs to be loaded before any entries which might rely on scene group
// selections to be available.
loadSceneGroups(obj);
LoadVariables(obj);
for (const auto &func : loadSteps) {
func(obj);
}
LoadMacros(obj);
LoadGlobalMacroProperties(obj);
loadWindowTitleSwitches(obj);
loadScreenRegionSwitches(obj);
loadPauseSwitches(obj);
loadSceneSequenceSwitches(obj);
loadSceneTransitions(obj);
loadIdleSwitches(obj);
loadExecutableSwitches(obj);
loadRandomSwitches(obj);
loadFileSwitches(obj);
loadMediaSwitches(obj);
loadTimeSwitches(obj);
loadAudioSwitches(obj);
loadVideoSwitches(obj);
loadNetworkSettings(obj);
loadSceneTriggers(obj);
LoadGeneralSettings(obj);
LoadHotkeys(obj);
LoadUISettings(obj);
for (const auto &func : postLoadSteps) {
func();
}
// Reset on startup and scene collection change
switcher->lastOpenedTab = -1;
startupLoadDone = true;
}
void SwitcherData::SaveSettings(obs_data_t *obj)
{
if (!obj) {
return;
}
saveSceneGroups(obj);
SaveMacros(obj);
SaveGlobalMacroProperties(obj);
SaveVariables(obj);
saveWindowTitleSwitches(obj);
saveScreenRegionSwitches(obj);
savePauseSwitches(obj);
saveSceneSequenceSwitches(obj);
saveSceneTransitions(obj);
saveIdleSwitches(obj);
saveExecutableSwitches(obj);
saveRandomSwitches(obj);
saveFileSwitches(obj);
saveMediaSwitches(obj);
saveTimeSwitches(obj);
saveAudioSwitches(obj);
saveVideoSwitches(obj);
saveNetworkSwitches(obj);
saveSceneTriggers(obj);
SaveGeneralSettings(obj);
SaveHotkeys(obj);
SaveUISettings(obj);
SaveVersion(obj, g_GIT_SHA1);
for (const auto &func : saveSteps) {
func(obj);
}
}
void SwitcherData::SaveGeneralSettings(obs_data_t *obj)
{
obs_data_set_int(obj, "interval", interval);
std::string nonMatchingSceneName = GetWeakSourceName(nonMatchingScene);
obs_data_set_string(obj, "non_matching_scene",
nonMatchingSceneName.c_str());
obs_data_set_int(obj, "switch_if_not_matching",
static_cast<int>(switchIfNotMatching));
noMatchDelay.Save(obj, "noMatchDelay");
cooldown.Save(obj, "cooldown");
obs_data_set_bool(obj, "active", sceneColletionStop ? true : !stop);
sceneColletionStop = false;
obs_data_set_int(obj, "startup_behavior",
static_cast<int>(startupBehavior));
obs_data_set_int(obj, "autoStartEvent",
static_cast<int>(autoStartEvent));
obs_data_set_bool(obj, "verbose", verbose);
obs_data_set_bool(obj, "showSystemTrayNotifications",
showSystemTrayNotifications);
obs_data_set_bool(obj, "disableHints", disableHints);
obs_data_set_bool(obj, "disableFilterComboboxFilter",
disableFilterComboboxFilter);
obs_data_set_bool(obj, "warnPluginLoadFailure", warnPluginLoadFailure);
obs_data_set_bool(obj, "hideLegacyTabs", hideLegacyTabs);
SaveFunctionPriorities(obj, functionNamesByPriority);
obs_data_set_int(obj, "threadPriority", threadPriority);
obs_data_set_bool(obj, "transitionOverrideOverride",
transitionOverrideOverride);
obs_data_set_bool(obj, "adjustActiveTransitionType",
adjustActiveTransitionType);
obs_data_set_string(obj, "lastImportPath", lastImportPath.c_str());
}
void SwitcherData::LoadGeneralSettings(obs_data_t *obj)
{
obs_data_set_default_int(obj, "interval", default_interval);
interval = obs_data_get_int(obj, "interval");
obs_data_set_default_int(obj, "switch_if_not_matching",
static_cast<int>(NoMatchBehavior::NO_SWITCH));
switchIfNotMatching = static_cast<NoMatchBehavior>(
obs_data_get_int(obj, "switch_if_not_matching"));
std::string nonMatchingSceneName =
obs_data_get_string(obj, "non_matching_scene");
nonMatchingScene = GetWeakSourceByName(nonMatchingSceneName.c_str());
noMatchDelay.Load(obj, "noMatchDelay");
cooldown.Load(obj, "cooldown");
obs_data_set_default_bool(obj, "active", true);
stop = !obs_data_get_bool(obj, "active");
startupBehavior =
(StartupBehavior)obs_data_get_int(obj, "startup_behavior");
if (startupBehavior == StartupBehavior::START) {
stop = false;
}
if (startupBehavior == StartupBehavior::STOP) {
stop = true;
}
autoStartEvent =
static_cast<AutoStart>(obs_data_get_int(obj, "autoStartEvent"));
verbose = obs_data_get_bool(obj, "verbose");
showSystemTrayNotifications =
obs_data_get_bool(obj, "showSystemTrayNotifications");
disableHints = obs_data_get_bool(obj, "disableHints");
disableFilterComboboxFilter =
obs_data_get_bool(obj, "disableFilterComboboxFilter");
obs_data_set_default_bool(obj, "warnPluginLoadFailure", true);
warnPluginLoadFailure = obs_data_get_bool(obj, "warnPluginLoadFailure");
obs_data_set_default_bool(obj, "hideLegacyTabs", true);
hideLegacyTabs = obs_data_get_bool(obj, "hideLegacyTabs");
SetDefaultFunctionPriorities(obj);
LoadFunctionPriorities(obj, functionNamesByPriority);
if (!PrioFuncsValid()) {
functionNamesByPriority = GetDefaultFunctionPriorityList();
}
obs_data_set_default_int(obj, "threadPriority",
QThread::NormalPriority);
threadPriority = obs_data_get_int(obj, "threadPriority");
transitionOverrideOverride =
obs_data_get_bool(obj, "transitionOverrideOverride");
adjustActiveTransitionType =
obs_data_get_bool(obj, "adjustActiveTransitionType");
if (!transitionOverrideOverride && !adjustActiveTransitionType) {
blog(LOG_INFO,
"reset transition behaviour to adjust active transition type");
adjustActiveTransitionType = true;
}
lastImportPath = obs_data_get_string(obj, "lastImportPath");
}
void SwitcherData::SaveUISettings(obs_data_t *obj)
{
obs_data_set_int(obj, "generalTabPos", tabOrder[0]);
obs_data_set_int(obj, "macroTabPos", tabOrder[1]);
obs_data_set_int(obj, "transitionTabPos", tabOrder[2]);
obs_data_set_int(obj, "pauseTabPos", tabOrder[3]);
obs_data_set_int(obj, "titleTabPos", tabOrder[4]);
obs_data_set_int(obj, "exeTabPos", tabOrder[5]);
obs_data_set_int(obj, "regionTabPos", tabOrder[6]);
obs_data_set_int(obj, "mediaTabPos", tabOrder[7]);
obs_data_set_int(obj, "fileTabPos", tabOrder[8]);
obs_data_set_int(obj, "randomTabPos", tabOrder[9]);
obs_data_set_int(obj, "timeTabPos", tabOrder[10]);
obs_data_set_int(obj, "idleTabPos", tabOrder[11]);
obs_data_set_int(obj, "sequenceTabPos", tabOrder[12]);
obs_data_set_int(obj, "audioTabPos", tabOrder[13]);
obs_data_set_int(obj, "videoTabPos", tabOrder[14]);
obs_data_set_int(obj, "networkTabPos", tabOrder[15]);
obs_data_set_int(obj, "sceneGroupTabPos", tabOrder[16]);
obs_data_set_int(obj, "triggerTabPos", tabOrder[17]);
obs_data_set_bool(obj, "saveWindowGeo", saveWindowGeo);
obs_data_set_int(obj, "windowPosX", windowPos.x());
obs_data_set_int(obj, "windowPosY", windowPos.y());
obs_data_set_int(obj, "windowWidth", windowSize.width());
obs_data_set_int(obj, "windowHeight", windowSize.height());
SaveSplitterPos(macroListMacroEditSplitterPosition, obj,
"macroListMacroEditSplitterPosition");
}
void SwitcherData::LoadUISettings(obs_data_t *obj)
{
obs_data_set_default_int(obj, "generalTabPos", 0);
obs_data_set_default_int(obj, "macroTabPos", 1);
obs_data_set_default_int(obj, "networkTabPos", 13);
obs_data_set_default_int(obj, "sceneGroupTabPos", 14);
obs_data_set_default_int(obj, "transitionTabPos", 15);
obs_data_set_default_int(obj, "pauseTabPos", 16);
obs_data_set_default_int(obj, "titleTabPos", 2);
obs_data_set_default_int(obj, "exeTabPos", 3);
obs_data_set_default_int(obj, "regionTabPos", 4);
obs_data_set_default_int(obj, "mediaTabPos", 5);
obs_data_set_default_int(obj, "fileTabPos", 6);
obs_data_set_default_int(obj, "randomTabPos", 7);
obs_data_set_default_int(obj, "timeTabPos", 8);
obs_data_set_default_int(obj, "idleTabPos", 9);
obs_data_set_default_int(obj, "sequenceTabPos", 10);
obs_data_set_default_int(obj, "audioTabPos", 11);
obs_data_set_default_int(obj, "videoTabPos", 12);
obs_data_set_default_int(obj, "triggerTabPos", 17);
tabOrder.clear();
tabOrder.emplace_back((int)(obs_data_get_int(obj, "generalTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "macroTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "transitionTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "pauseTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "titleTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "exeTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "regionTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "mediaTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "fileTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "randomTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "timeTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "idleTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "sequenceTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "audioTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "videoTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "networkTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "sceneGroupTabPos")));
tabOrder.emplace_back((int)(obs_data_get_int(obj, "triggerTabPos")));
if (!TabOrderValid()) {
ResetTabOrder();
}
saveWindowGeo = obs_data_get_bool(obj, "saveWindowGeo");
windowPos = {(int)obs_data_get_int(obj, "windowPosX"),
(int)obs_data_get_int(obj, "windowPosY")};
windowSize = {(int)obs_data_get_int(obj, "windowWidth"),
(int)obs_data_get_int(obj, "windowHeight")};
LoadSplitterPos(macroListMacroEditSplitterPosition, obj,
"macroListMacroEditSplitterPosition");
}
bool SwitcherData::TabOrderValid()
{
auto tmp = std::vector<int>(tab_count);
std::iota(tmp.begin(), tmp.end(), 0);
for (auto &p : tmp) {
auto it = std::find(tabOrder.begin(), tabOrder.end(), p);
if (it == tabOrder.end()) {
return false;
}
}
return true;
}
void SwitcherData::ResetTabOrder()
{
tabOrder = std::vector<int>(tab_count);
std::iota(tabOrder.begin(), tabOrder.end(), 0);
}
void SwitcherData::CheckNoMatchSwitch(bool &match, OBSWeakSource &scene,
OBSWeakSource &transition, int &sleep)
{
if (match) {
noMatchDelay.Reset();
return;
}
if (!noMatchDelay.DurationReached()) {
return;
}
if (switchIfNotMatching == NoMatchBehavior::SWITCH &&
nonMatchingScene) {
match = true;
scene = nonMatchingScene;
transition = nullptr;
}
if (switchIfNotMatching == NoMatchBehavior::RANDOM_SWITCH) {
match = checkRandom(scene, transition, sleep);
}
}
void SwitcherData::checkSwitchCooldown(bool &match)
{
if (!match) {
return;
}
if (cooldown.DurationReached()) {
cooldown.Reset();
} else {
match = false;
vblog(LOG_INFO, "cooldown active - ignoring match");
}
}
static void populateStartupBehavior(QComboBox *cb)
{
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.asLastRun"));
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.alwaysStart"));
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.onStartup.doNotStart"));
}
static void populateAutoStartEventSelection(QComboBox *cb)
{
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.autoStart.never"));
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.autoStart.recording"));
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.autoStart.streaming"));
cb->addItem(obs_module_text(
"AdvSceneSwitcher.generalTab.status.autoStart.recordingAndStreaming"));
}
static void populatePriorityFunctionList(QListWidget *list)
{
for (int p : switcher->functionNamesByPriority) {
std::string s = "";
switch (p) {
case read_file_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.fileContent");
break;
case round_trip_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.sceneSequence");
break;
case idle_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.idleDetection");
break;
case exe_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.executable");
break;
case screen_region_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.screenRegion");
break;
case window_title_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.windowTitle");
break;
case media_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.media");
break;
case time_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.time");
break;
case audio_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.audio");
break;
case video_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.video");
break;
case macro_func:
s = obs_module_text(
"AdvSceneSwitcher.generalTab.priority.macro");
break;
}
QString text(s.c_str());
QListWidgetItem *item = new QListWidgetItem(text, list);
item->setData(Qt::UserRole, text);
}
}
static void populateThreadPriorityList(QComboBox *list)
{
for (int i = 0; i < (int)switcher->threadPriorities.size(); ++i) {
list->addItem(switcher->threadPriorities[i].name.c_str());
list->setItemData(
i, switcher->threadPriorities[i].description.c_str(),
Qt::ToolTipRole);
if (switcher->threadPriority ==
switcher->threadPriorities[i].value) {
list->setCurrentText(
switcher->threadPriorities[i].name.c_str());
}
}
}
static bool isGeneralTab(const QString &name)
{
return name == obs_module_text("AdvSceneSwitcher.generalTab.title");
}
static int getGeneralTabIdx(QTabWidget *tabWidget)
{
for (int idx = 0; idx < tabWidget->count(); idx++) {
if (isGeneralTab(tabWidget->tabText(idx))) {
return idx;
}
}
return -1;
}
static void setupGeneralTabInactiveWarning(QTabWidget *tabs)
{
auto callback = [tabs]() {
const bool isRunning = switcher && switcher->th &&
switcher->th->isRunning();
auto idx = getGeneralTabIdx(tabs);
tabs->setTabIcon(
idx,
isRunning ? QIcon()
: QIcon::fromTheme(
"obs",
QIcon(":/res/images/warning.svg")));
};
auto inactiveTimer = new QTimer(tabs);
inactiveTimer->setInterval(1000);
QObject::connect(inactiveTimer, &QTimer::timeout, callback);
inactiveTimer->start();
}
void AdvSceneSwitcher::SetupGeneralTab()
{
PopulateSceneSelection(ui->noMatchSwitchScene, false);
if (switcher->switchIfNotMatching == NoMatchBehavior::SWITCH) {
ui->noMatchSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(true);
} else if (switcher->switchIfNotMatching ==
NoMatchBehavior::NO_SWITCH) {
ui->noMatchDontSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
} else {
ui->noMatchRandomSwitch->setChecked(true);
ui->noMatchSwitchScene->setEnabled(false);
}
ui->noMatchSwitchScene->setCurrentText(
GetWeakSourceName(switcher->nonMatchingScene).c_str());
DurationSelection *noMatchDelay = new DurationSelection();
noMatchDelay->SetDuration(switcher->noMatchDelay);
noMatchDelay->setToolTip(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.onNoMetDelayTooltip"));
ui->noMatchLayout->addWidget(noMatchDelay);
QWidget::connect(noMatchDelay,
SIGNAL(DurationChanged(const Duration &)), this,
SLOT(NoMatchDelayDurationChanged(const Duration &)));
ui->checkInterval->setValue(switcher->interval);
DurationSelection *cooldownTime = new DurationSelection();
cooldownTime->SetDuration(switcher->cooldown);
cooldownTime->setToolTip(obs_module_text(
"AdvSceneSwitcher.generalTab.generalBehavior.cooldownHint"));
ui->cooldownLayout->addWidget(cooldownTime);
ui->cooldownLayout->addStretch();
QWidget::connect(cooldownTime,
SIGNAL(DurationChanged(const Duration &)), this,
SLOT(CooldownDurationChanged(const Duration &)));
ui->verboseLogging->setChecked(switcher->verbose);
ui->saveWindowGeo->setChecked(switcher->saveWindowGeo);
ui->showTrayNotifications->setChecked(
switcher->showSystemTrayNotifications);
ui->uiHintsDisable->setChecked(switcher->disableHints);
ui->disableComboBoxFilter->setChecked(
switcher->disableFilterComboboxFilter);
FilterComboBox::SetFilterBehaviourEnabled(
!switcher->disableFilterComboboxFilter);
ui->warnPluginLoadFailure->setChecked(switcher->warnPluginLoadFailure);
ui->hideLegacyTabs->setChecked(switcher->hideLegacyTabs);
populatePriorityFunctionList(ui->priorityList);
populateThreadPriorityList(ui->threadPriority);
populateStartupBehavior(ui->startupBehavior);
ui->startupBehavior->setCurrentIndex(
static_cast<int>(switcher->startupBehavior));
populateAutoStartEventSelection(ui->autoStartEvent);
ui->autoStartEvent->setCurrentIndex(
static_cast<int>(switcher->autoStartEvent));
// Set up status control
auto statusControl = new StatusControl(this, true);
ui->statusLayout->addWidget(statusControl->StatusPrefixLabel(), 1, 0);
auto tmp = new QHBoxLayout;
tmp->addWidget(statusControl->StatusLabel());
tmp->addStretch();
ui->statusLayout->addLayout(tmp, 1, 1);
ui->statusLayout->addWidget(statusControl->Button(), 2, 1);
// Hide the now empty invisible shell of the statusControl widget
// as otherwise it could block user input
statusControl->hide();
setupGeneralTabInactiveWarning(ui->tabWidget);
MinimizeSizeOfColumn(ui->statusLayout, 0);
setWindowTitle(windowTitle() + " - " + g_GIT_TAG);
}
} // namespace advss