type undo / redo

This commit is contained in:
WarmUpTill
2026-08-25 22:50:46 +02:00
parent 151f69305b
commit 0ea98073d7
5 changed files with 174 additions and 0 deletions

View File

@@ -203,6 +203,7 @@ AdvSceneSwitcher.undo.addMacro="Add Macro '%1'"
AdvSceneSwitcher.undo.removeMacro="Remove Macro '%1'"
AdvSceneSwitcher.undo.addSegment="Add %1 in '%2'"
AdvSceneSwitcher.undo.removeSegment="Remove %1 in '%2'"
AdvSceneSwitcher.undo.changeSegmentType="Change %1 Type in '%2'"
AdvSceneSwitcher.undo.groupMacros="Group Macros '%1'"
AdvSceneSwitcher.undo.ungroupMacros="Ungroup Macros '%1'"
AdvSceneSwitcher.undo.removeMacroGroup="Remove Macro Group '%1'"

View File

@@ -1,4 +1,5 @@
#include "macro-action-edit.hpp"
#include "macro-undo-redo.hpp"
#include "advanced-scene-switcher.hpp"
#include "macro-helpers.hpp"
#include "macro-settings.hpp"
@@ -111,9 +112,24 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
return;
}
const std::string oldId = (*_entryData)->GetId();
OBSDataAutoRelease oldData = obs_data_create();
(*_entryData)->Save(oldData);
HeaderInfoChanged("");
auto idx = _entryData->get()->GetIndex();
auto macro = _entryData->get()->GetMacro();
// Determine whether this is an action or else-action before resetting.
const auto *rawPtr = (*_entryData).get();
const auto &elseActions = macro->ElseActions();
const bool isElse = std::any_of(elseActions.begin(), elseActions.end(),
[rawPtr](const auto &a) {
return a.get() == rawPtr;
});
const auto segmentType = isElse ? MacroEdit::SegmentType::ELSE_ACTION
: MacroEdit::SegmentType::ACTION;
{
auto lock = LockContext();
_entryData->reset();
@@ -122,6 +138,11 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
(*_entryData)->PostLoad();
RunAndClearPostLoadSteps();
}
OBSDataAutoRelease newData = obs_data_create();
(*_entryData)->Save(newData);
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 &)));

View File

@@ -1,4 +1,5 @@
#include "macro-condition-edit.hpp"
#include "macro-undo-redo.hpp"
#include "advanced-scene-switcher.hpp"
#include "condition-logic.hpp"
@@ -250,6 +251,11 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
return;
}
const std::string oldId = (*_entryData)->GetId();
const int oldLogic = (int)(*_entryData)->GetLogicType();
OBSDataAutoRelease oldData = obs_data_create();
(*_entryData)->Save(oldData);
auto temp = DurationModifier();
_dur->SetValue(temp);
HeaderInfoChanged("");
@@ -267,6 +273,12 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
(*_entryData)->PostLoad();
RunAndClearPostLoadSteps();
}
OBSDataAutoRelease newData = obs_data_create();
(*_entryData)->Save(newData);
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 &)),

View File

@@ -534,6 +534,102 @@ static void addSegmentFromData(const char *jsonData)
}
}
// ---------------------------------------------------------------------------
// Segment type-change undo/redo callback
// ---------------------------------------------------------------------------
// Same data format as addSegmentFromData:
// {"macro": "Name", "type": N, "index": N, "id": "...", "logic": N,
// "segment": {...}}
static void replaceSegmentFromData(const char *jsonData)
{
OBSDataAutoRelease data = obs_data_create_from_json(jsonData);
if (!data) {
return;
}
const std::string macroName = obs_data_get_string(data, "macro");
const int type = (int)obs_data_get_int(data, "type");
const int index = (int)obs_data_get_int(data, "index");
const std::string id = obs_data_get_string(data, "id");
const int logic = (int)obs_data_get_int(data, "logic");
OBSDataAutoRelease segData = obs_data_get_obj(data, "segment");
const auto macro = GetWeakMacroByName(macroName.c_str()).lock();
if (!macro) {
return;
}
{
auto lock = LockContext();
switch ((SegmentType)type) {
case SegmentType::ACTION: {
if (index < 0 ||
index >= (int)macro->Actions().size()) {
break;
}
macro->Actions().erase(macro->Actions().begin() +
index);
macro->Actions().emplace(
macro->Actions().begin() + index,
MacroActionFactory::Create(id, macro.get()));
if (segData) {
macro->Actions().at(index)->Load(segData);
}
macro->Actions().at(index)->PostLoad();
RunAndClearPostLoadSteps();
macro->UpdateActionIndices();
break;
}
case SegmentType::ELSE_ACTION: {
if (index < 0 ||
index >= (int)macro->ElseActions().size()) {
break;
}
macro->ElseActions().erase(
macro->ElseActions().begin() + index);
macro->ElseActions().emplace(
macro->ElseActions().begin() + index,
MacroActionFactory::Create(id, macro.get()));
if (segData) {
macro->ElseActions().at(index)->Load(segData);
}
macro->ElseActions().at(index)->PostLoad();
RunAndClearPostLoadSteps();
macro->UpdateElseActionIndices();
break;
}
case SegmentType::CONDITION: {
if (index < 0 ||
index >= (int)macro->Conditions().size()) {
break;
}
macro->Conditions().erase(macro->Conditions().begin() +
index);
macro->Conditions().emplace(
macro->Conditions().begin() + index,
MacroConditionFactory::Create(id, macro.get()));
if (segData) {
macro->Conditions().at(index)->Load(segData);
}
macro->Conditions().at(index)->PostLoad();
RunAndClearPostLoadSteps();
macro->Conditions().at(index)->SetLogicType(
(Logic::Type)logic);
macro->UpdateConditionIndices();
break;
}
}
}
if (auto *window = AdvSceneSwitcher::window) {
updateMacroEditSegment(window, macroName, SegmentOp::REMOVE,
(SegmentType)type, index);
updateMacroEditSegment(window, macroName, SegmentOp::ADD,
(SegmentType)type, index);
}
}
// ---------------------------------------------------------------------------
// Rename undo/redo callback
// ---------------------------------------------------------------------------
@@ -928,4 +1024,42 @@ void RegisterMacroRenameUndoRedo(const std::string &oldName,
obs_data_get_json(redoData), false);
}
void RegisterSegmentTypeChangeUndoRedo(Macro *macro, SegmentType type,
int index, const std::string &oldId,
obs_data_t *oldData, int oldLogic,
const std::string &newId,
obs_data_t *newData, int newLogic)
{
if (!macro) {
return;
}
const std::string macroName = macro->Name();
OBSDataAutoRelease undoData = obs_data_create();
obs_data_set_string(undoData, "macro", macroName.c_str());
obs_data_set_int(undoData, "type", (int)type);
obs_data_set_int(undoData, "index", index);
obs_data_set_string(undoData, "id", oldId.c_str());
obs_data_set_int(undoData, "logic", oldLogic);
obs_data_set_obj(undoData, "segment", oldData);
OBSDataAutoRelease redoData = obs_data_create();
obs_data_set_string(redoData, "macro", macroName.c_str());
obs_data_set_int(redoData, "type", (int)type);
obs_data_set_int(redoData, "index", index);
obs_data_set_string(redoData, "id", newId.c_str());
obs_data_set_int(redoData, "logic", newLogic);
obs_data_set_obj(redoData, "segment", newData);
const std::string actionName =
fmtUndoName("AdvSceneSwitcher.undo.changeSegmentType",
segmentTypeName(type), macroName);
obs_frontend_add_undo_redo_action(actionName.c_str(),
&replaceSegmentFromData,
&replaceSegmentFromData,
obs_data_get_json(undoData),
obs_data_get_json(redoData), false);
}
} // namespace advss

View File

@@ -12,6 +12,12 @@ void RegisterMacroAddUndoRedo(const std::string &macroName);
bool RegisterMacroRemoveUndoRedo(Macro *macro);
void RegisterSegmentAddUndoRedo(Macro *macro, MacroEdit::SegmentType type,
int index);
void RegisterSegmentTypeChangeUndoRedo(Macro *macro,
MacroEdit::SegmentType type, int index,
const std::string &oldId,
obs_data_t *oldData, int oldLogic,
const std::string &newId,
obs_data_t *newData, int newLogic);
void RegisterSegmentRemoveUndoRedo(Macro *macro, MacroEdit::SegmentType type,
int index, const std::string &segmentId,
obs_data_t *segmentData, int logic);