Handle macro control signals

This commit is contained in:
WarmUpTill 2021-07-17 17:28:10 +02:00 committed by WarmUpTill
parent d541356fd3
commit 3fc82df278
10 changed files with 450 additions and 53 deletions

View File

@ -14,6 +14,8 @@
}
class QCloseEvent;
class MacroActionEdit;
class MacroConditionEdit;
/*******************************************************************************
* Advanced Scene Switcher window
@ -47,6 +49,10 @@ public:
bool addNewMacro(std::string &name);
Macro *getSelectedMacro();
void SetEditMacro(Macro &m);
void ConnectControlSignals(MacroActionEdit *);
void ConnectControlSignals(MacroConditionEdit *);
void SwapActions(Macro *m, int pos1, int pos2);
void SwapConditions(Macro *m, int pos1, int pos2);
void loadUI();
void setupGeneralTab();
@ -111,6 +117,14 @@ public slots:
void on_actionRemove_clicked();
void showMacroContextMenu(const QPoint &);
void copyMacro();
void AddMacroAction(int idx);
void RemoveMacroAction(int idx);
void MoveMacroActionUp(int idx);
void MoveMacroActionDown(int idx);
void AddMacroCondition(int idx);
void RemoveMacroCondition(int idx);
void MoveMacroConditionUp(int idx);
void MoveMacroConditionDown(int idx);
void on_screenRegionSwitches_currentRowChanged(int idx);
void on_showFrame_clicked();

View File

@ -1,4 +1,7 @@
#pragma once
#include "macro.hpp"
#include "section.hpp"
#include "macro-entry-controls.hpp"
#include <QWidget>
#include <QComboBox>
@ -6,8 +9,6 @@
#include <QGroupBox>
#include <QLabel>
#include <deque>
#include "macro.hpp"
#include "section.hpp"
struct MacroActionInfo {
using TCreateMethod = std::shared_ptr<MacroAction> (*)();
@ -46,6 +47,10 @@ public:
private slots:
void ActionSelectionChanged(const QString &text);
void HeaderInfoChanged(const QString &);
void Add();
void Remove();
void Up();
void Down();
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
@ -53,11 +58,19 @@ signals:
void SceneGroupAdded(const QString &name);
void SceneGroupRemoved(const QString &name);
void SceneGroupRenamed(const QString &oldName, const QString newName);
void AddAt(int idx);
void RemoveAt(int idx);
void UpAt(int idx);
void DownAt(int idx);
protected:
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
QComboBox *_actionSelection;
Section *_section;
QLabel *_headerInfo;
MacroEntryControls *_controls;
std::shared_ptr<MacroAction> *_entryData;

View File

@ -4,6 +4,7 @@
#include "macro.hpp"
#include "macro-condition-scene.hpp"
#include "section.hpp"
#include "macro-entry-controls.hpp"
#include "utility.hpp"
#include <QGroupBox>
@ -43,6 +44,7 @@ public:
const std::string &id = "scene", bool root = true,
bool startCollapsed = false);
bool IsRootNode();
void SetRootNode(bool);
void UpdateEntryData(const std::string &id, bool collapse);
private slots:
@ -52,6 +54,10 @@ private slots:
void DurationConditionChanged(DurationCondition cond);
void DurationUnitChanged(DurationUnit unit);
void HeaderInfoChanged(const QString &);
void Add();
void Remove();
void Up();
void Down();
signals:
void MacroAdded(const QString &name);
void MacroRemoved(const QString &name);
@ -59,13 +65,21 @@ signals:
void SceneGroupAdded(const QString &name);
void SceneGroupRemoved(const QString &name);
void SceneGroupRenamed(const QString &oldName, const QString newName);
void AddAt(int idx);
void RemoveAt(int idx);
void UpAt(int idx);
void DownAt(int idx);
protected:
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
QComboBox *_logicSelection;
QComboBox *_conditionSelection;
Section *_section;
QLabel *_headerInfo;
DurationConstraintEdit *_dur;
MacroEntryControls *_controls;
std::shared_ptr<MacroCondition> *_entryData;

View File

@ -36,7 +36,16 @@ struct LogicTypeInfo {
std::string _name;
};
class MacroCondition {
class MacroSegment {
public:
void SetIndex(int idx) { _idx = idx; }
int GetIndex() { return _idx; }
protected:
int _idx;
};
class MacroCondition : public MacroSegment {
public:
virtual bool CheckCondition() = 0;
virtual bool Save(obs_data_t *obj) = 0;
@ -61,7 +70,7 @@ private:
DurationConstraint _duration;
};
class MacroAction {
class MacroAction : public MacroSegment {
public:
virtual bool PerformAction() = 0;
virtual bool Save(obs_data_t *obj) = 0;
@ -89,6 +98,8 @@ public:
{
return _conditions;
}
void UpdateActionIndices();
void UpdateConditionIndices();
std::deque<std::shared_ptr<MacroAction>> &Actions() { return _actions; }
bool Save(obs_data_t *obj);

View File

@ -44,6 +44,7 @@ QString fromatJsonString(const char *);
void placeWidgets(std::string text, QBoxLayout *layout,
std::unordered_map<std::string, QWidget *> placeholders,
bool addStretch = true);
void deleteLayoutItem(QLayoutItem *item);
void clearLayout(QLayout *layout);
QMetaObject::Connection PulseWidget(QWidget *widget, QColor endColor,
QColor = QColor(0, 0, 0, 0),

View File

@ -65,10 +65,12 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
_actionSelection = new QComboBox();
_section = new Section(300);
_headerInfo = new QLabel();
_controls = new MacroEntryControls();
QWidget::connect(_actionSelection,
SIGNAL(currentTextChanged(const QString &)), this,
SLOT(ActionSelectionChanged(const QString &)));
// Macro signals
QWidget::connect(parent, SIGNAL(MacroAdded(const QString &)), this,
SIGNAL(MacroAdded(const QString &)));
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
@ -77,6 +79,8 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
SIGNAL(MacroRenamed(const QString &, const QString)),
this,
SIGNAL(MacroRenamed(const QString &, const QString)));
// Scene group signals
QWidget::connect(parent, SIGNAL(SceneGroupAdded(const QString &)), this,
SIGNAL(SceneGroupAdded(const QString &)));
QWidget::connect(parent, SIGNAL(SceneGroupRemoved(const QString &)),
@ -86,6 +90,12 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
SIGNAL(SceneGroupRenamed(const QString &, const QString)), this,
SIGNAL(SceneGroupRenamed(const QString &, const QString)));
// Control signals
QWidget::connect(_controls, SIGNAL(Add()), this, SLOT(Add()));
QWidget::connect(_controls, SIGNAL(Remove()), this, SLOT(Remove()));
QWidget::connect(_controls, SIGNAL(Up()), this, SLOT(Up()));
QWidget::connect(_controls, SIGNAL(Down()), this, SLOT(Down()));
populateActionSelection(_actionSelection);
_section->AddHeaderWidget(_actionSelection);
@ -93,6 +103,7 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(_section);
mainLayout->addWidget(_controls);
setLayout(mainLayout);
_entryData = entryData;
@ -101,6 +112,16 @@ MacroActionEdit::MacroActionEdit(QWidget *parent,
_loading = false;
}
void MacroActionEdit::enterEvent(QEvent *)
{
_controls->Show(true);
}
void MacroActionEdit::leaveEvent(QEvent *)
{
_controls->Show(false);
}
void MacroActionEdit::ActionSelectionChanged(const QString &text)
{
if (_loading || !_entryData) {
@ -137,48 +158,157 @@ void MacroActionEdit::HeaderInfoChanged(const QString &text)
_headerInfo->setText(text);
}
void AdvSceneSwitcher::on_actionAdd_clicked()
void MacroActionEdit::Add()
{
if (_entryData) {
// Insert after current entry
emit AddAt((*_entryData)->GetIndex() + 1);
}
}
void MacroActionEdit::Remove()
{
if (_entryData) {
emit RemoveAt((*_entryData)->GetIndex());
}
}
void MacroActionEdit::Up()
{
if (_entryData) {
emit UpAt((*_entryData)->GetIndex());
}
}
void MacroActionEdit::Down()
{
if (_entryData) {
emit DownAt((*_entryData)->GetIndex());
}
}
void AdvSceneSwitcher::AddMacroAction(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx > macro->Actions().size()) {
return;
}
MacroActionSwitchScene temp;
std::string id = temp.GetId();
std::lock_guard<std::mutex> lock(switcher->m);
macro->Actions().emplace_back(MacroActionFactory::Create(id));
auto newEntry =
new MacroActionEdit(this, &macro->Actions().back(), id, false);
ui->macroEditActionLayout->addWidget(newEntry);
auto action = macro->Actions().emplace(macro->Actions().begin() + idx,
MacroActionFactory::Create(id));
macro->UpdateActionIndices();
// All entry pointers in existing edit widgets after the new entry will
// be invalidated by adding the new entry so we have to recreate them
// and because I am lazy I am recreating every widget.
//
// If performance should become a concern this has to be revisited.
SetEditMacro(*macro);
}
void AdvSceneSwitcher::on_actionAdd_clicked()
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
AddMacroAction((int)macro->Actions().size());
ui->macroEditActionHelp->setVisible(false);
}
void AdvSceneSwitcher::RemoveMacroAction(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= macro->Actions().size()) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
macro->Actions().erase(macro->Actions().begin() + idx);
macro->UpdateActionIndices();
// All entry pointers in existing edit widgets after the new entry will
// be invalidated by adding the new entry so we have to recreate them
// and because I am lazy I am recreating every widget.
//
// If performance should become a concern this has to be revisited.
SetEditMacro(*macro);
}
void AdvSceneSwitcher::on_actionRemove_clicked()
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
if (macro->Actions().empty()) {
RemoveMacroAction((int)macro->Actions().size() - 1);
}
void AdvSceneSwitcher::SwapActions(Macro *m, int pos1, int pos2)
{
if (pos1 == pos2) {
return;
}
macro->Actions().pop_back();
int count = ui->macroEditActionLayout->count();
auto item = ui->macroEditActionLayout->takeAt(count - 1);
if (item) {
auto widget = item->widget();
if (widget) {
widget->setVisible(false);
}
delete item;
if (pos1 > pos2) {
std::swap(pos1, pos2);
}
if (count == 1) {
ui->macroEditActionHelp->setVisible(true);
}
std::lock_guard<std::mutex> lock(switcher->m);
iter_swap(m->Actions().begin() + pos1, m->Actions().begin() + pos2);
m->UpdateActionIndices();
auto a1 = m->Actions().begin() + pos1;
auto a2 = m->Actions().begin() + pos2;
auto item1 = ui->macroEditActionLayout->takeAt(pos1);
auto item2 = ui->macroEditActionLayout->takeAt(pos2 - 1);
deleteLayoutItem(item1);
deleteLayoutItem(item2);
auto widget1 = new MacroActionEdit(this, &(*a1), (*a1)->GetId(), false);
auto widget2 = new MacroActionEdit(this, &(*a2), (*a2)->GetId(), false);
ConnectControlSignals(widget1);
ConnectControlSignals(widget2);
ui->macroEditActionLayout->insertWidget(pos1, widget1);
ui->macroEditActionLayout->insertWidget(pos2, widget2);
}
void AdvSceneSwitcher::MoveMacroActionUp(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 1 || idx >= macro->Actions().size()) {
return;
}
SwapActions(macro, idx, idx - 1);
}
void AdvSceneSwitcher::MoveMacroActionDown(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= macro->Actions().size() - 1) {
return;
}
SwapActions(macro, idx, idx + 1);
}

View File

@ -88,13 +88,14 @@ static inline void populateConditionSelection(QComboBox *list)
MacroConditionEdit::MacroConditionEdit(
QWidget *parent, std::shared_ptr<MacroCondition> *entryData,
const std::string &id, bool root, bool startCollapsed)
: QWidget(parent)
: QWidget(parent), _isRoot(root), _entryData(entryData)
{
_logicSelection = new QComboBox();
_conditionSelection = new QComboBox();
_section = new Section(300);
_headerInfo = new QLabel();
_dur = new DurationConstraintEdit();
_controls = new MacroEntryControls();
QWidget::connect(_logicSelection, SIGNAL(currentIndexChanged(int)),
this, SLOT(LogicSelectionChanged(int)));
@ -108,6 +109,8 @@ MacroConditionEdit::MacroConditionEdit(
QWidget::connect(_dur, SIGNAL(ConditionChanged(DurationCondition)),
this,
SLOT(DurationConditionChanged(DurationCondition)));
// Macro signals
QWidget::connect(parent, SIGNAL(MacroAdded(const QString &)), this,
SIGNAL(MacroAdded(const QString &)));
QWidget::connect(parent, SIGNAL(MacroRemoved(const QString &)), this,
@ -116,6 +119,8 @@ MacroConditionEdit::MacroConditionEdit(
SIGNAL(MacroRenamed(const QString &, const QString)),
this,
SIGNAL(MacroRenamed(const QString &, const QString)));
// Scene group signals
QWidget::connect(parent, SIGNAL(SceneGroupAdded(const QString &)), this,
SIGNAL(SceneGroupAdded(const QString &)));
QWidget::connect(parent, SIGNAL(SceneGroupRemoved(const QString &)),
@ -125,6 +130,12 @@ MacroConditionEdit::MacroConditionEdit(
SIGNAL(SceneGroupRenamed(const QString &, const QString)), this,
SIGNAL(SceneGroupRenamed(const QString &, const QString)));
// Control signals
QWidget::connect(_controls, SIGNAL(Add()), this, SLOT(Add()));
QWidget::connect(_controls, SIGNAL(Remove()), this, SLOT(Remove()));
QWidget::connect(_controls, SIGNAL(Up()), this, SLOT(Up()));
QWidget::connect(_controls, SIGNAL(Down()), this, SLOT(Down()));
populateLogicSelection(_logicSelection, root);
populateConditionSelection(_conditionSelection);
@ -135,14 +146,23 @@ MacroConditionEdit::MacroConditionEdit(
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(_section);
mainLayout->addWidget(_controls);
setLayout(mainLayout);
_entryData = entryData;
_isRoot = root;
UpdateEntryData(id, startCollapsed);
_loading = false;
}
void MacroConditionEdit::enterEvent(QEvent *)
{
_controls->Show(true);
}
void MacroConditionEdit::leaveEvent(QEvent *)
{
_controls->Show(false);
}
void MacroConditionEdit::LogicSelectionChanged(int idx)
{
if (_loading || !_entryData) {
@ -165,6 +185,13 @@ bool MacroConditionEdit::IsRootNode()
return _isRoot;
}
void MacroConditionEdit::SetRootNode(bool root)
{
const QSignalBlocker blocker(_logicSelection);
_logicSelection->clear();
populateLogicSelection(_logicSelection, root);
}
void MacroConditionEdit::UpdateEntryData(const std::string &id, bool collapse)
{
_conditionSelection->setCurrentText(obs_module_text(
@ -250,24 +277,107 @@ void MacroConditionEdit::HeaderInfoChanged(const QString &text)
_headerInfo->setText(text);
}
void MacroConditionEdit::Add()
{
if (_entryData) {
// Insert after current entry
emit AddAt((*_entryData)->GetIndex() + 1);
}
}
void MacroConditionEdit::Remove()
{
if (_entryData) {
emit RemoveAt((*_entryData)->GetIndex());
}
}
void MacroConditionEdit::Up()
{
if (_entryData) {
emit UpAt((*_entryData)->GetIndex());
}
}
void MacroConditionEdit::Down()
{
if (_entryData) {
emit DownAt((*_entryData)->GetIndex());
}
}
void AdvSceneSwitcher::AddMacroCondition(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx > macro->Conditions().size()) {
return;
}
MacroConditionScene temp;
std::string id = temp.GetId();
std::lock_guard<std::mutex> lock(switcher->m);
bool root = idx == 0;
auto cond =
macro->Conditions().emplace(macro->Conditions().begin() + idx,
MacroConditionFactory::Create(id));
auto logic = root ? LogicType::ROOT_NONE : LogicType::NONE;
(*cond)->SetLogicType(logic);
macro->UpdateConditionIndices();
// All entry pointers in existing edit widgets after the new entry will
// be invalidated by adding the new entry so we have to recreate them
// and because I am lazy I am recreating every widget.
//
// If performance should become a concern this has to be revisited.
SetEditMacro(*macro);
}
void AdvSceneSwitcher::on_conditionAdd_clicked()
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
MacroConditionScene temp;
std::string id = temp.GetId();
AddMacroCondition((int)macro->Conditions().size());
ui->macroEditConditionHelp->setVisible(false);
}
void AdvSceneSwitcher::RemoveMacroCondition(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= macro->Conditions().size()) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
bool root = macro->Conditions().size() == 0;
macro->Conditions().emplace_back(MacroConditionFactory::Create(id));
auto logic = root ? LogicType::ROOT_NONE : LogicType::NONE;
macro->Conditions().back()->SetLogicType(logic);
auto newEntry = new MacroConditionEdit(
this, &macro->Conditions().back(), id, root, false);
ui->macroEditConditionLayout->addWidget(newEntry);
ui->macroEditConditionHelp->setVisible(false);
macro->Conditions().erase(macro->Conditions().begin() + idx);
macro->UpdateConditionIndices();
if (macro->Conditions().size() == 0) {
ui->macroEditConditionHelp->setVisible(true);
}
if (idx == 0 && macro->Conditions().size() > 0) {
auto newRoot = macro->Conditions().at(0);
newRoot->SetLogicType(LogicType::ROOT_NONE);
}
// All entry pointers in existing edit widgets after the new entry will
// be invalidated by adding the new entry so we have to recreate them
// and because I am lazy I am recreating every widget.
//
// If performance should become a concern this has to be revisited.
SetEditMacro(*macro);
}
void AdvSceneSwitcher::on_conditionRemove_clicked()
@ -276,24 +386,71 @@ void AdvSceneSwitcher::on_conditionRemove_clicked()
if (!macro) {
return;
}
std::lock_guard<std::mutex> lock(switcher->m);
if (macro->Conditions().empty()) {
RemoveMacroCondition((int)macro->Conditions().size() - 1);
}
void AdvSceneSwitcher::SwapConditions(Macro *m, int pos1, int pos2)
{
if (pos1 == pos2) {
return;
}
macro->Conditions().pop_back();
int count = ui->macroEditConditionLayout->count();
auto item = ui->macroEditConditionLayout->takeAt(count - 1);
if (item) {
auto widget = item->widget();
if (widget) {
widget->setVisible(false);
}
delete item;
if (pos1 > pos2) {
std::swap(pos1, pos2);
}
if (count == 1) {
ui->macroEditConditionHelp->setVisible(true);
bool root = pos1 == 0;
std::lock_guard<std::mutex> lock(switcher->m);
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 item1 = ui->macroEditConditionLayout->takeAt(pos1);
auto item2 = ui->macroEditConditionLayout->takeAt(pos2 - 1);
deleteLayoutItem(item1);
deleteLayoutItem(item2);
auto widget1 = new MacroConditionEdit(this, &(*c1), (*c1)->GetId(),
root, false);
auto widget2 = new MacroConditionEdit(this, &(*c2), (*c2)->GetId(),
false, false);
ConnectControlSignals(widget1);
ConnectControlSignals(widget2);
ui->macroEditConditionLayout->insertWidget(pos1, widget1);
ui->macroEditConditionLayout->insertWidget(pos2, widget2);
}
void AdvSceneSwitcher::MoveMacroConditionUp(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 1 || idx >= macro->Conditions().size()) {
return;
}
SwapConditions(macro, idx, idx - 1);
}
void AdvSceneSwitcher::MoveMacroConditionDown(int idx)
{
auto macro = getSelectedMacro();
if (!macro) {
return;
}
if (idx < 0 || idx >= macro->Conditions().size() - 1) {
return;
}
SwapConditions(macro, idx, idx + 1);
}

View File

@ -180,6 +180,7 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
for (auto &c : m.Conditions()) {
auto newEntry = new MacroConditionEdit(this, &c, c->GetId(),
root, collapse);
ConnectControlSignals(newEntry);
ui->macroEditConditionLayout->addWidget(newEntry);
ui->macroEditConditionHelp->setVisible(false);
root = false;
@ -189,6 +190,7 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
for (auto &a : m.Actions()) {
auto newEntry =
new MacroActionEdit(this, &a, a->GetId(), collapse);
ConnectControlSignals(newEntry);
ui->macroEditActionLayout->addWidget(newEntry);
ui->macroEditActionHelp->setVisible(false);
}
@ -208,6 +210,30 @@ void AdvSceneSwitcher::SetEditMacro(Macro &m)
}
}
void AdvSceneSwitcher::ConnectControlSignals(MacroActionEdit *c)
{
connect(c, &MacroActionEdit::AddAt, this,
&AdvSceneSwitcher::AddMacroAction);
connect(c, &MacroActionEdit::RemoveAt, this,
&AdvSceneSwitcher::RemoveMacroAction);
connect(c, &MacroActionEdit::UpAt, this,
&AdvSceneSwitcher::MoveMacroActionUp);
connect(c, &MacroActionEdit::DownAt, this,
&AdvSceneSwitcher::MoveMacroActionDown);
}
void AdvSceneSwitcher::ConnectControlSignals(MacroConditionEdit *c)
{
connect(c, &MacroConditionEdit::AddAt, this,
&AdvSceneSwitcher::AddMacroCondition);
connect(c, &MacroConditionEdit::RemoveAt, this,
&AdvSceneSwitcher::RemoveMacroCondition);
connect(c, &MacroConditionEdit::UpAt, this,
&AdvSceneSwitcher::MoveMacroConditionUp);
connect(c, &MacroConditionEdit::DownAt, this,
&AdvSceneSwitcher::MoveMacroConditionDown);
}
Macro *AdvSceneSwitcher::getSelectedMacro()
{
QListWidgetItem *item = ui->macros->currentItem();

View File

@ -124,6 +124,24 @@ void Macro::SetName(const std::string &name)
SetHotkeysDesc();
}
void Macro::UpdateActionIndices()
{
int idx = 0;
for (auto a : _actions) {
a->SetIndex(idx);
idx++;
}
}
void Macro::UpdateConditionIndices()
{
int idx = 0;
for (auto c : _conditions) {
c->SetIndex(idx);
idx++;
}
}
bool Macro::Save(obs_data_t *obj)
{
obs_data_set_string(obj, "name", _name.c_str());
@ -238,6 +256,7 @@ bool Macro::Load(obs_data_t *obj)
root = false;
}
obs_data_array_release(conditions);
UpdateConditionIndices();
obs_data_array_t *actions = obs_data_get_array(obj, "actions");
count = obs_data_array_count(actions);
@ -260,6 +279,7 @@ bool Macro::Load(obs_data_t *obj)
obs_data_release(array_obj);
}
obs_data_array_release(actions);
UpdateActionIndices();
return true;
}

View File

@ -174,6 +174,17 @@ void placeWidgets(std::string text, QBoxLayout *layout,
}
}
void deleteLayoutItem(QLayoutItem *item)
{
if (item) {
auto widget = item->widget();
if (widget) {
widget->setVisible(false);
}
delete item;
}
}
void clearLayout(QLayout *layout)
{
QLayoutItem *item;