#include "macro-segment-script-inline.hpp" #include "layout-helpers.hpp" #include "obs-module-helper.hpp" #include "sync-helpers.hpp" #include "ui-helpers.hpp" #include #include namespace advss { void MacroSegmentScriptInline::SetType(InlineScript::Type type) { _script.SetType(type); } void MacroSegmentScriptInline::SetLanguage(obs_script_lang language) { _script.SetLanguage(language); } void MacroSegmentScriptInline::SetScript(const std::string &text) { _script.SetText(text); } void MacroSegmentScriptInline::SetPath(const std::string &path) { _script.SetPath(path); } static void populateLanguageSelection(QComboBox *list) { list->addItem( obs_module_text("AdvSceneSwitcher.script.language.python"), OBS_SCRIPT_LANG_PYTHON); list->addItem(obs_module_text("AdvSceneSwitcher.script.language.lua"), OBS_SCRIPT_LANG_LUA); list->setPlaceholderText( obs_module_text("AdvSceneSwitcher.script.language.select")); } static void populateScriptTypeSelection(QComboBox *list) { list->addItem(obs_module_text("AdvSceneSwitcher.script.type.inline"), InlineScript::INLINE); list->addItem(obs_module_text("AdvSceneSwitcher.script.type.file"), InlineScript::FILE); } MacroSegmentScriptInlineEdit::MacroSegmentScriptInlineEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _scriptType(new QComboBox(this)), _language(new QComboBox(this)), _script(new ScriptEditor(this)), _path(new FileSelection(FileSelection::Type::WRITE, this)), _openFile(new QPushButton( obs_module_text("AdvSceneSwitcher.script.file.open"), this)), _fileLayout(new QHBoxLayout()), _contentIssueWarning(new QLabel(this)), _entryData(entryData) { SetupLayout(); SetupWidgetConnections(); PopulateWidgets(); SetWidgetVisibility(); _loading = false; } void MacroSegmentScriptInlineEdit::ScriptTypeChanged(int idx) { GUARD_LOADING_AND_LOCK(); _entryData->SetType(static_cast( _scriptType->itemData(idx).toInt())); SetWidgetVisibility(); } void MacroSegmentScriptInlineEdit::LanguageChanged(int idx) { { GUARD_LOADING_AND_LOCK(); _entryData->SetLanguage(static_cast( _language->itemData(idx).toInt())); const QSignalBlocker b(_script); _script->setPlainText(_entryData->GetScript()); } if (_entryData->GetType() == InlineScript::Type::FILE) { PathChanged(QString::fromStdString(_entryData->GetPath())); } } void MacroSegmentScriptInlineEdit::ScriptChanged() { GUARD_LOADING_AND_LOCK(); _entryData->SetScript(_script->toPlainText().toStdString()); adjustSize(); updateGeometry(); } void MacroSegmentScriptInlineEdit::PathChanged(const QString &path) { GUARD_LOADING_AND_LOCK(); if (path.isEmpty()) { _entryData->SetPath(path.toStdString()); return; } // Script language will be detected by OBS based on file extension so // adjust it if necessary QString pathAdjusted = path; if (_entryData->GetLanguage() == OBS_SCRIPT_LANG_PYTHON && !path.endsWith(".py")) { if (path.endsWith(".lua")) { pathAdjusted.chop(4); } pathAdjusted += ".py"; } if (_entryData->GetLanguage() == OBS_SCRIPT_LANG_LUA && !path.endsWith(".lua")) { if (path.endsWith(".py")) { pathAdjusted.chop(3); } pathAdjusted += ".lua"; } const QSignalBlocker b(_path); _path->SetPath(pathAdjusted); _entryData->SetPath(pathAdjusted.toStdString()); SetupContentIssueWarning(); } void MacroSegmentScriptInlineEdit::PopulateWidgets() { populateLanguageSelection(_language); populateScriptTypeSelection(_scriptType); if (!_entryData) { return; } _scriptType->setCurrentIndex( _scriptType->findData(_entryData->GetType())); _language->setCurrentIndex( _language->findData(_entryData->GetLanguage())); _script->setPlainText(_entryData->GetScript()); _path->SetPath(_entryData->GetPath()); } void MacroSegmentScriptInlineEdit::SetupWidgetConnections() { QWidget::connect(_scriptType, SIGNAL(currentIndexChanged(int)), this, SLOT(ScriptTypeChanged(int))); QWidget::connect(_language, SIGNAL(currentIndexChanged(int)), this, SLOT(LanguageChanged(int))); QWidget::connect(_script, SIGNAL(ScriptChanged()), this, SLOT(ScriptChanged())); QWidget::connect(_path, SIGNAL(PathChanged(const QString &)), this, SLOT(PathChanged(const QString &))); QWidget::connect(_openFile, &QPushButton::clicked, this, [this] { QUrl fileUrl = QUrl::fromLocalFile( QString::fromStdString(_entryData->GetPath())); if (!QDesktopServices::openUrl(fileUrl)) { DisplayMessage(obs_module_text( "AdvSceneSwitcher.script.file.open.failed")); } }); } void MacroSegmentScriptInlineEdit::SetupLayout() { auto languageLayout = new QHBoxLayout(); PlaceWidgets(obs_module_text("AdvSceneSwitcher.script.language.layout"), languageLayout, {{"{{language}}", _language}}); auto typeLayout = new QHBoxLayout(); PlaceWidgets(obs_module_text("AdvSceneSwitcher.script.type.layout"), typeLayout, {{"{{scriptType}}", _scriptType}}); PlaceWidgets(obs_module_text("AdvSceneSwitcher.script.file.layout"), _fileLayout, {{"{{path}}", _path}, {"{{open}}", _openFile}}, false); auto layout = new QVBoxLayout(); layout->addLayout(typeLayout); layout->addLayout(languageLayout); layout->addLayout(_fileLayout); layout->addWidget(_script); layout->addWidget(_contentIssueWarning); setLayout(layout); } void MacroSegmentScriptInlineEdit::SetWidgetVisibility() { _script->setVisible(_entryData->GetType() == InlineScript::Type::INLINE); SetLayoutVisible(_fileLayout, _entryData->GetType() == InlineScript::Type::FILE); SetupContentIssueWarning(); adjustSize(); updateGeometry(); } void MacroSegmentScriptInlineEdit::SetupContentIssueWarning() const { if (_entryData->GetType() == InlineScript::Type::INLINE) { _contentIssueWarning->hide(); return; } const auto path = QString::fromStdString(_entryData->GetPath()); QFile file(path); if (!file.exists()) { _contentIssueWarning->setText(obs_module_text( "AdvSceneSwitcher.script.file.warning.notFound")); _contentIssueWarning->show(); return; } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { _contentIssueWarning->setText(obs_module_text( "AdvSceneSwitcher.script.file.warning.openFail")); _contentIssueWarning->show(); return; } QTextStream in(&file); QStringList fileLines; while (!in.atEnd()) { QString line = in.readLine().trimmed(); fileLines << line.trimmed(); } file.close(); static const QStringList requiredLinesLUA = { "function script_load(settings)"}; static const QStringList requiredLinesPython = { "def script_load(settings):"}; const auto &requiredLines = _entryData->GetLanguage() == OBS_SCRIPT_LANG_PYTHON ? requiredLinesPython : requiredLinesLUA; for (const QString &required : requiredLines) { if (fileLines.contains(required)) { _contentIssueWarning->hide(); return; } } _contentIssueWarning->setText(obs_module_text( "AdvSceneSwitcher.script.file.warning.loadMissing")); _contentIssueWarning->show(); } } // namespace advss