#include "headers/advanced-scene-switcher.hpp" #include "headers/macro-condition-edit.hpp" #include "headers/macro-condition-scene.hpp" #include "headers/section.hpp" #include "headers/utility.hpp" std::map MacroConditionFactory::_methods; bool MacroConditionFactory::Register(const std::string &id, MacroConditionInfo info) { if (auto it = _methods.find(id); it == _methods.end()) { _methods[id] = info; return true; } return false; } std::shared_ptr MacroConditionFactory::Create(const std::string &id, Macro *m) { if (auto it = _methods.find(id); it != _methods.end()) { return it->second._createFunc(m); } return nullptr; } QWidget * MacroConditionFactory::CreateWidget(const std::string &id, QWidget *parent, std::shared_ptr cond) { if (auto it = _methods.find(id); it != _methods.end()) { return it->second._createWidgetFunc(parent, cond); } return nullptr; } std::string MacroConditionFactory::GetConditionName(const std::string &id) { if (auto it = _methods.find(id); it != _methods.end()) { return it->second._name; } return "unknown condition"; } std::string MacroConditionFactory::GetIdByName(const QString &name) { for (auto it : _methods) { if (name == obs_module_text(it.second._name.c_str())) { return it.first; } } return ""; } bool MacroConditionFactory::UsesDurationConstraint(const std::string &id) { if (auto it = _methods.find(id); it != _methods.end()) { return it->second._useDurationConstraint; } return false; } static inline void populateLogicSelection(QComboBox *list, bool root = false) { if (root) { for (auto entry : MacroCondition::logicTypes) { if (static_cast(entry.first) < logic_root_offset) { list->addItem(obs_module_text( entry.second._name.c_str())); } } } else { for (auto entry : MacroCondition::logicTypes) { if (static_cast(entry.first) >= logic_root_offset) { list->addItem(obs_module_text( entry.second._name.c_str())); } } } } static inline void populateConditionSelection(QComboBox *list) { for (auto entry : MacroConditionFactory::GetConditionTypes()) { list->addItem(obs_module_text(entry.second._name.c_str())); } list->model()->sort(0); } MacroConditionEdit::MacroConditionEdit( QWidget *parent, std::shared_ptr *entryData, const std::string &id, bool root) : MacroSegmentEdit(switcher->macroProperties._highlightConditions, parent), _entryData(entryData), _isRoot(root) { _logicSelection = new QComboBox(); _conditionSelection = new QComboBox(); _dur = new DurationConstraintEdit(); QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)), this, SLOT(LogicSelectionChanged(int))); QWidget::connect(_conditionSelection, SIGNAL(currentTextChanged(const QString &)), this, SLOT(ConditionSelectionChanged(const QString &))); QWidget::connect(_dur, SIGNAL(DurationChanged(double)), this, SLOT(DurationChanged(double))); QWidget::connect(_dur, SIGNAL(UnitChanged(DurationUnit)), this, SLOT(DurationUnitChanged(DurationUnit))); QWidget::connect(_dur, SIGNAL(ConditionChanged(DurationCondition)), this, SLOT(DurationConditionChanged(DurationCondition))); QWidget::connect(window(), SIGNAL(HighlightConditionsChanged(bool)), this, SLOT(EnableHighlight(bool))); populateLogicSelection(_logicSelection, root); populateConditionSelection(_conditionSelection); _section->AddHeaderWidget(_logicSelection); _section->AddHeaderWidget(_conditionSelection); _section->AddHeaderWidget(_headerInfo); _section->AddHeaderWidget(_dur); QVBoxLayout *conditionLayout = new QVBoxLayout; conditionLayout->setContentsMargins({7, 7, 7, 7}); conditionLayout->addWidget(_section); _contentLayout->addLayout(conditionLayout); QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); mainLayout->addWidget(_frame); setLayout(mainLayout); UpdateEntryData(id); _loading = false; } void MacroConditionEdit::LogicSelectionChanged(int idx) { if (_loading || !_entryData) { return; } LogicType type; if (IsRootNode()) { type = static_cast(idx); } else { type = static_cast(idx + logic_root_offset); } std::lock_guard lock(switcher->m); (*_entryData)->SetLogicType(type); } bool MacroConditionEdit::IsRootNode() { return _isRoot; } void MacroConditionEdit::SetLogicSelection() { auto logic = (*_entryData)->GetLogicType(); if (IsRootNode()) { _logicSelection->setCurrentIndex(static_cast(logic)); } else { _logicSelection->setCurrentIndex(static_cast(logic) - logic_root_offset); } } void MacroConditionEdit::SetRootNode(bool root) { _isRoot = root; const QSignalBlocker blocker(_logicSelection); _logicSelection->clear(); populateLogicSelection(_logicSelection, root); SetLogicSelection(); } void MacroConditionEdit::UpdateEntryData(const std::string &id) { _conditionSelection->setCurrentText(obs_module_text( MacroConditionFactory::GetConditionName(id).c_str())); auto widget = MacroConditionFactory::CreateWidget(id, this, *_entryData); QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), this, SLOT(HeaderInfoChanged(const QString &))); HeaderInfoChanged( QString::fromStdString((*_entryData)->GetShortDesc())); SetLogicSelection(); _section->SetContent(widget, (*_entryData)->GetCollapsed()); _dur->setVisible(MacroConditionFactory::UsesDurationConstraint(id)); auto constraint = (*_entryData)->GetDurationConstraint(); _dur->SetValue(constraint); SetFocusPolicyOfWidgets(); } void MacroConditionEdit::SetEntryData(std::shared_ptr *data) { _entryData = data; } void MacroConditionEdit::ConditionSelectionChanged(const QString &text) { if (_loading || !_entryData) { return; } auto idx = _entryData->get()->GetIndex(); auto macro = _entryData->get()->GetMacro(); std::string id = MacroConditionFactory::GetIdByName(text); auto temp = DurationConstraint(); _dur->SetValue(temp); HeaderInfoChanged(""); std::lock_guard lock(switcher->m); auto logic = (*_entryData)->GetLogicType(); _entryData->reset(); *_entryData = MacroConditionFactory::Create(id, macro); (*_entryData)->SetIndex(idx); (*_entryData)->SetLogicType(logic); auto widget = MacroConditionFactory::CreateWidget(id, this, *_entryData); QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)), this, SLOT(HeaderInfoChanged(const QString &))); _section->SetContent(widget); _dur->setVisible(MacroConditionFactory::UsesDurationConstraint(id)); SetFocusPolicyOfWidgets(); } void MacroConditionEdit::DurationChanged(double seconds) { if (_loading || !_entryData) { return; } std::lock_guard lock(switcher->m); (*_entryData)->SetDuration(seconds); } void MacroConditionEdit::DurationConditionChanged(DurationCondition cond) { if (_loading || !_entryData) { return; } std::lock_guard lock(switcher->m); (*_entryData)->SetDurationCondition(cond); } void MacroConditionEdit::DurationUnitChanged(DurationUnit unit) { if (_loading || !_entryData) { return; } std::lock_guard lock(switcher->m); (*_entryData)->SetDurationUnit(unit); } MacroSegment *MacroConditionEdit::Data() { return _entryData->get(); } void AdvSceneSwitcher::AddMacroCondition(int idx) { auto macro = getSelectedMacro(); if (!macro) { return; } if (idx < 0 || idx > (int)macro->Conditions().size()) { return; } std::string id; LogicType logic; if (idx >= 1) { id = macro->Conditions().at(idx - 1)->GetId(); if (idx == 1) { logic = LogicType::NONE; } else { logic = macro->Conditions().at(idx - 1)->GetLogicType(); } } else { MacroConditionScene temp(macro); id = temp.GetId(); logic = LogicType::ROOT_NONE; } { std::lock_guard lock(switcher->m); auto cond = macro->Conditions().emplace( macro->Conditions().begin() + idx, MacroConditionFactory::Create(id, macro)); if (idx - 1 >= 0) { auto data = obs_data_create(); macro->Conditions().at(idx - 1)->Save(data); macro->Conditions().at(idx)->Load(data); obs_data_release(data); } (*cond)->SetLogicType(logic); macro->UpdateConditionIndices(); conditionsList->Insert( idx, new MacroConditionEdit(this, ¯o->Conditions()[idx], id, idx == 0)); SetConditionData(*macro); } HighlightCondition(idx); } void AdvSceneSwitcher::on_conditionAdd_clicked() { auto macro = getSelectedMacro(); if (!macro) { return; } if (currentConditionIdx == -1) { auto macro = getSelectedMacro(); if (!macro) { return; } AddMacroCondition((int)macro->Conditions().size()); } else { AddMacroCondition(currentConditionIdx + 1); } if (currentConditionIdx != -1) { MacroConditionSelectionChanged(currentConditionIdx + 1); } conditionsList->SetHelpMsgVisible(false); } void AdvSceneSwitcher::RemoveMacroCondition(int idx) { auto macro = getSelectedMacro(); if (!macro) { return; } if (idx < 0 || idx >= (int)macro->Conditions().size()) { return; } { std::lock_guard lock(switcher->m); macro->Conditions().erase(macro->Conditions().begin() + idx); macro->UpdateConditionIndices(); if (idx == 0 && macro->Conditions().size() > 0) { auto newRoot = macro->Conditions().at(0); newRoot->SetLogicType(LogicType::ROOT_NONE); } conditionsList->Remove(idx); SetConditionData(*macro); } MacroConditionSelectionChanged(-1); } void AdvSceneSwitcher::on_conditionRemove_clicked() { if (currentConditionIdx == -1) { auto macro = getSelectedMacro(); if (!macro) { return; } RemoveMacroCondition((int)macro->Conditions().size() - 1); } else { RemoveMacroCondition(currentConditionIdx); } MacroConditionSelectionChanged(-1); } void AdvSceneSwitcher::on_conditionUp_clicked() { if (currentConditionIdx == -1) { return; } MoveMacroConditionUp(currentConditionIdx); MacroConditionSelectionChanged(currentConditionIdx - 1); } void AdvSceneSwitcher::on_conditionDown_clicked() { if (currentConditionIdx == -1) { return; } MoveMacroConditionDown(currentConditionIdx); MacroConditionSelectionChanged(currentConditionIdx + 1); } void AdvSceneSwitcher::SwapConditions(Macro *m, int pos1, int pos2) { if (pos1 == pos2) { return; } if (pos1 > pos2) { std::swap(pos1, pos2); } bool root = pos1 == 0; std::lock_guard lock(switcher->m); iter_swap(m->Conditions().begin() + pos1, m->Conditions().begin() + pos2); m->UpdateConditionIndices(); auto c1 = m->Conditions().begin() + pos1; auto c2 = m->Conditions().begin() + pos2; if (root) { auto logic1 = (*c1)->GetLogicType(); auto logic2 = (*c2)->GetLogicType(); (*c1)->SetLogicType(logic2); (*c2)->SetLogicType(logic1); } auto widget1 = static_cast( conditionsList->ContentLayout()->takeAt(pos1)->widget()); auto widget2 = static_cast( conditionsList->ContentLayout()->takeAt(pos2 - 1)->widget()); conditionsList->Insert(pos1, widget2); conditionsList->Insert(pos2, widget1); SetConditionData(*m); widget2->SetRootNode(root); widget1->SetRootNode(false); } void AdvSceneSwitcher::MoveMacroConditionUp(int idx) { auto macro = getSelectedMacro(); if (!macro) { return; } if (idx < 1 || idx >= (int)macro->Conditions().size()) { return; } SwapConditions(macro, idx, idx - 1); HighlightCondition(idx - 1); } void AdvSceneSwitcher::MoveMacroConditionDown(int idx) { auto macro = getSelectedMacro(); if (!macro) { return; } if (idx < 0 || idx >= (int)macro->Conditions().size() - 1) { return; } SwapConditions(macro, idx, idx + 1); HighlightCondition(idx + 1); } void AdvSceneSwitcher::MacroConditionSelectionChanged(int idx) { auto macro = getSelectedMacro(); if (!macro) { return; } conditionsList->SetSelection(idx); actionsList->SetSelection(-1); if (idx < 0 || (unsigned)idx >= macro->Conditions().size()) { currentConditionIdx = -1; } else { currentConditionIdx = idx; } currentActionIdx = -1; HighlightControls(); } void AdvSceneSwitcher::MacroConditionReorder(int to, int from) { auto macro = getSelectedMacro(); if (!macro) { return; } if (from < 0 || from > (int)macro->Conditions().size() || to < 0 || to > (int)macro->Conditions().size()) { return; } { std::lock_guard lock(switcher->m); auto condition = macro->Conditions().at(from); if (to == 0) { condition->SetLogicType(LogicType::ROOT_NONE); static_cast( conditionsList->WidgetAt(from)) ->SetRootNode(true); macro->Conditions().at(0)->SetLogicType(LogicType::AND); static_cast( conditionsList->WidgetAt(0)) ->SetRootNode(false); } if (from == 0) { condition->SetLogicType(LogicType::AND); static_cast( conditionsList->WidgetAt(from)) ->SetRootNode(false); macro->Conditions().at(1)->SetLogicType( LogicType::ROOT_NONE); static_cast( conditionsList->WidgetAt(1)) ->SetRootNode(true); } macro->Conditions().erase(macro->Conditions().begin() + from); macro->Conditions().insert(macro->Conditions().begin() + to, condition); macro->UpdateConditionIndices(); conditionsList->ContentLayout()->insertItem( to, conditionsList->ContentLayout()->takeAt(from)); SetConditionData(*macro); } HighlightCondition(to); }