#include "macro-action-source-interaction.hpp" #include "source-interaction-recorder.hpp" #include "layout-helpers.hpp" #include "selection-helpers.hpp" #include "sync-helpers.hpp" #include "log-helper.hpp" #include #include #include #include #include namespace advss { const std::string MacroActionSourceInteraction::id = "source_interaction"; bool MacroActionSourceInteraction::_registered = MacroActionFactory::Register( MacroActionSourceInteraction::id, {MacroActionSourceInteraction::Create, MacroActionSourceInteractionEdit::Create, "AdvSceneSwitcher.action.sourceInteraction"}); bool MacroActionSourceInteraction::PerformAction() { OBSSourceAutoRelease source = obs_weak_source_get_source(_source.GetSource()); if (!source) { blog(LOG_WARNING, "source interaction: source not found"); return true; } uint32_t flags = obs_source_get_output_flags(source); if (!(flags & OBS_SOURCE_INTERACTION)) { blog(LOG_WARNING, "source interaction: source \"%s\" does not support interaction", obs_source_get_name(source)); return true; } for (const auto &step : _steps) { PerformInteractionStep(source, step); } return true; } void MacroActionSourceInteraction::LogAction() const { ablog(LOG_INFO, "performed source interaction on \"%s\" (%d steps)", _source.ToString(true).c_str(), (int)_steps.size()); } bool MacroActionSourceInteraction::Save(obs_data_t *obj) const { MacroAction::Save(obj); _source.Save(obj); OBSDataArrayAutoRelease arr = obs_data_array_create(); for (const auto &step : _steps) { OBSDataAutoRelease stepObj = obs_data_create(); step.Save(stepObj); obs_data_array_push_back(arr, stepObj); } obs_data_set_array(obj, "steps", arr); return true; } bool MacroActionSourceInteraction::Load(obs_data_t *obj) { MacroAction::Load(obj); _source.Load(obj); _steps.clear(); OBSDataArrayAutoRelease arr = obs_data_get_array(obj, "steps"); size_t count = obs_data_array_count(arr); for (size_t i = 0; i < count; i++) { OBSDataAutoRelease stepObj = obs_data_array_item(arr, i); SourceInteractionStep step; step.Load(stepObj); _steps.push_back(step); } return true; } std::string MacroActionSourceInteraction::GetShortDesc() const { return _source.ToString(); } void MacroActionSourceInteraction::ResolveVariablesToFixedValues() { for (auto &step : _steps) { step.x.ResolveVariables(); step.y.ResolveVariables(); step.clickCount.ResolveVariables(); step.wheelDeltaX.ResolveVariables(); step.wheelDeltaY.ResolveVariables(); step.nativeVkey.ResolveVariables(); step.text.ResolveVariables(); step.waitMs.ResolveVariables(); } } std::shared_ptr MacroActionSourceInteraction::Create(Macro *m) { return std::make_shared(m); } std::shared_ptr MacroActionSourceInteraction::Copy() const { return std::make_shared(*this); } static QStringList getInteractableSourceNames() { QStringList names; obs_enum_sources( [](void *param, obs_source_t *source) -> bool { uint32_t flags = obs_source_get_output_flags(source); if (flags & OBS_SOURCE_INTERACTION) { auto list = static_cast(param); const char *name = obs_source_get_name(source); if (name) { list->append(QString(name)); } } return true; }, &names); names.sort(); return names; } MacroActionSourceInteractionEdit::MacroActionSourceInteractionEdit( QWidget *parent, std::shared_ptr entryData) : QWidget(parent), _sources(new SourceSelectionWidget(this, getInteractableSourceNames, true)), _stepList(new SourceInteractionStepList(this)), _recordButton(new QPushButton(obs_module_text( "AdvSceneSwitcher.action.sourceInteraction.record"))), _noSelectionLabel(new QLabel(obs_module_text( "AdvSceneSwitcher.action.sourceInteraction.noSelection"))) { _stepList->AddControlWidget(_recordButton); auto sourceRow = new QHBoxLayout; sourceRow->addWidget(new QLabel(obs_module_text( "AdvSceneSwitcher.action.sourceInteraction.source"))); sourceRow->addWidget(_sources); sourceRow->addStretch(); _noSelectionLabel->setAlignment(Qt::AlignCenter); _noSelectionLabel->hide(); auto mainLayout = new QVBoxLayout(this); mainLayout->addLayout(sourceRow); mainLayout->addWidget(_stepList); mainLayout->addWidget(_noSelectionLabel); setLayout(mainLayout); connect(_sources, SIGNAL(SourceChanged(const SourceSelection &)), this, SLOT(SourceChanged(const SourceSelection &))); connect(_stepList, &SourceInteractionStepList::StepsChanged, this, &MacroActionSourceInteractionEdit::OnStepsChanged); connect(_stepList, &SourceInteractionStepList::RowSelected, this, &MacroActionSourceInteractionEdit::SetCurrentStepEditor); connect(_recordButton, &QPushButton::clicked, this, &MacroActionSourceInteractionEdit::OpenRecorder); _entryData = entryData; UpdateEntryData(); _loading = false; } void MacroActionSourceInteractionEdit::UpdateEntryData() { if (!_entryData) { return; } _sources->SetSource(_entryData->_source); _stepList->SetSteps(_entryData->_steps); _noSelectionLabel->setVisible(_stepList->count() > 0); } void MacroActionSourceInteractionEdit::SourceChanged( const SourceSelection &source) { GUARD_LOADING_AND_LOCK(); _entryData->_source = source; emit HeaderInfoChanged( QString::fromStdString(_entryData->GetShortDesc())); } void MacroActionSourceInteractionEdit::OnStepsChanged( const std::vector &steps) { GUARD_LOADING_AND_LOCK(); _entryData->_steps = steps; } void MacroActionSourceInteractionEdit::StepChanged( const SourceInteractionStep &step) { GUARD_LOADING_AND_LOCK(); int row = _stepList->CurrentRow(); if (row < 0 || row >= (int)_entryData->_steps.size()) { return; } _entryData->_steps[row] = step; _stepList->UpdateStep(row, step); } void MacroActionSourceInteractionEdit::OpenRecorder() { if (!_entryData) { return; } OBSSourceAutoRelease source = obs_weak_source_get_source(_entryData->_source.GetSource()); if (!source) { QMessageBox::warning( this, obs_module_text( "AdvSceneSwitcher.action.sourceInteraction.record.title"), obs_module_text( "AdvSceneSwitcher.action.sourceInteraction.record.invalidSource")); return; } auto dlg = new SourceInteractionRecorder( window(), _entryData->_source.GetSource()); connect(dlg, &SourceInteractionRecorder::StepsRecorded, this, &MacroActionSourceInteractionEdit::AcceptRecorded); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->show(); } void MacroActionSourceInteractionEdit::AcceptRecorded( const std::vector &steps) { if (!_entryData) { return; } { auto lock = _entryData->Lock(); _entryData->_steps.insert(_entryData->_steps.end(), steps.begin(), steps.end()); } _stepList->SetSteps(_entryData->_steps); } void MacroActionSourceInteractionEdit::SetCurrentStepEditor(int row) { if (_stepEditor) { delete _stepEditor; _stepEditor = nullptr; } if (!_entryData || row < 0 || row >= (int)_entryData->_steps.size()) { _noSelectionLabel->setVisible(_stepList->count() > 0); return; } _noSelectionLabel->setVisible(false); _stepEditor = new SourceInteractionStepEdit(this, _entryData->_steps[row]); static_cast(layout())->addWidget(_stepEditor); connect(_stepEditor, &SourceInteractionStepEdit::StepChanged, this, &MacroActionSourceInteractionEdit::StepChanged); adjustSize(); updateGeometry(); } } // namespace advss