SceneSwitcher/plugins/scripting/macro-segment-script-inline.cpp
WarmUpTill ea4a951554
Some checks failed
debian-build / build (push) Has been cancelled
Check locale / ubuntu64 (push) Has been cancelled
Push to master / Check Formatting 🔍 (push) Has been cancelled
Push to master / Build Project 🧱 (push) Has been cancelled
Push to master / Create Release 🛫 (push) Has been cancelled
Add warning if inline script file is invalid
2025-09-23 22:59:42 +02:00

262 lines
7.0 KiB
C++

#include "macro-segment-script-inline.hpp"
#include "layout-helpers.hpp"
#include "obs-module-helper.hpp"
#include "sync-helpers.hpp"
#include "ui-helpers.hpp"
#include <QDesktopServices>
#include <QFile>
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<MacroSegmentScriptInline> 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<InlineScript::Type>(
_scriptType->itemData(idx).toInt()));
SetWidgetVisibility();
}
void MacroSegmentScriptInlineEdit::LanguageChanged(int idx)
{
{
GUARD_LOADING_AND_LOCK();
_entryData->SetLanguage(static_cast<obs_script_lang>(
_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