mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-08-31 13:45:36 -05:00
nested macros
This commit is contained in:
@@ -199,6 +199,7 @@ AdvSceneSwitcher.macroTab.removeSingleMacroPopup.text="Are you sure you want to
|
||||
AdvSceneSwitcher.macroTab.removeMultipleMacrosPopup.text="Are you sure you want to remove %1 macros/groups?"
|
||||
AdvSceneSwitcher.macroTab.removeGroupPopup.text="Are you sure you want to remove \"%1\" group and all its elements?"
|
||||
AdvSceneSwitcher.undo.renameMacro="Rename Macro '%1'"
|
||||
AdvSceneSwitcher.undo.modifyMacro="Modify Macro '%1'"
|
||||
AdvSceneSwitcher.undo.addMacro="Add Macro '%1'"
|
||||
AdvSceneSwitcher.undo.removeMacro="Remove Macro '%1'"
|
||||
AdvSceneSwitcher.undo.addSegment="Add %1 in '%2'"
|
||||
|
||||
@@ -112,6 +112,14 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
return;
|
||||
}
|
||||
|
||||
Macro *const parentMacro =
|
||||
(*_entryData)->GetMacro()->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
}
|
||||
|
||||
const std::string oldId = (*_entryData)->GetId();
|
||||
OBSDataAutoRelease oldData = obs_data_create();
|
||||
(*_entryData)->Save(oldData);
|
||||
@@ -141,8 +149,13 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
||||
|
||||
OBSDataAutoRelease newData = obs_data_create();
|
||||
(*_entryData)->Save(newData);
|
||||
RegisterSegmentTypeChangeUndoRedo(macro, segmentType, idx, oldId,
|
||||
oldData, 0, id, newData, 0);
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
} else {
|
||||
RegisterSegmentTypeChangeUndoRedo(macro, segmentType, idx,
|
||||
oldId, oldData, 0, id,
|
||||
newData, 0);
|
||||
}
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
this, SLOT(HeaderInfoChanged(const QString &)));
|
||||
|
||||
@@ -83,6 +83,7 @@ bool MacroActionLoop::PostLoad()
|
||||
MacroAction::PostLoad();
|
||||
_loopMacro->PostLoad();
|
||||
_loopMacro->SetActionTriggerMode(Macro::ActionTriggerMode::ALWAYS);
|
||||
_loopMacro->SetNestedParentMacro(GetMacro());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +281,7 @@ bool MacroActionMacro::PostLoad()
|
||||
MacroAction::PostLoad();
|
||||
_runOptions.macro.PostLoad();
|
||||
_nestedMacro->PostLoad();
|
||||
_nestedMacro->SetNestedParentMacro(GetMacro());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -251,6 +251,14 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
||||
return;
|
||||
}
|
||||
|
||||
Macro *const parentMacro =
|
||||
(*_entryData)->GetMacro()->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
}
|
||||
|
||||
const std::string oldId = (*_entryData)->GetId();
|
||||
const int oldLogic = (int)(*_entryData)->GetLogicType();
|
||||
OBSDataAutoRelease oldData = obs_data_create();
|
||||
@@ -276,9 +284,14 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
||||
|
||||
OBSDataAutoRelease newData = obs_data_create();
|
||||
(*_entryData)->Save(newData);
|
||||
RegisterSegmentTypeChangeUndoRedo(
|
||||
macro, MacroEdit::SegmentType::CONDITION, idx, oldId, oldData,
|
||||
oldLogic, id, newData, (int)(*_entryData)->GetLogicType());
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
} else {
|
||||
RegisterSegmentTypeChangeUndoRedo(
|
||||
macro, MacroEdit::SegmentType::CONDITION, idx, oldId,
|
||||
oldData, oldLogic, id, newData,
|
||||
(int)(*_entryData)->GetLogicType());
|
||||
}
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
|
||||
@@ -1171,6 +1171,13 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||
return;
|
||||
}
|
||||
|
||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->Actions().emplace(macro->Actions().begin() + idx,
|
||||
@@ -1185,7 +1192,11 @@ void MacroEdit::AddMacroAction(Macro *macro, int idx, const std::string &id,
|
||||
idx, new MacroActionEdit(this, ¯o->Actions()[idx]));
|
||||
SetActionData(*macro);
|
||||
}
|
||||
RegisterSegmentAddUndoRedo(macro, SegmentType::ACTION, idx);
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
} else {
|
||||
RegisterSegmentAddUndoRedo(macro, SegmentType::ACTION, idx);
|
||||
}
|
||||
HighlightAction(idx);
|
||||
ui->actionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
@@ -1251,7 +1262,12 @@ void MacroEdit::RemoveMacroAction(int idx)
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
} else {
|
||||
OBSDataAutoRelease segData = obs_data_create();
|
||||
std::string segId;
|
||||
{
|
||||
@@ -1273,6 +1289,9 @@ void MacroEdit::RemoveMacroAction(int idx)
|
||||
macro->UpdateActionIndices();
|
||||
SetActionData(*macro);
|
||||
}
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
}
|
||||
MacroActionSelectionChanged(-1);
|
||||
lastInteracted = SegmentType::ACTION;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
@@ -1491,6 +1510,13 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||
return;
|
||||
}
|
||||
|
||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
macro->ElseActions().emplace(macro->ElseActions().begin() + idx,
|
||||
@@ -1507,7 +1533,12 @@ void MacroEdit::AddMacroElseAction(Macro *macro, int idx, const std::string &id,
|
||||
new MacroActionEdit(this, ¯o->ElseActions()[idx]));
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
RegisterSegmentAddUndoRedo(macro, SegmentType::ELSE_ACTION, idx);
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
} else {
|
||||
RegisterSegmentAddUndoRedo(macro, SegmentType::ELSE_ACTION,
|
||||
idx);
|
||||
}
|
||||
HighlightElseAction(idx);
|
||||
ui->elseActionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
@@ -1557,7 +1588,12 @@ void MacroEdit::RemoveMacroElseAction(int idx)
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
} else {
|
||||
OBSDataAutoRelease segData = obs_data_create();
|
||||
std::string segId;
|
||||
{
|
||||
@@ -1580,6 +1616,9 @@ void MacroEdit::RemoveMacroElseAction(int idx)
|
||||
macro->UpdateElseActionIndices();
|
||||
SetElseActionData(*macro);
|
||||
}
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
}
|
||||
MacroElseActionSelectionChanged(-1);
|
||||
lastInteracted = SegmentType::ELSE_ACTION;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
@@ -1715,6 +1754,13 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
return;
|
||||
}
|
||||
|
||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
auto cond = macro->Conditions().emplace(
|
||||
@@ -1733,7 +1779,11 @@ void MacroEdit::AddMacroCondition(Macro *macro, int idx, const std::string &id,
|
||||
idx == 0));
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
RegisterSegmentAddUndoRedo(macro, SegmentType::CONDITION, idx);
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
} else {
|
||||
RegisterSegmentAddUndoRedo(macro, SegmentType::CONDITION, idx);
|
||||
}
|
||||
HighlightCondition(idx);
|
||||
ui->conditionsList->SetHelpMsgVisible(false);
|
||||
emit(MacroSegmentOrderChanged());
|
||||
@@ -1769,7 +1819,12 @@ void MacroEdit::RemoveMacroCondition(int idx)
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
Macro *const parentMacro = macro->GetNestedParentMacro();
|
||||
OBSDataAutoRelease parentBeforeData;
|
||||
if (parentMacro) {
|
||||
parentBeforeData = obs_data_create();
|
||||
parentMacro->Save(parentBeforeData);
|
||||
} else {
|
||||
OBSDataAutoRelease segData = obs_data_create();
|
||||
std::string segId;
|
||||
int logic;
|
||||
@@ -1798,6 +1853,9 @@ void MacroEdit::RemoveMacroCondition(int idx)
|
||||
}
|
||||
SetConditionData(*macro);
|
||||
}
|
||||
if (parentMacro) {
|
||||
RegisterMacroModifyUndoRedo(parentMacro, parentBeforeData);
|
||||
}
|
||||
MacroConditionSelectionChanged(-1);
|
||||
lastInteracted = SegmentType::CONDITION;
|
||||
emit(MacroSegmentOrderChanged());
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <obs-frontend-api.h>
|
||||
#include <obs.hpp>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
|
||||
namespace advss {
|
||||
@@ -630,6 +631,78 @@ static void replaceSegmentFromData(const char *jsonData)
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Macro state restore callback (for nested macro edits)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Callback data format: {"name": "MacroName", "macro": {...}}
|
||||
static void restoreMacroStateFromData(const char *jsonData)
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create_from_json(jsonData);
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string macroName = obs_data_get_string(data, "name");
|
||||
OBSDataAutoRelease macroData = obs_data_get_obj(data, "macro");
|
||||
if (!macroData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto macro = GetWeakMacroByName(macroName.c_str()).lock();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *const window = AdvSceneSwitcher::window;
|
||||
const bool uiVisible = SettingsWindowIsOpened() && window;
|
||||
auto *const macroEdit = uiVisible ? window->ui->macroEdit : nullptr;
|
||||
const bool isCurrent = macroEdit && macroEdit->GetMacro() &&
|
||||
macroEdit->GetMacro()->Name() == macroName;
|
||||
|
||||
// Clear widgets while data is still valid; also saves splitter positions.
|
||||
if (isCurrent) {
|
||||
MacroSegmentList::SetCachingEnabled(false);
|
||||
macroEdit->SetMacro({});
|
||||
}
|
||||
|
||||
// Preserve splitter positions: Load() overwrites them with snapshot values.
|
||||
const QList<int> savedCondSplitter =
|
||||
macro->GetActionConditionSplitterPosition();
|
||||
const QList<int> savedElseSplitter =
|
||||
macro->GetElseActionSplitterPosition();
|
||||
|
||||
// Destroy deleteLater()-queued widgets now so their timers cannot fire
|
||||
// with a dangling _entryData after the deques are cleared below.
|
||||
QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
|
||||
|
||||
if (isCurrent) {
|
||||
MacroSegmentList::SetCachingEnabled(true);
|
||||
}
|
||||
|
||||
{
|
||||
auto lock = LockContext();
|
||||
// Load() appends; clear first to avoid duplicate segments.
|
||||
macro->Conditions().clear();
|
||||
macro->Actions().clear();
|
||||
macro->ElseActions().clear();
|
||||
macro->Load(macroData);
|
||||
macro->PostLoad();
|
||||
RunAndClearPostLoadSteps();
|
||||
}
|
||||
|
||||
if (isCurrent) {
|
||||
if (!savedCondSplitter.isEmpty()) {
|
||||
macro->SetActionConditionSplitterPosition(
|
||||
savedCondSplitter);
|
||||
}
|
||||
if (!savedElseSplitter.isEmpty()) {
|
||||
macro->SetElseActionSplitterPosition(savedElseSplitter);
|
||||
}
|
||||
macroEdit->SetMacro(macro);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Rename undo/redo callback
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -1062,4 +1135,32 @@ void RegisterSegmentTypeChangeUndoRedo(Macro *macro, SegmentType type,
|
||||
obs_data_get_json(redoData), false);
|
||||
}
|
||||
|
||||
void RegisterMacroModifyUndoRedo(Macro *parentMacro, obs_data_t *beforeData)
|
||||
{
|
||||
if (!parentMacro || !beforeData) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string macroName = parentMacro->Name();
|
||||
|
||||
OBSDataAutoRelease afterMacroData = obs_data_create();
|
||||
parentMacro->Save(afterMacroData);
|
||||
|
||||
OBSDataAutoRelease undoData = obs_data_create();
|
||||
obs_data_set_string(undoData, "name", macroName.c_str());
|
||||
obs_data_set_obj(undoData, "macro", beforeData);
|
||||
|
||||
OBSDataAutoRelease redoData = obs_data_create();
|
||||
obs_data_set_string(redoData, "name", macroName.c_str());
|
||||
obs_data_set_obj(redoData, "macro", afterMacroData);
|
||||
|
||||
const std::string actionName =
|
||||
fmtUndoName("AdvSceneSwitcher.undo.modifyMacro", macroName);
|
||||
obs_frontend_add_undo_redo_action(actionName.c_str(),
|
||||
&restoreMacroStateFromData,
|
||||
&restoreMacroStateFromData,
|
||||
obs_data_get_json(undoData),
|
||||
obs_data_get_json(redoData), false);
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -26,5 +26,6 @@ void RegisterMacroRenameUndoRedo(const std::string &oldName,
|
||||
void RegisterGroupCreateUndoRedo(const std::string &groupName);
|
||||
void RegisterGroupRemoveUndoRedo(const std::string &groupName);
|
||||
void RegisterGroupDeleteUndoRedo(Macro *macro);
|
||||
void RegisterMacroModifyUndoRedo(Macro *parentMacro, obs_data_t *beforeData);
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -130,6 +130,13 @@ public:
|
||||
void SetParent(std::shared_ptr<Macro> m) { _parent = m; }
|
||||
std::shared_ptr<Macro> Parent() const;
|
||||
|
||||
// For nested macros embedded in actions (e.g. loop, nested-macro action)
|
||||
void SetNestedParentMacro(Macro *parent)
|
||||
{
|
||||
_nestedParentMacro = parent;
|
||||
}
|
||||
Macro *GetNestedParentMacro() const { return _nestedParentMacro; }
|
||||
|
||||
// Saving and loading
|
||||
bool Save(obs_data_t *obj, bool saveForCopy = false) const;
|
||||
bool Load(obs_data_t *obj);
|
||||
@@ -187,6 +194,7 @@ private:
|
||||
std::deque<std::shared_ptr<MacroAction>> _elseActions;
|
||||
|
||||
std::weak_ptr<Macro> _parent;
|
||||
Macro *_nestedParentMacro = nullptr;
|
||||
uint32_t _groupSize = 0;
|
||||
bool _isGroup = false;
|
||||
bool _isCollapsed = false;
|
||||
|
||||
Reference in New Issue
Block a user