diff --git a/data/locale/en-US.ini b/data/locale/en-US.ini index 3353cc37..8b730b92 100644 --- a/data/locale/en-US.ini +++ b/data/locale/en-US.ini @@ -71,6 +71,7 @@ AdvSceneSwitcher.macroTab.priorityWarning="Note: It is recommended to configure AdvSceneSwitcher.macroTab.help="Macros allow you to execute a string of actions depending on multiple conditions.\n\nClick on the highlighted plus symbol to add a new Macro." AdvSceneSwitcher.macroTab.editConditionHelp="This section allows you to define Macro conditions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new condition." AdvSceneSwitcher.macroTab.editActionHelp="This section allows you to define Macro actions.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new action." +AdvSceneSwitcher.macroTab.editElseActionHelp="This section allows you to define Macro actions, which are executed if the conditions are *not* met.\n\nSelect an existing or add a new Macro on the left.\nThen click the plus button below to add a new action." AdvSceneSwitcher.macroTab.edit="Edit macro" AdvSceneSwitcher.macroTab.edit.logic="Logic type:" AdvSceneSwitcher.macroTab.edit.condition="Condition type:" diff --git a/src/advanced-scene-switcher.hpp b/src/advanced-scene-switcher.hpp index 97087fd4..967fb9ef 100644 --- a/src/advanced-scene-switcher.hpp +++ b/src/advanced-scene-switcher.hpp @@ -84,10 +84,13 @@ public: void SetEditMacro(Macro &m); void SetMacroEditAreaDisabled(bool); void HighlightAction(int idx, QColor color = QColor(Qt::green)); + void HighlightElseAction(int idx, QColor color = QColor(Qt::green)); void HighlightCondition(int idx, QColor color = QColor(Qt::green)); void PopulateMacroActions(Macro &m, uint32_t afterIdx = 0); + void PopulateMacroElseActions(Macro &m, uint32_t afterIdx = 0); void PopulateMacroConditions(Macro &m, uint32_t afterIdx = 0); void SetActionData(Macro &m); + void SetElseActionData(Macro &m); void SetConditionData(Macro &m); void SwapActions(Macro *m, int pos1, int pos2); void SwapConditions(Macro *m, int pos1, int pos2); @@ -113,29 +116,50 @@ public slots: void on_actionUp_clicked(); void on_actionDown_clicked(); void on_actionBottom_clicked(); + void on_elseActionAdd_clicked(); + void on_elseActionRemove_clicked(); + void on_elseActionTop_clicked(); + void on_elseActionUp_clicked(); + void on_elseActionDown_clicked(); + void on_elseActionBottom_clicked(); + void MacroSelectionAboutToChange(); void MacroSelectionChanged(); void UpMacroSegementHotkey(); void DownMacroSegementHotkey(); void DeleteMacroSegementHotkey(); void ShowMacroContextMenu(const QPoint &); void ShowMacroActionsContextMenu(const QPoint &); + void ShowMacroElseActionsContextMenu(const QPoint &); void ShowMacroConditionsContextMenu(const QPoint &); void CopyMacro(); void RenameCurrentMacro(); void ExportMacros(); void ImportMacros(); void ExpandAllActions(); + void ExpandAllElseActions(); void ExpandAllConditions(); void CollapseAllActions(); + void CollapseAllElseActions(); void CollapseAllConditions(); void MinimizeActions(); + void MaximizeActions(); + void MinimizeElseActions(); + void MaximizeElseActions(); void MinimizeConditions(); + void MaximizeConditions(); void MacroActionSelectionChanged(int idx); void MacroActionReorder(int to, int target); void AddMacroAction(int idx); void RemoveMacroAction(int idx); void MoveMacroActionUp(int idx); void MoveMacroActionDown(int idx); + void MacroElseActionSelectionChanged(int idx); + void MacroElseActionReorder(int to, int target); + void AddMacroElseAction(int idx); + void RemoveMacroElseAction(int idx); + void SwapElseActions(Macro *m, int pos1, int pos2); + void MoveMacroElseActionUp(int idx); + void MoveMacroElseActionDown(int idx); void MacroConditionSelectionChanged(int idx); void MacroConditionReorder(int to, int target); void AddMacroCondition(int idx); @@ -157,6 +181,7 @@ signals: void MacroSegmentOrderChanged(); void HighlightMacrosChanged(bool value); void HighlightActionsChanged(bool value); + void HighlightElseActionsChanged(bool value); void HighlightConditionsChanged(bool value); void ConnectionAdded(const QString &); @@ -167,16 +192,16 @@ signals: void VariableRemoved(const QString &); private: + enum class MacroSection { CONDITIONS, ACTIONS, ELSE_ACTIONS }; + + void SetupMacroSegmentSelection(MacroSection type, int idx); bool ResolveMacroImportNameConflict(std::shared_ptr &); bool MacroTabIsInFocus(); - enum class MacroSection { - CONDITIONS, - ACTIONS, - }; MacroSection lastInteracted = MacroSection::CONDITIONS; int currentConditionIdx = -1; int currentActionIdx = -1; + int currentElseActionIdx = -1; /* --- End of macro tab section --- */ diff --git a/src/general.cpp b/src/general.cpp index fdfee314..e83f6653 100644 --- a/src/general.cpp +++ b/src/general.cpp @@ -132,10 +132,9 @@ void AdvSceneSwitcher::closeEvent(QCloseEvent *) } switcher->windowPos = this->pos(); switcher->windowSize = this->size(); - switcher->macroActionConditionSplitterPosition = - ui->macroActionConditionSplitter->sizes(); switcher->macroListMacroEditSplitterPosition = ui->macroListMacroEditSplitter->sizes(); + MacroSelectionAboutToChange(); // Trigger saving of splitter states obs_frontend_save(); } @@ -703,9 +702,7 @@ void SwitcherData::SaveUISettings(obs_data_t *obj) obs_data_set_int(obj, "windowWidth", windowSize.width()); obs_data_set_int(obj, "windowHeight", windowSize.height()); - saveSplitterPos(macroActionConditionSplitterPosition, obj, - "macroActionConditionSplitterPosition"); - saveSplitterPos(macroListMacroEditSplitterPosition, obj, + SaveSplitterPos(macroListMacroEditSplitterPosition, obj, "macroListMacroEditSplitterPosition"); } @@ -759,9 +756,8 @@ void SwitcherData::LoadUISettings(obs_data_t *obj) (int)obs_data_get_int(obj, "windowPosY")}; windowSize = {(int)obs_data_get_int(obj, "windowWidth"), (int)obs_data_get_int(obj, "windowHeight")}; - loadSplitterPos(macroActionConditionSplitterPosition, obj, - "macroActionConditionSplitterPosition"); - loadSplitterPos(macroListMacroEditSplitterPosition, obj, + + LoadSplitterPos(macroListMacroEditSplitterPosition, obj, "macroListMacroEditSplitterPosition"); } diff --git a/src/macro-core/macro-action-edit.cpp b/src/macro-core/macro-action-edit.cpp index 909cea7e..82cdb1be 100644 --- a/src/macro-core/macro-action-edit.cpp +++ b/src/macro-core/macro-action-edit.cpp @@ -322,6 +322,7 @@ void AdvSceneSwitcher::on_actionUp_clicked() MoveMacroActionUp(currentActionIdx); MacroActionSelectionChanged(currentActionIdx - 1); } + void AdvSceneSwitcher::on_actionDown_clicked() { if (currentActionIdx == -1 || @@ -342,6 +343,77 @@ void AdvSceneSwitcher::on_actionBottom_clicked() MacroActionSelectionChanged(newIdx); } +void AdvSceneSwitcher::on_elseActionAdd_clicked() +{ + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + + if (currentElseActionIdx == -1) { + AddMacroElseAction((int)macro->ElseActions().size()); + } else { + AddMacroElseAction(currentElseActionIdx + 1); + } + if (currentElseActionIdx != -1) { + MacroElseActionSelectionChanged(currentElseActionIdx + 1); + } + ui->elseActionsList->SetHelpMsgVisible(false); +} + +void AdvSceneSwitcher::on_elseActionRemove_clicked() +{ + if (currentElseActionIdx == -1) { + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + RemoveMacroElseAction((int)macro->Actions().size() - 1); + } else { + RemoveMacroElseAction(currentElseActionIdx); + } + MacroElseActionSelectionChanged(-1); +} + +void AdvSceneSwitcher::on_elseActionTop_clicked() +{ + if (currentElseActionIdx == -1) { + return; + } + MacroElseActionReorder(0, currentElseActionIdx); + MacroElseActionSelectionChanged(0); +} + +void AdvSceneSwitcher::on_elseActionUp_clicked() +{ + if (currentElseActionIdx == -1 || currentElseActionIdx == 0) { + return; + } + MoveMacroElseActionUp(currentElseActionIdx); + MacroElseActionSelectionChanged(currentElseActionIdx - 1); +} + +void AdvSceneSwitcher::on_elseActionDown_clicked() +{ + if (currentElseActionIdx == -1 || + currentElseActionIdx == + ui->elseActionsList->ContentLayout()->count() - 1) { + return; + } + MoveMacroElseActionDown(currentElseActionIdx); + MacroElseActionSelectionChanged(currentElseActionIdx + 1); +} + +void AdvSceneSwitcher::on_elseActionBottom_clicked() +{ + if (currentElseActionIdx == -1) { + return; + } + const int newIdx = ui->elseActionsList->ContentLayout()->count() - 1; + MacroElseActionReorder(newIdx, currentElseActionIdx); + MacroElseActionSelectionChanged(newIdx); +} + void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2) { if (pos1 == pos2) { @@ -394,24 +466,158 @@ void AdvSceneSwitcher::MoveMacroActionDown(int idx) HighlightAction(idx + 1); } -void AdvSceneSwitcher::MacroActionSelectionChanged(int idx) +void AdvSceneSwitcher::MacroElseActionSelectionChanged(int idx) +{ + SetupMacroSegmentSelection(MacroSection::ELSE_ACTIONS, idx); +} + +void AdvSceneSwitcher::MacroElseActionReorder(int to, int from) { auto macro = GetSelectedMacro(); if (!macro) { return; } - ui->actionsList->SetSelection(idx); - ui->conditionsList->SetSelection(-1); - - if (idx < 0 || (unsigned)idx >= macro->Actions().size()) { - currentActionIdx = -1; - } else { - currentActionIdx = idx; - lastInteracted = MacroSection::ACTIONS; + if (to == from || from < 0 || from > (int)macro->ElseActions().size() || + to < 0 || to > (int)macro->ElseActions().size()) { + return; } - currentConditionIdx = -1; - HighlightControls(); + { + std::lock_guard lock(switcher->m); + auto action = macro->ElseActions().at(from); + macro->ElseActions().erase(macro->ElseActions().begin() + from); + macro->ElseActions().insert(macro->ElseActions().begin() + to, + action); + macro->UpdateElseActionIndices(); + ui->elseActionsList->ContentLayout()->insertItem( + to, ui->elseActionsList->ContentLayout()->takeAt(from)); + SetElseActionData(*macro); + } + HighlightElseAction(to); + emit(MacroSegmentOrderChanged()); +} + +void AdvSceneSwitcher::AddMacroElseAction(int idx) +{ + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + + if (idx < 0 || idx > (int)macro->ElseActions().size()) { + return; + } + + std::string id; + if (idx - 1 >= 0) { + id = macro->ElseActions().at(idx - 1)->GetId(); + } else { + MacroActionSwitchScene temp(nullptr); + id = temp.GetId(); + } + { + std::lock_guard lock(switcher->m); + macro->ElseActions().emplace( + macro->ElseActions().begin() + idx, + MacroActionFactory::Create(id, macro.get())); + if (idx - 1 >= 0) { + OBSDataAutoRelease data = obs_data_create(); + macro->ElseActions().at(idx - 1)->Save(data); + macro->ElseActions().at(idx)->Load(data); + } + macro->UpdateElseActionIndices(); + ui->elseActionsList->Insert( + idx, new MacroActionEdit( + this, ¯o->ElseActions()[idx], id)); + SetElseActionData(*macro); + } + HighlightElseAction(idx); + emit(MacroSegmentOrderChanged()); +} + +void AdvSceneSwitcher::RemoveMacroElseAction(int idx) +{ + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + + if (idx < 0 || idx >= (int)macro->ElseActions().size()) { + return; + } + + { + std::lock_guard lock(switcher->m); + ui->elseActionsList->Remove(idx); + macro->ElseActions().erase(macro->ElseActions().begin() + idx); + switcher->abortMacroWait = true; + switcher->macroWaitCv.notify_all(); + macro->UpdateElseActionIndices(); + SetActionData(*macro); + } + MacroElseActionSelectionChanged(-1); + lastInteracted = MacroSection::ELSE_ACTIONS; + emit(MacroSegmentOrderChanged()); +} + +void AdvSceneSwitcher::SwapElseActions(Macro *m, int pos1, int pos2) +{ + if (pos1 == pos2) { + return; + } + if (pos1 > pos2) { + std::swap(pos1, pos2); + } + + std::lock_guard lock(switcher->m); + iter_swap(m->ElseActions().begin() + pos1, + m->ElseActions().begin() + pos2); + m->UpdateElseActionIndices(); + auto widget1 = static_cast( + ui->elseActionsList->ContentLayout()->takeAt(pos1)->widget()); + auto widget2 = static_cast( + ui->elseActionsList->ContentLayout() + ->takeAt(pos2 - 1) + ->widget()); + ui->elseActionsList->Insert(pos1, widget2); + ui->elseActionsList->Insert(pos2, widget1); + SetElseActionData(*m); + emit(MacroSegmentOrderChanged()); +} + +void AdvSceneSwitcher::MoveMacroElseActionUp(int idx) +{ + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + + if (idx < 1 || idx >= (int)macro->ElseActions().size()) { + return; + } + + SwapElseActions(macro.get(), idx, idx - 1); + HighlightElseAction(idx - 1); +} + +void AdvSceneSwitcher::MoveMacroElseActionDown(int idx) +{ + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + + if (idx < 0 || idx >= (int)macro->ElseActions().size() - 1) { + return; + } + + SwapElseActions(macro.get(), idx, idx + 1); + HighlightElseAction(idx + 1); +} + +void AdvSceneSwitcher::MacroActionSelectionChanged(int idx) +{ + SetupMacroSegmentSelection(MacroSection::ACTIONS, idx); } void AdvSceneSwitcher::MacroActionReorder(int to, int from) diff --git a/src/macro-core/macro-condition-edit.cpp b/src/macro-core/macro-condition-edit.cpp index 0a325c8d..e1923687 100644 --- a/src/macro-core/macro-condition-edit.cpp +++ b/src/macro-core/macro-condition-edit.cpp @@ -564,22 +564,7 @@ void AdvSceneSwitcher::MoveMacroConditionDown(int idx) void AdvSceneSwitcher::MacroConditionSelectionChanged(int idx) { - auto macro = GetSelectedMacro(); - if (!macro) { - return; - } - - ui->conditionsList->SetSelection(idx); - ui->actionsList->SetSelection(-1); - - if (idx < 0 || (unsigned)idx >= macro->Conditions().size()) { - currentConditionIdx = -1; - } else { - currentConditionIdx = idx; - lastInteracted = MacroSection::CONDITIONS; - } - currentActionIdx = -1; - HighlightControls(); + SetupMacroSegmentSelection(MacroSection::CONDITIONS, idx); } void AdvSceneSwitcher::MacroConditionReorder(int to, int from) diff --git a/src/macro-core/macro-tab.cpp b/src/macro-core/macro-tab.cpp index 16d8aa74..ec8b6a16 100644 --- a/src/macro-core/macro-tab.cpp +++ b/src/macro-core/macro-tab.cpp @@ -253,6 +253,76 @@ void AdvSceneSwitcher::ExportMacros() MacroExportImportDialog::ExportMacros(exportString); } +static bool +isValidMacroSegmentIdx(const std::deque> &list, + int idx) +{ + return (idx > 0 || (unsigned)idx < list.size()); +} + +void AdvSceneSwitcher::SetupMacroSegmentSelection(MacroSection type, int idx) +{ + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + + MacroSegmentList *setList, *resetList1, *resetList2; + int *setIdx, *resetIdx1, *resetIdx2; + std::deque> segements; + + switch (type) { + case AdvSceneSwitcher::MacroSection::CONDITIONS: + setList = ui->conditionsList; + setIdx = ¤tConditionIdx; + segements = {macro->Conditions().begin(), + macro->Conditions().end()}; + + resetList1 = ui->actionsList; + resetList2 = ui->elseActionsList; + resetIdx1 = ¤tActionIdx; + resetIdx2 = ¤tElseActionIdx; + break; + case AdvSceneSwitcher::MacroSection::ACTIONS: + setList = ui->actionsList; + setIdx = ¤tActionIdx; + segements = {macro->Actions().begin(), macro->Actions().end()}; + + resetList1 = ui->conditionsList; + resetList2 = ui->elseActionsList; + resetIdx1 = ¤tConditionIdx; + resetIdx2 = ¤tElseActionIdx; + break; + case AdvSceneSwitcher::MacroSection::ELSE_ACTIONS: + setList = ui->elseActionsList; + setIdx = ¤tElseActionIdx; + segements = {macro->ElseActions().begin(), + macro->ElseActions().end()}; + + resetList1 = ui->actionsList; + resetList2 = ui->conditionsList; + resetIdx1 = ¤tActionIdx; + resetIdx2 = ¤tConditionIdx; + break; + default: + break; + } + + setList->SetSelection(idx); + resetList1->SetSelection(-1); + resetList2->SetSelection(-1); + if (isValidMacroSegmentIdx(segements, idx)) { + *setIdx = idx; + } else { + *setIdx = -1; + } + *resetIdx1 = -1; + *resetIdx2 = -1; + + lastInteracted = type; + HighlightControls(); +} + bool AdvSceneSwitcher::ResolveMacroImportNameConflict( std::shared_ptr ¯o) { @@ -427,6 +497,17 @@ void AdvSceneSwitcher::PopulateMacroActions(Macro &m, uint32_t afterIdx) ui->actionsList->SetHelpMsgVisible(actions.size() == 0); } +void AdvSceneSwitcher::PopulateMacroElseActions(Macro &m, uint32_t afterIdx) +{ + auto &actions = m.ElseActions(); + for (; afterIdx < actions.size(); afterIdx++) { + auto newEntry = new MacroActionEdit(this, &actions[afterIdx], + actions[afterIdx]->GetId()); + ui->elseActionsList->Add(newEntry); + } + ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0); +} + void AdvSceneSwitcher::PopulateMacroConditions(Macro &m, uint32_t afterIdx) { bool root = afterIdx == 0; @@ -458,6 +539,23 @@ void AdvSceneSwitcher::SetActionData(Macro &m) } } +void AdvSceneSwitcher::SetElseActionData(Macro &m) +{ + auto &actions = m.ElseActions(); + for (int idx = 0; idx < ui->elseActionsList->ContentLayout()->count(); + idx++) { + auto item = ui->elseActionsList->ContentLayout()->itemAt(idx); + if (!item) { + continue; + } + auto widget = static_cast(item->widget()); + if (!widget) { + continue; + } + widget->SetEntryData(&*(actions.begin() + idx)); + } +} + void AdvSceneSwitcher::SetConditionData(Macro &m) { auto &conditions = m.Conditions(); @@ -475,6 +573,21 @@ void AdvSceneSwitcher::SetConditionData(Macro &m) } } +static void maximizeFirstSplitterEntry(QSplitter *splitter) +{ + QList newSizes; + newSizes << 999999; + for (int i = 0; i < splitter->sizes().size() - 1; i++) { + newSizes << 0; + } + splitter->setSizes(newSizes); +} + +static void centerSplitterPosition(QSplitter *splitter) +{ + splitter->setSizes(QList() << 999999 << 999999); +} + void AdvSceneSwitcher::SetEditMacro(Macro &m) { { @@ -487,20 +600,38 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m) } ui->conditionsList->Clear(); ui->actionsList->Clear(); + ui->elseActionsList->Clear(); m.ResetUIHelpers(); PopulateMacroConditions(m); PopulateMacroActions(m); + PopulateMacroElseActions(m); SetMacroEditAreaDisabled(false); + + currentActionIdx = -1; + currentElseActionIdx = -1; + currentConditionIdx = -1; + HighlightControls(); + if (m.IsGroup()) { SetMacroEditAreaDisabled(true); ui->macroName->setEnabled(true); + centerSplitterPosition(ui->macroActionConditionSplitter); + maximizeFirstSplitterEntry(ui->macroElseActionSplitter); + return; } - currentActionIdx = -1; - currentConditionIdx = -1; - HighlightControls(); + if (!m.HasValidSplitterPositions()) { + centerSplitterPosition(ui->macroActionConditionSplitter); + maximizeFirstSplitterEntry(ui->macroElseActionSplitter); + return; + } + + ui->macroActionConditionSplitter->setSizes( + m.GetActionConditionSplitterPosition()); + ui->macroElseActionSplitter->setSizes( + m.GetElseActionSplitterPosition()); } void AdvSceneSwitcher::SetMacroEditAreaDisabled(bool disable) @@ -519,6 +650,11 @@ void AdvSceneSwitcher::HighlightAction(int idx, QColor color) ui->actionsList->Highlight(idx, color); } +void AdvSceneSwitcher::HighlightElseAction(int idx, QColor color) +{ + ui->elseActionsList->Highlight(idx, color); +} + void AdvSceneSwitcher::HighlightCondition(int idx, QColor color) { ui->conditionsList->Highlight(idx, color); @@ -534,6 +670,33 @@ std::vector> AdvSceneSwitcher::GetSelectedMacros() return ui->macros->GetCurrentMacros(); } +void AdvSceneSwitcher::MacroSelectionAboutToChange() +{ + if (loading) { + return; + } + + auto macro = GetMacroByQString(ui->macroName->text()); + if (!macro) { + return; + } + + macro->SetActionConditionSplitterPosition( + ui->macroActionConditionSplitter->sizes()); + + auto elsePos = ui->macroElseActionSplitter->sizes(); + // If only conditions are visible maximize the actions to avoid neither + // actions nor elseActions being visible when the condition <-> action + // splitter is moved + if (elsePos[0] == 0 && elsePos[1] == 0) { + macro->SetElseActionSplitterPosition(QList() + << 999999 << 0); + return; + } + macro->SetElseActionSplitterPosition( + ui->macroElseActionSplitter->sizes()); +} + void AdvSceneSwitcher::MacroSelectionChanged() { if (loading) { @@ -545,8 +708,12 @@ void AdvSceneSwitcher::MacroSelectionChanged() SetMacroEditAreaDisabled(true); ui->conditionsList->Clear(); ui->actionsList->Clear(); + ui->elseActionsList->Clear(); ui->conditionsList->SetHelpMsgVisible(true); ui->actionsList->SetHelpMsgVisible(true); + ui->elseActionsList->SetHelpMsgVisible(true); + centerSplitterPosition(ui->macroActionConditionSplitter); + maximizeFirstSplitterEntry(ui->macroElseActionSplitter); return; } SetEditMacro(*macro); @@ -584,8 +751,19 @@ void AdvSceneSwitcher::on_macroProperties_clicked() emit HighlightConditionsChanged(prop._highlightConditions); } -// Don't restore splitter pos if an element is not visible at all -bool shouldResotreSplitterPos(const QList &pos) +static void moveControlsToSplitter(QSplitter *splitter, int idx, + QLayoutItem *item) +{ + static int splitterHandleWidth = 38; + auto handle = splitter->handle(idx); + auto layout = item->layout(); + layout->setContentsMargins(7, 7, 7, 7); + handle->setLayout(layout); + splitter->setHandleWidth(splitterHandleWidth); + splitter->setStyleSheet("QSplitter::handle {background: transparent;}"); +} + +bool shouldRestoreSplitter(const QList &pos) { if (pos.size() == 0) { return false; @@ -606,6 +784,8 @@ void AdvSceneSwitcher::SetupMacroTab() } ui->macros->Reset(switcher->macros, switcher->macroProperties._highlightExecuted); + connect(ui->macros, SIGNAL(MacroSelectionAboutToChange()), this, + SLOT(MacroSelectionAboutToChange())); connect(ui->macros, SIGNAL(MacroSelectionChanged()), this, SLOT(MacroSelectionChanged())); @@ -623,12 +803,22 @@ void AdvSceneSwitcher::SetupMacroTab() connect(ui->actionsList, &MacroSegmentList::Reorder, this, &AdvSceneSwitcher::MacroActionReorder); + ui->elseActionsList->SetHelpMsg(obs_module_text( + "AdvSceneSwitcher.macroTab.editElseActionHelp")); + connect(ui->elseActionsList, &MacroSegmentList::SelectionChagned, this, + &AdvSceneSwitcher::MacroElseActionSelectionChanged); + connect(ui->elseActionsList, &MacroSegmentList::Reorder, this, + &AdvSceneSwitcher::MacroElseActionReorder); + ui->macros->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->macros, &QWidget::customContextMenuRequested, this, &AdvSceneSwitcher::ShowMacroContextMenu); ui->actionsList->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->actionsList, &QWidget::customContextMenuRequested, this, &AdvSceneSwitcher::ShowMacroActionsContextMenu); + ui->elseActionsList->setContextMenuPolicy(Qt::CustomContextMenu); + connect(ui->elseActionsList, &QWidget::customContextMenuRequested, this, + &AdvSceneSwitcher::ShowMacroElseActionsContextMenu); ui->conditionsList->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->conditionsList, &QWidget::customContextMenuRequested, this, &AdvSceneSwitcher::ShowMacroConditionsContextMenu); @@ -643,16 +833,10 @@ void AdvSceneSwitcher::SetupMacroTab() onChangeHighlightTimer.start(); // Move condition controls into splitter handle layout - auto handle = ui->macroActionConditionSplitter->handle(1); - auto item = ui->macroConditionsLayout->takeAt(1); - if (item) { - auto layout = item->layout(); - layout->setContentsMargins(7, 7, 7, 7); - handle->setLayout(layout); - ui->macroActionConditionSplitter->setHandleWidth(38); - } - ui->macroActionConditionSplitter->setStyleSheet( - "QSplitter::handle {background: transparent;}"); + moveControlsToSplitter(ui->macroActionConditionSplitter, 1, + ui->macroConditionsLayout->takeAt(1)); + moveControlsToSplitter(ui->macroElseActionSplitter, 1, + ui->macroActionsLayout->takeAt(1)); // Set action and condition control icons const std::string pathPrefix = @@ -660,6 +844,9 @@ void AdvSceneSwitcher::SetupMacroTab() SetButtonIcon(ui->actionTop, (pathPrefix + "DoubleUp.svg").c_str()); SetButtonIcon(ui->actionBottom, (pathPrefix + "DoubleDown.svg").c_str()); + SetButtonIcon(ui->elseActionTop, (pathPrefix + "DoubleUp.svg").c_str()); + SetButtonIcon(ui->elseActionBottom, + (pathPrefix + "DoubleDown.svg").c_str()); SetButtonIcon(ui->conditionTop, (pathPrefix + "DoubleUp.svg").c_str()); SetButtonIcon(ui->conditionBottom, (pathPrefix + "DoubleDown.svg").c_str()); @@ -668,13 +855,11 @@ void AdvSceneSwitcher::SetupMacroTab() ui->macroListMacroEditSplitter->setStretchFactor(0, 1); ui->macroListMacroEditSplitter->setStretchFactor(1, 4); + centerSplitterPosition(ui->macroActionConditionSplitter); + maximizeFirstSplitterEntry(ui->macroElseActionSplitter); + if (switcher->saveWindowGeo) { - if (shouldResotreSplitterPos( - switcher->macroActionConditionSplitterPosition)) { - ui->macroActionConditionSplitter->setSizes( - switcher->macroActionConditionSplitterPosition); - } - if (shouldResotreSplitterPos( + if (shouldRestoreSplitter( switcher->macroListMacroEditSplitterPosition)) { ui->macroListMacroEditSplitter->setSizes( switcher->macroListMacroEditSplitterPosition); @@ -732,34 +917,49 @@ void AdvSceneSwitcher::ShowMacroContextMenu(const QPoint &pos) menu.exec(globalPos); } -void AdvSceneSwitcher::ShowMacroActionsContextMenu(const QPoint &pos) +static void setupConextMenu(AdvSceneSwitcher *ss, const QPoint &pos, + std::function expand, + std::function collapse, + std::function maximize, + std::function minimize) { - QPoint globalPos = ui->actionsList->mapToGlobal(pos); QMenu menu; menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.expandAll"), - this, &AdvSceneSwitcher::ExpandAllActions); + ss, [ss, expand]() { expand(ss); }); menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.collapseAll"), - this, &AdvSceneSwitcher::CollapseAllActions); + ss, [ss, collapse]() { collapse(ss); }); menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.maximize"), - this, &AdvSceneSwitcher::MinimizeConditions); + ss, [ss, maximize]() { maximize(ss); }); menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.minimize"), - this, &AdvSceneSwitcher::MinimizeActions); - menu.exec(globalPos); + ss, [ss, minimize]() { minimize(ss); }); + menu.exec(pos); +} + +void AdvSceneSwitcher::ShowMacroActionsContextMenu(const QPoint &pos) +{ + setupConextMenu(this, ui->actionsList->mapToGlobal(pos), + &AdvSceneSwitcher::ExpandAllActions, + &AdvSceneSwitcher::CollapseAllActions, + &AdvSceneSwitcher::MaximizeActions, + &AdvSceneSwitcher::MinimizeActions); +} + +void AdvSceneSwitcher::ShowMacroElseActionsContextMenu(const QPoint &pos) +{ + setupConextMenu(this, ui->elseActionsList->mapToGlobal(pos), + &AdvSceneSwitcher::ExpandAllElseActions, + &AdvSceneSwitcher::CollapseAllElseActions, + &AdvSceneSwitcher::MaximizeElseActions, + &AdvSceneSwitcher::MinimizeElseActions); } void AdvSceneSwitcher::ShowMacroConditionsContextMenu(const QPoint &pos) { - QPoint globalPos = ui->conditionsList->mapToGlobal(pos); - QMenu menu; - menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.expandAll"), - this, &AdvSceneSwitcher::ExpandAllConditions); - menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.collapseAll"), - this, &AdvSceneSwitcher::CollapseAllConditions); - menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.maximize"), - this, &AdvSceneSwitcher::MinimizeActions); - menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.minimize"), - this, &AdvSceneSwitcher::MinimizeConditions); - menu.exec(globalPos); + setupConextMenu(this, ui->conditionsList->mapToGlobal(pos), + &AdvSceneSwitcher::ExpandAllConditions, + &AdvSceneSwitcher::CollapseAllConditions, + &AdvSceneSwitcher::MaximizeConditions, + &AdvSceneSwitcher::MinimizeConditions); } void AdvSceneSwitcher::CopyMacro() @@ -789,60 +989,103 @@ void AdvSceneSwitcher::CopyMacro() emit MacroAdded(QString::fromStdString(name)); } -void AdvSceneSwitcher::ExpandAllActions() +void setCollapsedHelper(const std::shared_ptr &m, MacroSegmentList *list, + bool collapsed) { - auto m = GetSelectedMacro(); if (!m) { return; } - ui->actionsList->SetCollapsed(false); + list->SetCollapsed(collapsed); +} + +void AdvSceneSwitcher::ExpandAllActions() +{ + setCollapsedHelper(GetSelectedMacro(), ui->actionsList, false); +} + +void AdvSceneSwitcher::ExpandAllElseActions() +{ + setCollapsedHelper(GetSelectedMacro(), ui->elseActionsList, false); } void AdvSceneSwitcher::ExpandAllConditions() { - auto m = GetSelectedMacro(); - if (!m) { - return; - } - ui->conditionsList->SetCollapsed(false); + setCollapsedHelper(GetSelectedMacro(), ui->conditionsList, false); } void AdvSceneSwitcher::CollapseAllActions() { - auto m = GetSelectedMacro(); - if (!m) { - return; - } - ui->actionsList->SetCollapsed(true); + setCollapsedHelper(GetSelectedMacro(), ui->actionsList, true); +} + +void AdvSceneSwitcher::CollapseAllElseActions() +{ + setCollapsedHelper(GetSelectedMacro(), ui->elseActionsList, true); } void AdvSceneSwitcher::CollapseAllConditions() { - auto m = GetSelectedMacro(); - if (!m) { - return; - } - ui->conditionsList->SetCollapsed(true); + setCollapsedHelper(GetSelectedMacro(), ui->conditionsList, true); +} + +static void reduceSizeOfSplitterIdx(QSplitter *splitter, int idx) +{ + auto sizes = splitter->sizes(); + int sum = sizes[0] + sizes[1]; + int reducedSize = sum / 10; + sizes[idx] = reducedSize; + sizes[(idx + 1) % 2] = sum - reducedSize; + splitter->setSizes(sizes); } void AdvSceneSwitcher::MinimizeActions() { - QList sizes = ui->macroActionConditionSplitter->sizes(); - int sum = sizes[0] + sizes[1]; - int actionsHeight = sum / 10; - sizes[1] = actionsHeight; - sizes[0] = sum - actionsHeight; - ui->macroActionConditionSplitter->setSizes(sizes); + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + if (macro->ElseActions().size() == 0) { + reduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 1); + } else { + maximizeFirstSplitterEntry(ui->macroElseActionSplitter); + reduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 1); + } +} + +void AdvSceneSwitcher::MaximizeActions() +{ + MinimizeElseActions(); + MinimizeConditions(); +} + +void AdvSceneSwitcher::MinimizeElseActions() +{ + auto macro = GetSelectedMacro(); + if (!macro) { + return; + } + if (macro->ElseActions().size() == 0) { + maximizeFirstSplitterEntry(ui->macroElseActionSplitter); + } else { + reduceSizeOfSplitterIdx(ui->macroElseActionSplitter, 1); + } +} + +void AdvSceneSwitcher::MaximizeElseActions() +{ + MinimizeConditions(); + reduceSizeOfSplitterIdx(ui->macroElseActionSplitter, 0); } void AdvSceneSwitcher::MinimizeConditions() { - QList sizes = ui->macroActionConditionSplitter->sizes(); - int sum = sizes[0] + sizes[1]; - int conditionsHeight = sum / 10; - sizes[0] = conditionsHeight; - sizes[1] = sum - conditionsHeight; - ui->macroActionConditionSplitter->setSizes(sizes); + reduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 0); +} + +void AdvSceneSwitcher::MaximizeConditions() +{ + MinimizeElseActions(); + MinimizeActions(); } bool AdvSceneSwitcher::MacroTabIsInFocus() diff --git a/src/macro-core/macro-tree.cpp b/src/macro-core/macro-tree.cpp index c284ec57..e743cb46 100644 --- a/src/macro-core/macro-tree.cpp +++ b/src/macro-core/macro-tree.cpp @@ -1260,6 +1260,7 @@ void MacroTree::UngroupSelectedGroups() void MacroTree::SelectionChangedHelper(const QItemSelection &, const QItemSelection &) { + emit MacroSelectionAboutToChange(); emit MacroSelectionChanged(); } diff --git a/src/macro-core/macro-tree.hpp b/src/macro-core/macro-tree.hpp index eb40f9e9..423a6f58 100644 --- a/src/macro-core/macro-tree.hpp +++ b/src/macro-core/macro-tree.hpp @@ -142,6 +142,7 @@ public slots: const QItemSelection &); signals: + void MacroSelectionAboutToChange(); void MacroSelectionChanged(); protected: diff --git a/src/macro-core/macro.cpp b/src/macro-core/macro.cpp index b9b5861e..1b2ae8cc 100644 --- a/src/macro-core/macro.cpp +++ b/src/macro-core/macro.cpp @@ -176,14 +176,11 @@ bool Macro::CeckMatch() } vblog(LOG_INFO, "Macro %s returned %d", _name.c_str(), _matched); - bool matchedBeforeOnChangeCheck = _matched; - if (_matched && _matchOnChange && _lastMatched) { - vblog(LOG_INFO, "ignore match for Macro %s (on change)", - _name.c_str()); - _matched = false; - SetOnChangeHighlight(); + _conditionSateChanged = _lastMatched != _matched; + if (!_conditionSateChanged) { + _onPreventedActionExecution = true; } - _lastMatched = matchedBeforeOnChangeCheck; + _lastMatched = _matched; _lastCheckTime = std::chrono::high_resolution_clock::now(); return _matched; } @@ -223,6 +220,28 @@ bool Macro::ExecutedSince( return _lastExecutionTime > time; } +bool Macro::ShouldRunActions() const +{ + const bool hasActionsToExecute = + (_matched || _elseActions.size() > 0) && + (!_performActionsOnChange || _conditionSateChanged); + + if (VerboseLoggingEnabled() && _performActionsOnChange && + !_conditionSateChanged) { + if (_matched && _actions.size() > 0) { + blog(LOG_INFO, "skip actions for Macro %s (on change)", + _name.c_str()); + } + if (!_matched && _elseActions.size() > 0) { + blog(LOG_INFO, + "skip else actions for Macro %s (on change)", + _name.c_str()); + } + } + + return hasActionsToExecute; +} + int64_t Macro::MsSinceLastCheck() const { if (_lastCheckTime.time_since_epoch().count() == 0) { @@ -254,20 +273,24 @@ void Macro::ResetTimers() void Macro::RunActions(bool &retVal, bool ignorePause) { bool ret = true; - for (auto &a : _actions) { - if (a->Enabled()) { - a->LogAction(); - ret = ret && a->PerformAction(); + const std::deque> &actionsToExecute = + _matched ? _actions : _elseActions; + vblog(LOG_INFO, "running %sactions of %s", _matched ? "" : "else ", + _name.c_str()); + for (auto &action : actionsToExecute) { + if (action->Enabled()) { + action->LogAction(); + ret = ret && action->PerformAction(); } else { vblog(LOG_INFO, "skipping disabled action %s", - a->GetId().c_str()); + action->GetId().c_str()); } if (!ret || (_paused && !ignorePause) || _stop || _die) { retVal = ret; break; } - if (a->Enabled()) { - a->SetHighlight(); + if (action->Enabled()) { + action->SetHighlight(); } } _done = true; @@ -279,16 +302,16 @@ void Macro::RunActions(bool ignorePause) RunActions(unused, ignorePause); } -void Macro::SetOnChangeHighlight() -{ - _onChangeTriggered = true; -} - bool Macro::DockIsVisible() const { return _dock && _dockAction && _dock->isVisible(); } +void Macro::SetMatchOnChange(bool onChange) +{ + _performActionsOnChange = onChange; +} + void Macro::SetPaused(bool pause) { if (_paused && !pause) { @@ -332,22 +355,39 @@ std::deque> &Macro::Actions() return _actions; } -void Macro::UpdateActionIndices() +std::deque> &Macro::ElseActions() +{ + return _elseActions; +} + +static void updateIndicesHelper(std::deque> &list) { int idx = 0; - for (auto a : _actions) { - a->SetIndex(idx); + for (auto segment : list) { + segment->SetIndex(idx); idx++; } } +void Macro::UpdateActionIndices() +{ + std::deque> list(_actions.begin(), + _actions.end()); + updateIndicesHelper(list); +} + +void Macro::UpdateElseActionIndices() +{ + std::deque> list(_elseActions.begin(), + _elseActions.end()); + updateIndicesHelper(list); +} + void Macro::UpdateConditionIndices() { - int idx = 0; - for (auto c : _conditions) { - c->SetIndex(idx); - idx++; - } + std::deque> list(_conditions.begin(), + _conditions.end()); + updateIndicesHelper(list); } std::shared_ptr Macro::Parent() const @@ -360,56 +400,57 @@ bool Macro::Save(obs_data_t *obj) const obs_data_set_string(obj, "name", _name.c_str()); obs_data_set_bool(obj, "pause", _paused); obs_data_set_bool(obj, "parallel", _runInParallel); - obs_data_set_bool(obj, "onChange", _matchOnChange); + obs_data_set_bool(obj, "onChange", _performActionsOnChange); obs_data_set_bool(obj, "skipExecOnStart", _skipExecOnStart); obs_data_set_bool(obj, "group", _isGroup); if (_isGroup) { - auto groupData = obs_data_create(); + OBSDataAutoRelease groupData = obs_data_create(); obs_data_set_bool(groupData, "collapsed", _isCollapsed); obs_data_set_int(groupData, "size", _groupSize); obs_data_set_obj(obj, "groupData", groupData); - obs_data_release(groupData); return true; } SaveDockSettings(obj); + SaveSplitterPos(_actionConditionSplitterPosition, obj, + "macroActionConditionSplitterPosition"); + SaveSplitterPos(_elseActionSplitterPosition, obj, + "macroElseActionSplitterPosition"); + obs_data_set_bool(obj, "registerHotkeys", _registerHotkeys); - obs_data_array_t *pauseHotkey = obs_hotkey_save(_pauseHotkey); + OBSDataArrayAutoRelease pauseHotkey = obs_hotkey_save(_pauseHotkey); obs_data_set_array(obj, "pauseHotkey", pauseHotkey); - obs_data_array_release(pauseHotkey); - obs_data_array_t *unpauseHotkey = obs_hotkey_save(_unpauseHotkey); + OBSDataArrayAutoRelease unpauseHotkey = obs_hotkey_save(_unpauseHotkey); obs_data_set_array(obj, "unpauseHotkey", unpauseHotkey); - obs_data_array_release(unpauseHotkey); - obs_data_array_t *togglePauseHotkey = + OBSDataArrayAutoRelease togglePauseHotkey = obs_hotkey_save(_togglePauseHotkey); obs_data_set_array(obj, "togglePauseHotkey", togglePauseHotkey); - obs_data_array_release(togglePauseHotkey); - obs_data_array_t *conditions = obs_data_array_create(); + OBSDataArrayAutoRelease conditions = obs_data_array_create(); for (auto &c : _conditions) { - obs_data_t *array_obj = obs_data_create(); - - c->Save(array_obj); - obs_data_array_push_back(conditions, array_obj); - - obs_data_release(array_obj); + OBSDataAutoRelease arrayObj = obs_data_create(); + c->Save(arrayObj); + obs_data_array_push_back(conditions, arrayObj); } obs_data_set_array(obj, "conditions", conditions); - obs_data_array_release(conditions); - obs_data_array_t *actions = obs_data_array_create(); + OBSDataArrayAutoRelease actions = obs_data_array_create(); for (auto &a : _actions) { - obs_data_t *array_obj = obs_data_create(); - - a->Save(array_obj); - obs_data_array_push_back(actions, array_obj); - - obs_data_release(array_obj); + OBSDataAutoRelease arrayObj = obs_data_create(); + a->Save(arrayObj); + obs_data_array_push_back(actions, arrayObj); } obs_data_set_array(obj, "actions", actions); - obs_data_array_release(actions); + + OBSDataArrayAutoRelease elseActions = obs_data_array_create(); + for (auto &a : _elseActions) { + OBSDataAutoRelease arrayObj = obs_data_create(); + a->Save(arrayObj); + obs_data_array_push_back(elseActions, arrayObj); + } + obs_data_set_array(obj, "elseActions", elseActions); return true; } @@ -453,73 +494,69 @@ bool Macro::Load(obs_data_t *obj) _name = obs_data_get_string(obj, "name"); _paused = obs_data_get_bool(obj, "pause"); _runInParallel = obs_data_get_bool(obj, "parallel"); - _matchOnChange = obs_data_get_bool(obj, "onChange"); + _performActionsOnChange = obs_data_get_bool(obj, "onChange"); _skipExecOnStart = obs_data_get_bool(obj, "skipExecOnStart"); _isGroup = obs_data_get_bool(obj, "group"); if (_isGroup) { - auto groupData = obs_data_get_obj(obj, "groupData"); + OBSDataAutoRelease groupData = + obs_data_get_obj(obj, "groupData"); _isCollapsed = obs_data_get_bool(groupData, "collapsed"); _groupSize = obs_data_get_int(groupData, "size"); - obs_data_release(groupData); return true; } LoadDockSettings(obj); + LoadSplitterPos(_actionConditionSplitterPosition, obj, + "macroActionConditionSplitterPosition"); + LoadSplitterPos(_elseActionSplitterPosition, obj, + "macroElseActionSplitterPosition"); + obs_data_set_default_bool(obj, "registerHotkeys", true); _registerHotkeys = obs_data_get_bool(obj, "registerHotkeys"); if (_registerHotkeys) { SetupHotkeys(); } - obs_data_array_t *pauseHotkey = obs_data_get_array(obj, "pauseHotkey"); + OBSDataArrayAutoRelease pauseHotkey = + obs_data_get_array(obj, "pauseHotkey"); obs_hotkey_load(_pauseHotkey, pauseHotkey); - obs_data_array_release(pauseHotkey); - obs_data_array_t *unpauseHotkey = + OBSDataArrayAutoRelease unpauseHotkey = obs_data_get_array(obj, "unpauseHotkey"); obs_hotkey_load(_unpauseHotkey, unpauseHotkey); - obs_data_array_release(unpauseHotkey); - obs_data_array_t *togglePauseHotkey = + OBSDataArrayAutoRelease togglePauseHotkey = obs_data_get_array(obj, "togglePauseHotkey"); obs_hotkey_load(_togglePauseHotkey, togglePauseHotkey); - obs_data_array_release(togglePauseHotkey); SetHotkeysDesc(); bool root = true; - obs_data_array_t *conditions = obs_data_get_array(obj, "conditions"); + OBSDataArrayAutoRelease conditions = + obs_data_get_array(obj, "conditions"); size_t count = obs_data_array_count(conditions); - for (size_t i = 0; i < count; i++) { - obs_data_t *array_obj = obs_data_array_item(conditions, i); - - std::string id = obs_data_get_string(array_obj, "id"); - + OBSDataAutoRelease arrayObj = + obs_data_array_item(conditions, i); + std::string id = obs_data_get_string(arrayObj, "id"); auto newEntry = MacroConditionFactory::Create(id, this); if (newEntry) { _conditions.emplace_back(newEntry); auto c = _conditions.back().get(); - c->Load(array_obj); + c->Load(arrayObj); setValidLogic(c, root, _name); } else { blog(LOG_WARNING, "discarding condition entry with unknown id (%s) for macro %s", id.c_str(), _name.c_str()); } - - obs_data_release(array_obj); root = false; } - obs_data_array_release(conditions); UpdateConditionIndices(); - obs_data_array_t *actions = obs_data_get_array(obj, "actions"); + OBSDataArrayAutoRelease actions = obs_data_get_array(obj, "actions"); count = obs_data_array_count(actions); - for (size_t i = 0; i < count; i++) { - obs_data_t *array_obj = obs_data_array_item(actions, i); - + OBSDataAutoRelease array_obj = obs_data_array_item(actions, i); std::string id = obs_data_get_string(array_obj, "id"); - auto newEntry = MacroActionFactory::Create(id, this); if (newEntry) { _actions.emplace_back(newEntry); @@ -529,11 +566,27 @@ bool Macro::Load(obs_data_t *obj) "discarding action entry with unknown id (%s) for macro %s", id.c_str(), _name.c_str()); } - - obs_data_release(array_obj); } - obs_data_array_release(actions); UpdateActionIndices(); + + OBSDataArrayAutoRelease elseActions = + obs_data_get_array(obj, "elseActions"); + count = obs_data_array_count(elseActions); + for (size_t i = 0; i < count; i++) { + OBSDataAutoRelease array_obj = + obs_data_array_item(elseActions, i); + std::string id = obs_data_get_string(array_obj, "id"); + auto newEntry = MacroActionFactory::Create(id, this); + if (newEntry) { + _elseActions.emplace_back(newEntry); + _elseActions.back()->Load(array_obj); + } else { + blog(LOG_WARNING, + "discarding elseAction entry with unknown id (%s) for macro %s", + id.c_str(), _name.c_str()); + } + } + UpdateElseActionIndices(); return true; } @@ -552,7 +605,12 @@ bool Macro::SwitchesScene() const { MacroActionSwitchScene temp(nullptr); auto sceneSwitchId = temp.GetId(); - for (auto &a : _actions) { + for (const auto &a : _actions) { + if (a->GetId() == sceneSwitchId) { + return true; + } + } + for (const auto &a : _elseActions) { if (a->GetId() == sceneSwitchId) { return true; } @@ -560,10 +618,36 @@ bool Macro::SwitchesScene() const return false; } +const QList &Macro::GetActionConditionSplitterPosition() const +{ + return _actionConditionSplitterPosition; +} + +void Macro::SetActionConditionSplitterPosition(const QList sizes) +{ + _actionConditionSplitterPosition = sizes; +} + +const QList &Macro::GetElseActionSplitterPosition() const +{ + return _elseActionSplitterPosition; +} + +void Macro::SetElseActionSplitterPosition(const QList sizes) +{ + _elseActionSplitterPosition = sizes; +} + +bool Macro::HasValidSplitterPositions() const +{ + return !_actionConditionSplitterPosition.empty() && + !_elseActionSplitterPosition.empty(); +} + bool Macro::OnChangePreventedActionsRecently() { - if (_onChangeTriggered) { - _onChangeTriggered = false; + if (_onPreventedActionExecution) { + _onPreventedActionExecution = false; return true; } return false; @@ -571,7 +655,7 @@ bool Macro::OnChangePreventedActionsRecently() void Macro::ResetUIHelpers() { - _onChangeTriggered = false; + _onPreventedActionExecution = false; for (auto c : _conditions) { c->Highlight(); } @@ -1014,7 +1098,7 @@ bool SwitcherData::CheckMacros() { bool ret = false; for (auto &m : macros) { - if (m->CeckMatch()) { + if (m->CeckMatch() || m->ElseActions().size() > 0) { ret = true; // This has to be performed here for now as actions are // not performed immediately after checking conditions. @@ -1049,7 +1133,7 @@ bool SwitcherData::RunMacros() } for (auto &m : runPhaseMacros) { - if (!m || !m->Matched()) { + if (!m || !m->ShouldRunActions()) { continue; } if (firstInterval && m->SkipExecOnStart()) { diff --git a/src/macro-core/macro.hpp b/src/macro-core/macro.hpp index 6266fa92..9dce81fc 100644 --- a/src/macro-core/macro.hpp +++ b/src/macro-core/macro.hpp @@ -28,6 +28,7 @@ public: bool PerformActions(bool forceParallel = false, bool ignorePause = false); bool Matched() const { return _matched; } + bool ShouldRunActions() const; int64_t MsSinceLastCheck() const; std::string Name() const { return _name; } void SetName(const std::string &name); @@ -35,8 +36,8 @@ public: bool RunInParallel() const { return _runInParallel; } void SetPaused(bool pause = true); bool Paused() const { return _paused; } - void SetMatchOnChange(bool onChange) { _matchOnChange = onChange; } - bool MatchOnChange() const { return _matchOnChange; } + void SetMatchOnChange(bool onChange); + bool MatchOnChange() const { return _performActionsOnChange; } void SetSkipExecOnStart(bool skip) { _skipExecOnStart = skip; } bool SkipExecOnStart() const { return _skipExecOnStart; } int RunCount() const { return _runCount; }; @@ -48,7 +49,9 @@ public: std::deque> &Conditions(); std::deque> &Actions(); + std::deque> &ElseActions(); void UpdateActionIndices(); + void UpdateElseActionIndices(); void UpdateConditionIndices(); // Group controls @@ -80,6 +83,11 @@ public: bool SwitchesScene() const; // UI helpers + const QList &GetActionConditionSplitterPosition() const; + void SetActionConditionSplitterPosition(const QList); + const QList &GetElseActionSplitterPosition() const; + void SetElseActionSplitterPosition(const QList); + bool HasValidSplitterPositions() const; bool ExecutedSince(const std::chrono::high_resolution_clock::time_point &); bool OnChangePreventedActionsRecently(); @@ -115,7 +123,6 @@ private: void SetHotkeysDesc() const; void RunActions(bool &ret, bool ignorePause); void RunActions(bool ignorePause); - void SetOnChangeHighlight(); bool DockIsVisible() const; void SetDockWidgetName() const; void SaveDockSettings(obs_data_t *obj) const; @@ -133,6 +140,7 @@ private: std::deque> _conditions; std::deque> _actions; + std::deque> _elseActions; std::weak_ptr _parent; uint32_t _groupSize = 0; @@ -142,7 +150,8 @@ private: bool _runInParallel = false; bool _matched = false; bool _lastMatched = false; - bool _matchOnChange = true; + bool _conditionSateChanged = false; + bool _performActionsOnChange = true; bool _skipExecOnStart = false; bool _paused = false; int _runCount = 0; @@ -151,7 +160,11 @@ private: obs_hotkey_id _unpauseHotkey = OBS_INVALID_HOTKEY_ID; obs_hotkey_id _togglePauseHotkey = OBS_INVALID_HOTKEY_ID; - bool _onChangeTriggered = false; + // UI helpers + bool _onPreventedActionExecution = false; + + QList _actionConditionSplitterPosition; + QList _elseActionSplitterPosition; bool _registerDock = false; bool _dockHasRunButton = true; diff --git a/src/switcher-data.hpp b/src/switcher-data.hpp index c2defd2c..bb706d97 100644 --- a/src/switcher-data.hpp +++ b/src/switcher-data.hpp @@ -214,7 +214,6 @@ public: bool saveWindowGeo = false; QPoint windowPos = {}; QSize windowSize = {}; - QList macroActionConditionSplitterPosition; QList macroListMacroEditSplitterPosition; /* --- End of UI section --- */