Support nested macro groups in data model

This commit is contained in:
WarmUpTill
2026-10-21 21:12:43 +02:00
committed by WarmUpTill
parent 60e5475642
commit 1a542f8092
11 changed files with 639 additions and 252 deletions

View File

@@ -14,6 +14,7 @@
#include <QAction>
#include <QMainWindow>
#include <algorithm>
#include <chrono>
#include <limits>
#undef max
@@ -62,11 +63,23 @@ Macro::CreateGroup(const std::string &name,
{
auto group = std::make_shared<Macro>(name);
group->_registerHotkeys = false;
for (auto &c : children) {
c->SetParent(group);
}
group->_isGroup = true;
group->_groupSize = children.size();
if (!children.empty()) {
const auto parent = children.front()->Parent();
const bool haveSameParent = std::all_of(
children.begin(), children.end(),
[&parent](const std::shared_ptr<Macro> &child) {
return child->Parent() == parent;
});
if (haveSameParent) {
PrepareMoveToGroup(parent, group);
}
}
for (auto &child : children) {
PrepareMoveToGroup(group, child);
}
return group;
}
@@ -78,11 +91,11 @@ void Macro::RemoveGroup(std::shared_ptr<Macro> group)
return;
}
auto size = group->GroupSize();
for (uint32_t i = 1; i <= size; i++) {
auto m = std::next(it, i);
(*m)->SetParent(nullptr);
const auto parent = group->Parent();
for (const auto &child : GetGroupChildren(group.get())) {
child->SetParent(parent);
}
AddToGroupSizes(parent, -1);
macros.erase(it);
}
@@ -106,15 +119,72 @@ void Macro::PrepareMoveToGroup(std::shared_ptr<Macro> group,
return;
}
// Potentially remove from old group
auto oldGroup = item->Parent();
if (oldGroup) {
oldGroup->_groupSize--;
if (group &&
(group == item || IsMacroInGroup(group.get(), item.get()))) {
blog(LOG_WARNING, "cannot move \"%s\" into itself",
item->Name().c_str());
return;
}
const int count = 1 + (int)item->_groupSize;
AddToGroupSizes(item->Parent(), -count);
item->SetParent(group);
if (group) {
group->_groupSize++;
AddToGroupSizes(group, count);
}
void Macro::AddToGroupSizes(std::shared_ptr<Macro> group, int count)
{
for (; group; group = group->Parent()) {
assert((int)group->_groupSize + count >= 0);
group->_groupSize += count;
}
}
void Macro::RestoreGroupHierarchy(
const std::deque<std::shared_ptr<Macro>> &macros)
{
struct OpenGroup {
std::shared_ptr<Macro> group;
uint32_t remaining;
};
std::vector<OpenGroup> openGroups;
for (size_t i = 0; i < macros.size(); i++) {
const auto &macro = macros[i];
while (!openGroups.empty() &&
openGroups.back().remaining == 0) {
openGroups.pop_back();
}
macro->SetParent(openGroups.empty() ? nullptr
: openGroups.back().group);
for (auto &openGroup : openGroups) {
openGroup.remaining--;
}
if (!macro->IsGroup()) {
continue;
}
const auto maxSize = openGroups.empty()
? (uint32_t)(macros.size() - i - 1)
: openGroups.back().remaining;
auto size = macro->_groupSize;
if (size > maxSize) {
blog(LOG_WARNING,
"invalid group size detected for \"%s\" - "
"reducing size from %u to %u",
macro->Name().c_str(), size, maxSize);
size = maxSize;
}
openGroups.push_back({macro, size});
}
for (const auto &macro : macros) {
macro->_groupSize = 0;
}
for (const auto &macro : macros) {
AddToGroupSizes(macro->Parent(), 1);
}
}
@@ -339,8 +409,7 @@ bool Macro::PerformActions(bool match, bool forceParallel, bool ignorePause)
}
_lastExecutionTime = std::chrono::high_resolution_clock::now();
auto group = _parent.lock();
if (group) {
for (auto group = _parent.lock(); group; group = group->Parent()) {
group->_lastExecutionTime = _lastExecutionTime;
}
if (_runCount != std::numeric_limits<int>::max()) {
@@ -1250,42 +1319,10 @@ void LoadMacros(obs_data_t *obj)
}
obs_data_array_release(macroArray);
int groupCount = 0;
std::shared_ptr<Macro> group;
std::vector<std::shared_ptr<Macro>> invalidGroups;
Macro::RestoreGroupHierarchy(macros);
for (const auto &m : macros) {
if (groupCount && m->IsGroup()) {
blog(LOG_ERROR,
"nested group detected - will delete \"%s\"",
m->Name().c_str());
invalidGroups.emplace_back(m);
continue;
}
if (groupCount) {
m->SetParent(group);
groupCount--;
}
if (m->IsGroup()) {
groupCount = m->GroupSize();
group = m;
}
m->PostLoad();
}
if (groupCount) {
blog(LOG_ERROR,
"invalid group size detected - will delete \"%s\"",
group->Name().c_str());
invalidGroups.emplace_back(group);
}
for (auto &m : invalidGroups) {
auto it = std::find(macros.begin(), macros.end(), m);
if (it == macros.end()) {
continue;
}
macros.erase(it);
}
}
bool CheckMacros()