#include "macro-edit.hpp" #include "cursor-shape-changer.hpp" #include "macro.hpp" #include "macro-action-edit.hpp" #include "macro-action-macro.hpp" #include "macro-condition-edit.hpp" #include "macro-segment-copy-paste.hpp" #include "macro-segment-list.hpp" #include "macro-settings.hpp" #include "macro-signals.hpp" #include "math-helpers.hpp" #include "name-dialog.hpp" #include "path-helpers.hpp" #include "obs-module-helper.hpp" #include "plugin-state-helpers.hpp" #include "splitter-helpers.hpp" #include "tab-helpers.hpp" #include "ui-helpers.hpp" #include #include #include #include namespace advss { static void moveControlsToSplitter(QSplitter *splitter, int idx, QLayoutItem *item) { static int splitterHandleWidth = 32; auto handle = splitter->handle(idx); auto layout = item->layout(); int leftMargin, rightMargin; layout->getContentsMargins(&leftMargin, nullptr, &rightMargin, nullptr); layout->setContentsMargins(leftMargin, 0, rightMargin, 0); handle->setLayout(layout); splitter->setHandleWidth(splitterHandleWidth); splitter->setStyleSheet("QSplitter::handle {background: transparent;}"); } static QToolBar * setupToolBar(const std::initializer_list> &widgetGroups) { auto toolbar = new QToolBar(); toolbar->setIconSize({16, 16}); QAction *lastSeperator = nullptr; for (const auto &widgetGroup : widgetGroups) { for (const auto &widget : widgetGroup) { toolbar->addWidget(widget); } lastSeperator = toolbar->addSeparator(); } if (lastSeperator) { toolbar->removeAction(lastSeperator); } // Prevent "extension" button from showing up toolbar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); return toolbar; } MacroEdit::MacroEdit(QWidget *parent, QStringList helpMsg) : ui(new Ui_MacroEdit) { setParent(parent); if (helpMsg.size() != 3) { helpMsg << "AdvSceneSwitcher.macroTab.editConditionHelp" << "AdvSceneSwitcher.macroTab.editActionHelp" << "AdvSceneSwitcher.macroTab.editElseActionHelp"; } ui->setupUi(this); ui->macroElseActions->installEventFilter(this); ui->conditionsList->SetHelpMsg( obs_module_text(helpMsg[0].toStdString().c_str())); connect(ui->conditionsList, &MacroSegmentList::SelectionChanged, this, &MacroEdit::MacroConditionSelectionChanged); connect(ui->conditionsList, &MacroSegmentList::Reorder, this, &MacroEdit::MacroConditionReorder); ui->actionsList->SetHelpMsg( obs_module_text(helpMsg[1].toStdString().c_str())); connect(ui->actionsList, &MacroSegmentList::SelectionChanged, this, &MacroEdit::MacroActionSelectionChanged); connect(ui->actionsList, &MacroSegmentList::Reorder, this, &MacroEdit::MacroActionReorder); ui->elseActionsList->SetHelpMsg( obs_module_text(helpMsg[2].toStdString().c_str())); connect(ui->elseActionsList, &MacroSegmentList::SelectionChanged, this, &MacroEdit::MacroElseActionSelectionChanged); connect(ui->elseActionsList, &MacroSegmentList::Reorder, this, &MacroEdit::MacroElseActionReorder); ui->actionsList->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->actionsList, &QWidget::customContextMenuRequested, this, &MacroEdit::ShowMacroActionsContextMenu); ui->elseActionsList->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->elseActionsList, &QWidget::customContextMenuRequested, this, &MacroEdit::ShowMacroElseActionsContextMenu); ui->conditionsList->setContextMenuPolicy(Qt::CustomContextMenu); connect(ui->conditionsList, &QWidget::customContextMenuRequested, this, &MacroEdit::ShowMacroConditionsContextMenu); connect(this, &MacroEdit::MacroAdded, MacroSignalManager::Instance(), &MacroSignalManager::Add); connect(this, &MacroEdit::MacroRemoved, MacroSignalManager::Instance(), &MacroSignalManager::Remove); connect(this, &MacroEdit::MacroRenamed, MacroSignalManager::Instance(), &MacroSignalManager::Rename); connect(this, &MacroEdit::MacroSegmentOrderChanged, MacroSignalManager::Instance(), &MacroSignalManager::SegmentOrderChanged); // Set action and condition toolbars const std::string pathPrefix = GetDataFilePath("res/images/" + GetThemeTypeName()); 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()); SetButtonIcon(ui->toggleElseActions, (pathPrefix + "NotEqual.svg").c_str()); auto conditionToolbar = setupToolBar({{ui->conditionAdd, ui->conditionRemove}, {ui->conditionTop, ui->conditionUp, ui->conditionDown, ui->conditionBottom}}); auto actionToolbar = setupToolBar({{ui->actionAdd, ui->actionRemove}, {ui->actionTop, ui->actionUp, ui->actionDown, ui->actionBottom}}); auto elseActionToolbar = setupToolBar({{ui->elseActionAdd, ui->elseActionRemove}, {ui->elseActionTop, ui->elseActionUp, ui->elseActionDown, ui->elseActionBottom}}); ui->conditionControlsLayout->addWidget(conditionToolbar); ui->actionControlsLayout->insertWidget(0, actionToolbar); ui->elseActionControlsLayout->addWidget(elseActionToolbar); // Move condition controls into splitter handle layout moveControlsToSplitter(ui->macroActionConditionSplitter, 1, ui->macroConditionsLayout->takeAt(1)); moveControlsToSplitter(ui->macroElseActionSplitter, 1, ui->macroActionsLayout->takeAt(1)); // Override splitter cursor icon when hovering over controls in splitter SetCursorOnWidgetHover(ui->conditionAdd, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->conditionRemove, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->conditionTop, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->conditionUp, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->conditionDown, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->conditionBottom, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->actionAdd, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->actionRemove, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->actionTop, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->actionUp, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->actionDown, Qt::CursorShape::ArrowCursor); SetCursorOnWidgetHover(ui->actionBottom, Qt::CursorShape::ArrowCursor); CenterSplitterPosition(ui->macroActionConditionSplitter); MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); // Macro segment highlight auto timer = new QTimer(this); connect(timer, &QTimer::timeout, this, [this]() { RunSegmentHighlightChecks(); }); timer->start(1500); SetupSegmentCopyPasteShortcutHandlers(this); } void MacroEdit::SetMacro(const std::shared_ptr ¯o) { if (_currentMacro) { _currentMacro->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) { MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); } else { _currentMacro->SetElseActionSplitterPosition( ui->macroElseActionSplitter->sizes()); } ui->conditionsList->CacheCurrentWidgetsFor(_currentMacro.get()); ui->actionsList->CacheCurrentWidgetsFor(_currentMacro.get()); ui->elseActionsList->CacheCurrentWidgetsFor( _currentMacro.get()); } ui->conditionsList->Clear(); ui->actionsList->Clear(); ui->elseActionsList->Clear(); currentActionIdx = -1; currentElseActionIdx = -1; currentConditionIdx = -1; HighlightControls(); _currentMacro = macro; if (!macro) { CenterSplitterPosition(ui->macroActionConditionSplitter); MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); ui->conditionsList->SetHelpMsgVisible(true); ui->actionsList->SetHelpMsgVisible(true); ui->elseActionsList->SetHelpMsgVisible(true); return; } PopulateMacroConditions(*macro); PopulateMacroActions(*macro); PopulateMacroElseActions(*macro); if (macro->IsGroup()) { CenterSplitterPosition(ui->macroActionConditionSplitter); MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); return; } if (macro->HasValidSplitterPositions()) { ui->macroActionConditionSplitter->setSizes( macro->GetActionConditionSplitterPosition()); ui->macroElseActionSplitter->setSizes( macro->GetElseActionSplitterPosition()); } else { CenterSplitterPosition(ui->macroActionConditionSplitter); MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); } } std::shared_ptr MacroEdit::GetMacro() const { return _currentMacro; } void MacroEdit::ClearSegmentWidgetCacheFor(Macro *macro) const { ui->conditionsList->ClearWidgetsFromCacheFor(macro); ui->actionsList->ClearWidgetsFromCacheFor(macro); ui->elseActionsList->ClearWidgetsFromCacheFor(macro); } void MacroEdit::SetControlsDisabled(bool disable) const { ui->macroActions->setDisabled(disable); ui->macroElseActions->setDisabled(disable); ui->macroConditions->setDisabled(disable); ui->macroActionConditionSplitter->setDisabled(disable); } bool MacroEdit::eventFilter(QObject *obj, QEvent *event) { if (obj != ui->macroElseActions || event->type() != QEvent::Resize) { return QWidget::eventFilter(obj, event); } auto resizeEvent = static_cast(event); if (resizeEvent->size().height() == 0) { SetElseActionsStateToHidden(); return QWidget::eventFilter(obj, event); } SetElseActionsStateToVisible(); return QWidget::eventFilter(obj, event); } static bool isValidMacroSegmentIdx(const std::deque> &list, int idx) { return (idx > 0 || (unsigned)idx < list.size()); } void MacroEdit::SetupMacroSegmentSelection(MacroSection type, int idx) { auto macro = _currentMacro; if (!macro) { return; } MacroSegmentList *setList = nullptr, *resetList1 = nullptr, *resetList2 = nullptr; int *setIdx = nullptr, *resetIdx1 = nullptr, *resetIdx2 = nullptr; std::deque> segments; switch (type) { case MacroEdit::MacroSection::CONDITIONS: setList = ui->conditionsList; setIdx = ¤tConditionIdx; segments = {macro->Conditions().begin(), macro->Conditions().end()}; resetList1 = ui->actionsList; resetList2 = ui->elseActionsList; resetIdx1 = ¤tActionIdx; resetIdx2 = ¤tElseActionIdx; break; case MacroEdit::MacroSection::ACTIONS: setList = ui->actionsList; setIdx = ¤tActionIdx; segments = {macro->Actions().begin(), macro->Actions().end()}; resetList1 = ui->conditionsList; resetList2 = ui->elseActionsList; resetIdx1 = ¤tConditionIdx; resetIdx2 = ¤tElseActionIdx; break; case MacroEdit::MacroSection::ELSE_ACTIONS: setList = ui->elseActionsList; setIdx = ¤tElseActionIdx; segments = {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(segments, idx)) { *setIdx = idx; } else { *setIdx = -1; } *resetIdx1 = -1; *resetIdx2 = -1; lastInteracted = type; HighlightControls(); } static void runSegmentHighlightChecksHelper(MacroSegmentList *list) { MacroSegmentEdit *widget = nullptr; for (int i = 0; (widget = list->WidgetAt(i)); i++) { const auto data = widget->Data(); // No need to highlight nested macro action as it itself will // highlight its segments if required auto macroAction = dynamic_cast(data.get()); if (macroAction && macroAction->_action == MacroActionMacro::Action::NESTED_MACRO) { continue; } if (data && data->GetHighlightAndReset()) { list->Highlight(i); } } } void MacroEdit::RunSegmentHighlightChecks() { if (!HighlightUIElementsEnabled()) { return; } auto macro = _currentMacro; if (!macro) { return; } const auto &settings = GetGlobalMacroSettings(); if (settings._highlightConditions) { runSegmentHighlightChecksHelper(ui->conditionsList); } if (settings._highlightActions) { runSegmentHighlightChecksHelper(ui->actionsList); runSegmentHighlightChecksHelper(ui->elseActionsList); } } bool MacroEdit::ElseSectionIsVisible() const { const auto elsePosition = ui->macroElseActionSplitter->sizes(); return elsePosition[1] != 0; } void MacroEdit::PopulateMacroActions(Macro &m, uint32_t afterIdx) { auto &actions = m.Actions(); ui->actionsList->SetHelpMsgVisible(actions.size() == 0); if (ui->actionsList->PopulateWidgetsFromCache(&m)) { return; } // The layout system has not completed geometry propagation yet, so we // can skip those checks for now ui->actionsList->SetVisibilityCheckEnable(false); for (; afterIdx < actions.size(); afterIdx++) { auto newEntry = new MacroActionEdit(this, &actions[afterIdx]); ui->actionsList->Add(newEntry); } // Give the layout system time before enabling the visibility checks and // fully constructing the visible macro segments QTimer::singleShot(0, this, [this]() { ui->actionsList->SetVisibilityCheckEnable(true); }); } void MacroEdit::PopulateMacroElseActions(Macro &m, uint32_t afterIdx) { auto &actions = m.ElseActions(); ui->elseActionsList->SetHelpMsgVisible(actions.size() == 0); if (ui->elseActionsList->PopulateWidgetsFromCache(&m)) { return; } // The layout system has not completed geometry propagation yet, so we // can skip those checks for now ui->elseActionsList->SetVisibilityCheckEnable(false); for (; afterIdx < actions.size(); afterIdx++) { auto newEntry = new MacroActionEdit(this, &actions[afterIdx]); ui->elseActionsList->Add(newEntry); } // Give the layout system time before enabling the visibility checks and // fully constructing the visible macro segments QTimer::singleShot(0, this, [this]() { ui->elseActionsList->SetVisibilityCheckEnable(true); }); } void MacroEdit::PopulateMacroConditions(Macro &m, uint32_t afterIdx) { bool root = afterIdx == 0; auto &conditions = m.Conditions(); ui->conditionsList->SetHelpMsgVisible(conditions.size() == 0); if (ui->conditionsList->PopulateWidgetsFromCache(&m)) { return; } // The layout system has not completed geometry propagation yet, so we // can skip those checks for now ui->conditionsList->SetVisibilityCheckEnable(false); for (; afterIdx < conditions.size(); afterIdx++) { auto newEntry = new MacroConditionEdit( this, &conditions[afterIdx], root); ui->conditionsList->Add(newEntry); root = false; } // Give the layout system time before enabling the visibility checks and // fully constructing the visible macro segments QTimer::singleShot(0, this, [this]() { ui->conditionsList->SetVisibilityCheckEnable(true); }); } static void setCollapsedHelper(const std::shared_ptr &m, MacroSegmentList *list, bool collapsed) { if (!m) { return; } list->SetCollapsed(collapsed); } void MacroEdit::ExpandAllActions() const { setCollapsedHelper(_currentMacro, ui->actionsList, false); } void MacroEdit::ExpandAllElseActions() const { setCollapsedHelper(_currentMacro, ui->elseActionsList, false); } void MacroEdit::ExpandAllConditions() const { setCollapsedHelper(_currentMacro, ui->conditionsList, false); } void MacroEdit::CollapseAllActions() const { setCollapsedHelper(_currentMacro, ui->actionsList, true); } void MacroEdit::CollapseAllElseActions() const { setCollapsedHelper(_currentMacro, ui->elseActionsList, true); } void MacroEdit::CollapseAllConditions() const { setCollapsedHelper(_currentMacro, ui->conditionsList, true); } void MacroEdit::MinimizeActions() const { auto macro = _currentMacro; if (!macro) { return; } if (macro->ElseActions().size() == 0) { ReduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 1); } else { MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); ReduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 1); } } void MacroEdit::MaximizeActions() const { MinimizeElseActions(); MinimizeConditions(); } void MacroEdit::MinimizeElseActions() const { auto macro = _currentMacro; if (!macro) { return; } if (macro->ElseActions().size() == 0) { MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); } else { ReduceSizeOfSplitterIdx(ui->macroElseActionSplitter, 1); } } void MacroEdit::MaximizeElseActions() const { MinimizeConditions(); ReduceSizeOfSplitterIdx(ui->macroElseActionSplitter, 0); } void MacroEdit::MinimizeConditions() const { ReduceSizeOfSplitterIdx(ui->macroActionConditionSplitter, 0); } void MacroEdit::MaximizeConditions() const { MinimizeElseActions(); MinimizeActions(); } void MacroEdit::on_toggleElseActions_clicked() const { if (!ElseSectionIsVisible()) { CenterSplitterPosition(ui->macroElseActionSplitter); return; } MaximizeFirstSplitterEntry(ui->macroElseActionSplitter); } void MacroEdit::SetElseActionsStateToHidden() const { ui->toggleElseActions->setToolTip(obs_module_text( "AdvSceneSwitcher.macroTab.toggleElseActions.show.tooltip")); ui->toggleElseActions->setChecked(false); } void MacroEdit::SetElseActionsStateToVisible() const { ui->toggleElseActions->setToolTip(obs_module_text( "AdvSceneSwitcher.macroTab.toggleElseActions.hide.tooltip")); ui->toggleElseActions->setChecked(true); } static void fade(QWidget *widget, bool fadeOut) { const double fadeOutOpacity = 0.3; // Don't use exactly 1.0 as for some reason this causes buttons in // macroSplitter handle layout to not be redrawn unless mousing over // them const double fadeInOpacity = 0.99; auto curEffect = widget->graphicsEffect(); if (curEffect) { auto curOpacity = dynamic_cast(curEffect); if (curOpacity && ((fadeOut && DoubleEquals(curOpacity->opacity(), fadeOutOpacity, 0.0001)) || (!fadeOut && DoubleEquals(curOpacity->opacity(), fadeInOpacity, 0.0001)))) { return; } } else if (!fadeOut) { return; } delete curEffect; QGraphicsOpacityEffect *opacityEffect = new QGraphicsOpacityEffect(); widget->setGraphicsEffect(opacityEffect); QPropertyAnimation *animation = new QPropertyAnimation(opacityEffect, "opacity"); animation->setDuration(350); animation->setStartValue(fadeOut ? fadeInOpacity : fadeOutOpacity); animation->setEndValue(fadeOut ? fadeOutOpacity : fadeInOpacity); animation->setEasingCurve(QEasingCurve::OutQuint); animation->start(QPropertyAnimation::DeleteWhenStopped); } static void fadeWidgets(const std::vector &widgets, bool fadeOut) { for (const auto &widget : widgets) { fade(widget, fadeOut); } } void MacroEdit::HighlightAction(int idx, QColor color) const { ui->actionsList->Highlight(idx, color); } void MacroEdit::HighlightElseAction(int idx, QColor color) const { ui->elseActionsList->Highlight(idx, color); } void MacroEdit::HighlightCondition(int idx, QColor color) const { ui->conditionsList->Highlight(idx, color); } static void resetSegmentHighlights(MacroSegmentList *list) { MacroSegmentEdit *widget = nullptr; for (int i = 0; (widget = list->WidgetAt(i)); i++) { if (widget && widget->Data()) { (void)widget->Data()->GetHighlightAndReset(); } } } void MacroEdit::ResetConditionHighlights() { resetSegmentHighlights(ui->conditionsList); } void MacroEdit::ResetActionHighlights() { resetSegmentHighlights(ui->actionsList); resetSegmentHighlights(ui->elseActionsList); } void MacroEdit::HighlightControls() const { const std::vector conditionControls{ ui->conditionAdd, ui->conditionRemove, ui->conditionTop, ui->conditionUp, ui->conditionDown, ui->conditionBottom, }; const std::vector actionControls{ ui->actionAdd, ui->actionRemove, ui->actionTop, ui->actionUp, ui->actionDown, ui->actionBottom, }; const std::vector elseActionControls{ ui->elseActionAdd, ui->elseActionRemove, ui->elseActionTop, ui->elseActionUp, ui->elseActionDown, ui->elseActionBottom, }; if ((currentActionIdx == -1 && currentConditionIdx == -1 && currentElseActionIdx == -1)) { fadeWidgets(conditionControls, false); fadeWidgets(actionControls, false); fadeWidgets(elseActionControls, false); } else if (currentConditionIdx != -1) { fadeWidgets(conditionControls, false); fadeWidgets(actionControls, true); fadeWidgets(elseActionControls, true); } else if (currentActionIdx != -1) { fadeWidgets(conditionControls, true); fadeWidgets(actionControls, false); fadeWidgets(elseActionControls, true); } else if (currentElseActionIdx != -1) { fadeWidgets(conditionControls, true); fadeWidgets(actionControls, true); fadeWidgets(elseActionControls, false); } else { assert(false); } } void MacroEdit::SetActionData(Macro &m) const { auto &actions = m.Actions(); for (int idx = 0; idx < ui->actionsList->ContentLayout()->count(); idx++) { auto item = ui->actionsList->ContentLayout()->itemAt(idx); if (!item) { continue; } auto widget = static_cast(item->widget()); if (!widget) { continue; } widget->SetEntryData(&*(actions.begin() + idx)); } } void MacroEdit::SetElseActionData(Macro &m) const { 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 MacroEdit::SetConditionData(Macro &m) const { auto &conditions = m.Conditions(); for (int idx = 0; idx < ui->conditionsList->ContentLayout()->count(); idx++) { auto item = ui->conditionsList->ContentLayout()->itemAt(idx); if (!item) { continue; } auto widget = static_cast(item->widget()); if (!widget) { continue; } widget->SetEntryData(&*(conditions.begin() + idx)); } } static void setupCopyPasteContextMenuEnry(MacroEdit *edit, QWidget *macroActions, QWidget *macroElseActions, MacroSegmentEdit *segmentEdit, QMenu &menu) { auto copy = menu.addAction( obs_module_text("AdvSceneSwitcher.macroTab.segment.copy"), edit, [edit]() { edit->CopyMacroSegment(); }); copy->setEnabled(!!segmentEdit); bool pasteAsElseAction = true; const char *pasteText = "AdvSceneSwitcher.macroTab.segment.paste"; if (MacroActionIsInClipboard()) { if (IsCursorInWidgetArea(macroActions)) { pasteAsElseAction = false; pasteText = "AdvSceneSwitcher.macroTab.segment.pasteAction"; } else if (IsCursorInWidgetArea(macroElseActions)) { pasteAsElseAction = true; pasteText = "AdvSceneSwitcher.macroTab.segment.pasteElseAction"; } } auto paste = menu.addAction( obs_module_text(pasteText), edit, [edit, pasteAsElseAction]() { SetCopySegmentTargetActionType(pasteAsElseAction); edit->PasteMacroSegment(); }); paste->setEnabled(MacroSegmentIsInClipboard()); } static void setupRemoveContextMenuEnry( MacroEdit *edit, const std::function &remove, const QPoint &pos, MacroSegmentList *list, QMenu &menu) { const auto segmentEditIndex = list->IndexAt(pos); if (segmentEditIndex == -1) { return; } menu.addAction( obs_module_text("AdvSceneSwitcher.macroTab.segment.remove"), edit, [edit, remove, segmentEditIndex]() { remove(edit, segmentEditIndex); }); } static bool handleCustomLabelRename(MacroSegmentEdit *segmentEdit) { std::string label; auto segment = segmentEdit->Data(); if (!segment) { return false; } bool accepted = NameDialog::AskForName( GetSettingsWindow(), obs_module_text( "AdvSceneSwitcher.macroTab.segment.setCustomLabel"), "", label, QString::fromStdString(segment->GetCustomLabel())); if (!accepted) { return false; } segment->SetCustomLabel(label); segmentEdit->HeaderInfoChanged(""); return true; } static void handleCustomLabelEnableChange(MacroSegmentEdit *segmentEdit, QAction *contextMenuOption) { bool enable = contextMenuOption->isChecked(); auto segment = segmentEdit->Data(); segment->SetUseCustomLabel(enable); if (!enable) { segmentEdit->HeaderInfoChanged( QString::fromStdString(segment->GetShortDesc())); return; } if (!handleCustomLabelRename(segmentEdit)) { segment->SetUseCustomLabel(false); } } static void setupSegmentLabelContextMenuEntries(MacroSegmentEdit *segmentEdit, QMenu &menu) { if (!segmentEdit) { return; } auto segment = segmentEdit ? segmentEdit->Data() : nullptr; const bool customLabelIsEnabled = segment && segment->GetUseCustomLabel(); auto enableCustomLabel = menu.addAction(obs_module_text( "AdvSceneSwitcher.macroTab.segment.useCustomLabel")); enableCustomLabel->setCheckable(true); enableCustomLabel->setChecked(customLabelIsEnabled); QWidget::connect(enableCustomLabel, &QAction::triggered, [segmentEdit, enableCustomLabel]() { handleCustomLabelEnableChange( segmentEdit, enableCustomLabel); }); if (!customLabelIsEnabled) { return; } auto customLabelRename = menu.addAction(obs_module_text( "AdvSceneSwitcher.macroTab.segment.customLabelRename")); QWidget::connect(customLabelRename, &QAction::triggered, [segmentEdit]() { handleCustomLabelRename(segmentEdit); }); } void MacroEdit::SetupContextMenu( const QPoint &pos, const std::function &remove, const std::function &expand, const std::function &collapse, const std::function &maximize, const std::function &minimize, MacroSegmentList *list) { QMenu menu; auto segmentEdit = list->WidgetAt(pos); setupCopyPasteContextMenuEnry(this, ui->macroActions, ui->macroElseActions, segmentEdit, menu); menu.addSeparator(); setupRemoveContextMenuEnry(this, remove, pos, list, menu); menu.addSeparator(); setupSegmentLabelContextMenuEntries(segmentEdit, menu); menu.addSeparator(); menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.expandAll"), this, [this, expand]() { expand(this); }); menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.collapseAll"), this, [this, collapse]() { collapse(this); }); menu.addSeparator(); menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.maximize"), this, [this, maximize]() { maximize(this); }); menu.addAction(obs_module_text("AdvSceneSwitcher.macroTab.minimize"), this, [this, minimize]() { minimize(this); }); menu.exec(list->mapToGlobal(pos)); } void MacroEdit::ShowMacroActionsContextMenu(const QPoint &pos) { SetupContextMenu(pos, &MacroEdit::RemoveMacroAction, &MacroEdit::ExpandAllActions, &MacroEdit::CollapseAllActions, &MacroEdit::MaximizeActions, &MacroEdit::MinimizeActions, ui->actionsList); } void MacroEdit::ShowMacroElseActionsContextMenu(const QPoint &pos) { SetupContextMenu(pos, &MacroEdit::RemoveMacroElseAction, &MacroEdit::ExpandAllElseActions, &MacroEdit::CollapseAllElseActions, &MacroEdit::MaximizeElseActions, &MacroEdit::MinimizeElseActions, ui->elseActionsList); } void MacroEdit::ShowMacroConditionsContextMenu(const QPoint &pos) { SetupContextMenu(pos, &MacroEdit::RemoveMacroCondition, &MacroEdit::ExpandAllConditions, &MacroEdit::CollapseAllConditions, &MacroEdit::MaximizeConditions, &MacroEdit::MinimizeConditions, ui->conditionsList); } void MacroEdit::UpMacroSegmentHotkey() { if (!MacroTabIsInFocus()) { return; } auto macro = _currentMacro; if (!macro) { return; } int actionSize = macro->Actions().size(); int conditionSize = macro->Conditions().size(); if (currentActionIdx == -1 && currentConditionIdx == -1) { if (lastInteracted == MacroSection::CONDITIONS) { if (conditionSize == 0) { MacroActionSelectionChanged(0); } else { MacroConditionSelectionChanged(0); } } else { if (actionSize == 0) { MacroConditionSelectionChanged(0); } else { MacroActionSelectionChanged(0); } } return; } if (currentActionIdx > 0) { MacroActionSelectionChanged(currentActionIdx - 1); return; } if (currentConditionIdx > 0) { MacroConditionSelectionChanged(currentConditionIdx - 1); return; } if (currentActionIdx == 0) { if (conditionSize == 0) { MacroActionSelectionChanged(actionSize - 1); } else { MacroConditionSelectionChanged(conditionSize - 1); } return; } if (currentConditionIdx == 0) { if (actionSize == 0) { MacroConditionSelectionChanged(conditionSize - 1); } else { MacroActionSelectionChanged(actionSize - 1); } return; } } void MacroEdit::DownMacroSegmentHotkey() { if (!MacroTabIsInFocus()) { return; } auto macro = _currentMacro; if (!macro) { return; } int actionSize = macro->Actions().size(); int conditionSize = macro->Conditions().size(); if (currentActionIdx == -1 && currentConditionIdx == -1) { if (lastInteracted == MacroSection::CONDITIONS) { if (conditionSize == 0) { MacroActionSelectionChanged(0); } else { MacroConditionSelectionChanged(0); } } else { if (actionSize == 0) { MacroConditionSelectionChanged(0); } else { MacroActionSelectionChanged(0); } } return; } if (currentActionIdx < actionSize - 1) { MacroActionSelectionChanged(currentActionIdx + 1); return; } if (currentConditionIdx < conditionSize - 1) { MacroConditionSelectionChanged(currentConditionIdx + 1); return; } if (currentActionIdx == actionSize - 1) { if (conditionSize == 0) { MacroActionSelectionChanged(0); } else { MacroConditionSelectionChanged(0); } return; } if (currentConditionIdx == conditionSize - 1) { if (actionSize == 0) { MacroConditionSelectionChanged(0); } else { MacroActionSelectionChanged(0); } return; } } void MacroEdit::DeleteMacroSegmentHotkey() { if (!MacroTabIsInFocus()) { return; } if (currentActionIdx != -1) { RemoveMacroAction(currentActionIdx); } else if (currentConditionIdx != -1) { RemoveMacroCondition(currentConditionIdx); } } void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id, obs_data_t *data) { if (idx < 0 || idx > (int)macro->Actions().size()) { assert(false); return; } { auto lock = LockContext(); macro->Actions().emplace(macro->Actions().begin() + idx, MacroActionFactory::Create(id, macro)); if (data) { macro->Actions().at(idx)->Load(data); } macro->Actions().at(idx)->PostLoad(); RunAndClearPostLoadSteps(); macro->UpdateActionIndices(); ui->actionsList->Insert( idx, new MacroActionEdit(this, ¯o->Actions()[idx])); SetActionData(*macro); } HighlightAction(idx); ui->actionsList->SetHelpMsgVisible(false); emit(MacroSegmentOrderChanged()); } void MacroEdit::AddMacroAction(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx > (int)macro->Actions().size()) { assert(false); return; } std::string id; if (idx - 1 >= 0) { id = macro->Actions().at(idx - 1)->GetId(); } else { id = MacroAction::GetDefaultID(); } OBSDataAutoRelease data; if (idx - 1 >= 0) { data = obs_data_create(); macro->Actions().at(idx - 1)->Save(data); } AddMacroAction(macro.get(), idx, id, data); } void MacroEdit::on_actionAdd_clicked() { auto macro = _currentMacro; if (!macro) { return; } if (currentActionIdx == -1) { AddMacroAction((int)macro->Actions().size()); } else { AddMacroAction(currentActionIdx + 1); } if (currentActionIdx != -1) { MacroActionSelectionChanged(currentActionIdx + 1); } } void MacroEdit::RemoveMacroAction(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx >= (int)macro->Actions().size()) { return; } { auto lock = LockContext(); ui->actionsList->Remove(idx); macro->Actions().erase(macro->Actions().begin() + idx); SetMacroAbortWait(true); GetMacroWaitCV().notify_all(); macro->UpdateActionIndices(); SetActionData(*macro); } MacroActionSelectionChanged(-1); lastInteracted = MacroSection::ACTIONS; emit(MacroSegmentOrderChanged()); } void MacroEdit::on_actionRemove_clicked() { if (currentActionIdx == -1) { auto macro = _currentMacro; if (!macro) { return; } RemoveMacroAction((int)macro->Actions().size() - 1); } else { RemoveMacroAction(currentActionIdx); } MacroActionSelectionChanged(-1); } void MacroEdit::on_actionTop_clicked() { if (currentActionIdx == -1) { return; } MacroActionReorder(0, currentActionIdx); MacroActionSelectionChanged(0); } void MacroEdit::on_actionUp_clicked() { if (currentActionIdx == -1 || currentActionIdx == 0) { return; } MoveMacroActionUp(currentActionIdx); MacroActionSelectionChanged(currentActionIdx - 1); } void MacroEdit::on_actionDown_clicked() { if (currentActionIdx == -1 || currentActionIdx == ui->actionsList->ContentLayout()->count() - 1) { return; } MoveMacroActionDown(currentActionIdx); MacroActionSelectionChanged(currentActionIdx + 1); } void MacroEdit::on_actionBottom_clicked() { if (currentActionIdx == -1) { return; } const int newIdx = ui->actionsList->ContentLayout()->count() - 1; MacroActionReorder(newIdx, currentActionIdx); MacroActionSelectionChanged(newIdx); } void MacroEdit::on_elseActionAdd_clicked() { auto macro = _currentMacro; if (!macro) { return; } if (currentElseActionIdx == -1) { AddMacroElseAction((int)macro->ElseActions().size()); } else { AddMacroElseAction(currentElseActionIdx + 1); } if (currentElseActionIdx != -1) { MacroElseActionSelectionChanged(currentElseActionIdx + 1); } } void MacroEdit::on_elseActionRemove_clicked() { if (currentElseActionIdx == -1) { auto macro = _currentMacro; if (!macro) { return; } RemoveMacroElseAction((int)macro->ElseActions().size() - 1); } else { RemoveMacroElseAction(currentElseActionIdx); } MacroElseActionSelectionChanged(-1); } void MacroEdit::on_elseActionTop_clicked() { if (currentElseActionIdx == -1) { return; } MacroElseActionReorder(0, currentElseActionIdx); MacroElseActionSelectionChanged(0); } void MacroEdit::on_elseActionUp_clicked() { if (currentElseActionIdx == -1 || currentElseActionIdx == 0) { return; } MoveMacroElseActionUp(currentElseActionIdx); MacroElseActionSelectionChanged(currentElseActionIdx - 1); } void MacroEdit::on_elseActionDown_clicked() { if (currentElseActionIdx == -1 || currentElseActionIdx == ui->elseActionsList->ContentLayout()->count() - 1) { return; } MoveMacroElseActionDown(currentElseActionIdx); MacroElseActionSelectionChanged(currentElseActionIdx + 1); } void MacroEdit::on_elseActionBottom_clicked() { if (currentElseActionIdx == -1) { return; } const int newIdx = ui->elseActionsList->ContentLayout()->count() - 1; MacroElseActionReorder(newIdx, currentElseActionIdx); MacroElseActionSelectionChanged(newIdx); } void MacroEdit::SwapActions(Macro *m, int pos1, int pos2) { if (pos1 == pos2) { return; } if (pos1 > pos2) { std::swap(pos1, pos2); } auto lock = LockContext(); iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2); m->UpdateActionIndices(); auto widget1 = static_cast( ui->actionsList->ContentLayout()->takeAt(pos1)->widget()); auto widget2 = static_cast( ui->actionsList->ContentLayout()->takeAt(pos2 - 1)->widget()); ui->actionsList->Insert(pos1, widget2); ui->actionsList->Insert(pos2, widget1); SetActionData(*m); emit(MacroSegmentOrderChanged()); } void MacroEdit::MoveMacroActionUp(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 1 || idx >= (int)macro->Actions().size()) { return; } SwapActions(macro.get(), idx, idx - 1); HighlightAction(idx - 1); } void MacroEdit::MoveMacroActionDown(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx >= (int)macro->Actions().size() - 1) { return; } SwapActions(macro.get(), idx, idx + 1); HighlightAction(idx + 1); } void MacroEdit::MacroElseActionSelectionChanged(int idx) { SetupMacroSegmentSelection(MacroSection::ELSE_ACTIONS, idx); } void MacroEdit::MacroElseActionReorder(int to, int from) { auto macro = _currentMacro; if (!macro) { return; } if (to == from || from < 0 || from > (int)macro->ElseActions().size() || to < 0 || to > (int)macro->ElseActions().size()) { return; } { auto lock = LockContext(); 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 MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id, obs_data_t *data) { if (idx < 0 || idx > (int)macro->ElseActions().size()) { assert(false); return; } { auto lock = LockContext(); macro->ElseActions().emplace(macro->ElseActions().begin() + idx, MacroActionFactory::Create(id, macro)); if (data) { macro->ElseActions().at(idx)->Load(data); } macro->ElseActions().at(idx)->PostLoad(); RunAndClearPostLoadSteps(); macro->UpdateElseActionIndices(); ui->elseActionsList->Insert( idx, new MacroActionEdit(this, ¯o->ElseActions()[idx])); SetElseActionData(*macro); } HighlightElseAction(idx); ui->elseActionsList->SetHelpMsgVisible(false); emit(MacroSegmentOrderChanged()); } void MacroEdit::AddMacroElseAction(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx > (int)macro->ElseActions().size()) { assert(false); return; } std::string id; if (idx - 1 >= 0) { id = macro->ElseActions().at(idx - 1)->GetId(); } else { id = MacroAction::GetDefaultID(); } OBSDataAutoRelease data; if (idx - 1 >= 0) { data = obs_data_create(); macro->ElseActions().at(idx - 1)->Save(data); } AddMacroElseAction(macro.get(), idx, id, data); } void MacroEdit::RemoveMacroElseAction(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx >= (int)macro->ElseActions().size()) { return; } { auto lock = LockContext(); ui->elseActionsList->Remove(idx); macro->ElseActions().erase(macro->ElseActions().begin() + idx); SetMacroAbortWait(true); GetMacroWaitCV().notify_all(); macro->UpdateElseActionIndices(); SetElseActionData(*macro); } MacroElseActionSelectionChanged(-1); lastInteracted = MacroSection::ELSE_ACTIONS; emit(MacroSegmentOrderChanged()); } void MacroEdit::SwapElseActions(Macro *m, int pos1, int pos2) { if (pos1 == pos2) { return; } if (pos1 > pos2) { std::swap(pos1, pos2); } auto lock = LockContext(); 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 MacroEdit::MoveMacroElseActionUp(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 1 || idx >= (int)macro->ElseActions().size()) { return; } SwapElseActions(macro.get(), idx, idx - 1); HighlightElseAction(idx - 1); } void MacroEdit::MoveMacroElseActionDown(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx >= (int)macro->ElseActions().size() - 1) { return; } SwapElseActions(macro.get(), idx, idx + 1); HighlightElseAction(idx + 1); } void MacroEdit::MacroActionSelectionChanged(int idx) { SetupMacroSegmentSelection(MacroSection::ACTIONS, idx); } void MacroEdit::MacroActionReorder(int to, int from) { auto macro = _currentMacro; if (!macro) { return; } if (to == from || from < 0 || from > (int)macro->Actions().size() || to < 0 || to > (int)macro->Actions().size()) { return; } { auto lock = LockContext(); auto action = macro->Actions().at(from); macro->Actions().erase(macro->Actions().begin() + from); macro->Actions().insert(macro->Actions().begin() + to, action); macro->UpdateActionIndices(); ui->actionsList->ContentLayout()->insertItem( to, ui->actionsList->ContentLayout()->takeAt(from)); SetActionData(*macro); } HighlightAction(to); emit(MacroSegmentOrderChanged()); } void MacroEdit::AddMacroCondition(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx > (int)macro->Conditions().size()) { assert(false); return; } std::string id; Logic::Type logic; if (idx >= 1) { id = macro->Conditions().at(idx - 1)->GetId(); if (idx == 1) { logic = Logic::Type::OR; } else { logic = macro->Conditions().at(idx - 1)->GetLogicType(); } } else { id = MacroCondition::GetDefaultID(); logic = Logic::Type::ROOT_NONE; } OBSDataAutoRelease data; if (idx - 1 >= 0) { data = obs_data_create(); macro->Conditions().at(idx - 1)->Save(data); } AddMacroCondition(macro.get(), idx, id, data.Get(), logic); } void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id, obs_data_t *data, Logic::Type logic) { if (idx < 0 || idx > (int)macro->Conditions().size()) { assert(false); return; } { auto lock = LockContext(); auto cond = macro->Conditions().emplace( macro->Conditions().begin() + idx, MacroConditionFactory::Create(id, macro)); if (data) { macro->Conditions().at(idx)->Load(data); } macro->Conditions().at(idx)->PostLoad(); RunAndClearPostLoadSteps(); (*cond)->SetLogicType(logic); macro->UpdateConditionIndices(); ui->conditionsList->Insert( idx, new MacroConditionEdit(this, ¯o->Conditions()[idx], idx == 0)); SetConditionData(*macro); } HighlightCondition(idx); ui->conditionsList->SetHelpMsgVisible(false); emit(MacroSegmentOrderChanged()); } void MacroEdit::on_conditionAdd_clicked() { auto macro = _currentMacro; if (!macro) { return; } if (currentConditionIdx == -1) { AddMacroCondition((int)macro->Conditions().size()); } else { AddMacroCondition(currentConditionIdx + 1); } if (currentConditionIdx != -1) { MacroConditionSelectionChanged(currentConditionIdx + 1); } } void MacroEdit::RemoveMacroCondition(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx >= (int)macro->Conditions().size()) { return; } { auto lock = LockContext(); ui->conditionsList->Remove(idx); macro->Conditions().erase(macro->Conditions().begin() + idx); macro->UpdateConditionIndices(); if (idx == 0 && macro->Conditions().size() > 0) { auto newRoot = macro->Conditions().at(0); newRoot->SetLogicType(Logic::Type::ROOT_NONE); static_cast( ui->conditionsList->WidgetAt(0)) ->SetRootNode(true); } SetConditionData(*macro); } MacroConditionSelectionChanged(-1); lastInteracted = MacroSection::CONDITIONS; emit(MacroSegmentOrderChanged()); } void MacroEdit::on_conditionRemove_clicked() { if (currentConditionIdx == -1) { auto macro = _currentMacro; if (!macro) { return; } RemoveMacroCondition((int)macro->Conditions().size() - 1); } else { RemoveMacroCondition(currentConditionIdx); } MacroConditionSelectionChanged(-1); } void MacroEdit::on_conditionTop_clicked() { if (currentConditionIdx == -1) { return; } MacroConditionReorder(0, currentConditionIdx); MacroConditionSelectionChanged(0); } void MacroEdit::on_conditionUp_clicked() { if (currentConditionIdx == -1 || currentConditionIdx == 0) { return; } MoveMacroConditionUp(currentConditionIdx); MacroConditionSelectionChanged(currentConditionIdx - 1); } void MacroEdit::on_conditionDown_clicked() { if (currentConditionIdx == -1 || currentConditionIdx == ui->conditionsList->ContentLayout()->count() - 1) { return; } MoveMacroConditionDown(currentConditionIdx); MacroConditionSelectionChanged(currentConditionIdx + 1); } void MacroEdit::on_conditionBottom_clicked() { if (currentConditionIdx == -1) { return; } const int newIdx = ui->conditionsList->ContentLayout()->count() - 1; MacroConditionReorder(newIdx, currentConditionIdx); MacroConditionSelectionChanged(newIdx); } void MacroEdit::SwapConditions(Macro *m, int pos1, int pos2) { if (pos1 == pos2) { return; } if (pos1 > pos2) { std::swap(pos1, pos2); } bool root = pos1 == 0; auto lock = LockContext(); 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( ui->conditionsList->ContentLayout()->takeAt(pos1)->widget()); auto widget2 = static_cast( ui->conditionsList->ContentLayout()->takeAt(pos2 - 1)->widget()); ui->conditionsList->Insert(pos1, widget2); ui->conditionsList->Insert(pos2, widget1); SetConditionData(*m); widget2->SetRootNode(root); widget1->SetRootNode(false); emit(MacroSegmentOrderChanged()); } void MacroEdit::MoveMacroConditionUp(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 1 || idx >= (int)macro->Conditions().size()) { return; } SwapConditions(macro.get(), idx, idx - 1); HighlightCondition(idx - 1); } void MacroEdit::MoveMacroConditionDown(int idx) { auto macro = _currentMacro; if (!macro) { return; } if (idx < 0 || idx >= (int)macro->Conditions().size() - 1) { return; } SwapConditions(macro.get(), idx, idx + 1); HighlightCondition(idx + 1); } void MacroEdit::MacroConditionSelectionChanged(int idx) { SetupMacroSegmentSelection(MacroSection::CONDITIONS, idx); } void MacroEdit::MacroConditionReorder(int to, int from) { auto macro = _currentMacro; if (!macro) { return; } if (to == from || from < 0 || from > (int)macro->Conditions().size() || to < 0 || to > (int)macro->Conditions().size()) { return; } { auto lock = LockContext(); auto condition = macro->Conditions().at(from); if (to == 0) { condition->SetLogicType(Logic::Type::ROOT_NONE); static_cast( ui->conditionsList->WidgetAt(from)) ->SetRootNode(true); macro->Conditions().at(0)->SetLogicType( Logic::Type::AND); static_cast( ui->conditionsList->WidgetAt(0)) ->SetRootNode(false); } if (from == 0) { condition->SetLogicType(Logic::Type::AND); static_cast( ui->conditionsList->WidgetAt(from)) ->SetRootNode(false); macro->Conditions().at(1)->SetLogicType( Logic::Type::ROOT_NONE); static_cast( ui->conditionsList->WidgetAt(1)) ->SetRootNode(true); } macro->Conditions().erase(macro->Conditions().begin() + from); macro->Conditions().insert(macro->Conditions().begin() + to, condition); macro->UpdateConditionIndices(); ui->conditionsList->ContentLayout()->insertItem( to, ui->conditionsList->ContentLayout()->takeAt(from)); SetConditionData(*macro); } HighlightCondition(to); emit(MacroSegmentOrderChanged()); } bool MacroEdit::IsEmpty() const { if (!_currentMacro) { return true; } return ui->conditionsList->IsEmpty() && ui->actionsList->IsEmpty() && ui->elseActionsList->IsEmpty(); } void MacroEdit::ShowAllMacroSections() { if (!ElseSectionIsVisible()) { on_toggleElseActions_clicked(); } SetSplitterPositionByFraction(ui->macroActionConditionSplitter, 0.3); CenterSplitterPosition(ui->macroElseActionSplitter); adjustSize(); updateGeometry(); } } // namespace advss