mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-04-22 18:17:25 -05:00
Add temporary variables
Enables easier use of values returned by macro segments. For example, this enables the user to extract the user name of a new Twitch follower and change a text sources settings accordingly
This commit is contained in:
parent
c17523a476
commit
17efa82057
|
|
@ -315,6 +315,8 @@ target_sources(
|
|||
src/utils/switch-button.hpp
|
||||
src/utils/sync-helper.cpp
|
||||
src/utils/sync-helper.hpp
|
||||
src/utils/temp-variable.cpp
|
||||
src/utils/temp-variable.hpp
|
||||
src/utils/transition-selection.cpp
|
||||
src/utils/transition-selection.hpp
|
||||
src/utils/utility.cpp
|
||||
|
|
|
|||
|
|
@ -325,6 +325,9 @@ void SwitcherData::SetPreconditions()
|
|||
cursorPosChanged = cursorPos.first != switcher->lastCursorPos.first ||
|
||||
cursorPos.second != switcher->lastCursorPos.second;
|
||||
lastCursorPos = GetCursorPos();
|
||||
|
||||
// Macro
|
||||
InvalidateMacroTempVarValues();
|
||||
}
|
||||
|
||||
void ClearWebsocketMessages();
|
||||
|
|
|
|||
|
|
@ -178,6 +178,7 @@ signals:
|
|||
void MacroRemoved(const QString &name);
|
||||
void MacroRenamed(const QString &oldName, const QString &newName);
|
||||
void MacroSegmentOrderChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightMacrosChanged(bool value);
|
||||
void HighlightActionsChanged(bool value);
|
||||
void HighlightElseActionsChanged(bool value);
|
||||
|
|
|
|||
|
|
@ -138,6 +138,7 @@ void MacroActionEdit::ActionSelectionChanged(const QString &text)
|
|||
_entryData->reset();
|
||||
*_entryData = MacroActionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->PostLoad();
|
||||
}
|
||||
auto widget = MacroActionFactory::CreateWidget(id, this, *_entryData);
|
||||
QWidget::connect(widget, SIGNAL(HeaderInfoChanged(const QString &)),
|
||||
|
|
@ -204,7 +205,7 @@ void MacroActionEdit::SetEnableAppearance(bool value)
|
|||
SetDisableEffect(!value);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data()
|
||||
std::shared_ptr<MacroSegment> MacroActionEdit::Data() const
|
||||
{
|
||||
return *_entryData;
|
||||
}
|
||||
|
|
@ -236,6 +237,7 @@ void AdvSceneSwitcher::AddMacroAction(int idx)
|
|||
auto data = obs_data_create();
|
||||
macro->Actions().at(idx - 1)->Save(data);
|
||||
macro->Actions().at(idx)->Load(data);
|
||||
macro->Actions().at(idx)->PostLoad();
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->UpdateActionIndices();
|
||||
|
|
@ -525,6 +527,7 @@ void AdvSceneSwitcher::AddMacroElseAction(int idx)
|
|||
macro->ElseActions().at(idx - 1)->Save(data);
|
||||
macro->ElseActions().at(idx)->Load(data);
|
||||
}
|
||||
macro->ElseActions().at(idx)->PostLoad();
|
||||
macro->UpdateElseActionIndices();
|
||||
ui->elseActionsList->Insert(
|
||||
idx, new MacroActionEdit(
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ private slots:
|
|||
void UpdateActionState();
|
||||
|
||||
private:
|
||||
std::shared_ptr<MacroSegment> Data();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
void SetDisableEffect(bool);
|
||||
void SetEnableAppearance(bool);
|
||||
|
||||
|
|
|
|||
|
|
@ -312,6 +312,7 @@ void MacroConditionEdit::ConditionSelectionChanged(const QString &text)
|
|||
*_entryData = MacroConditionFactory::Create(id, macro);
|
||||
(*_entryData)->SetIndex(idx);
|
||||
(*_entryData)->SetLogicType(logic);
|
||||
(*_entryData)->PostLoad();
|
||||
}
|
||||
auto widget =
|
||||
MacroConditionFactory::CreateWidget(id, this, *_entryData);
|
||||
|
|
@ -342,7 +343,7 @@ void MacroConditionEdit::DurationModifierChanged(DurationModifier::Type m)
|
|||
(*_entryData)->SetDurationModifier(m);
|
||||
}
|
||||
|
||||
std::shared_ptr<MacroSegment> MacroConditionEdit::Data()
|
||||
std::shared_ptr<MacroSegment> MacroConditionEdit::Data() const
|
||||
{
|
||||
return *_entryData;
|
||||
}
|
||||
|
|
@ -383,6 +384,7 @@ void AdvSceneSwitcher::AddMacroCondition(int idx)
|
|||
macro->Conditions().at(idx)->Load(data);
|
||||
obs_data_release(data);
|
||||
}
|
||||
macro->Conditions().at(idx)->PostLoad();
|
||||
(*cond)->SetLogicType(logic);
|
||||
macro->UpdateConditionIndices();
|
||||
ui->conditionsList->Insert(
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ private slots:
|
|||
|
||||
private:
|
||||
void SetLogicSelection();
|
||||
std::shared_ptr<MacroSegment> Data();
|
||||
std::shared_ptr<MacroSegment> Data() const;
|
||||
|
||||
QComboBox *_logicSelection;
|
||||
FilterComboBox *_conditionSelection;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "macro-segment.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "section.hpp"
|
||||
#include "utility.hpp"
|
||||
#include "mouse-wheel-guard.hpp"
|
||||
|
|
@ -26,11 +27,13 @@ bool MacroSegment::Save(obs_data_t *obj) const
|
|||
bool MacroSegment::Load(obs_data_t *obj)
|
||||
{
|
||||
_collapsed = obs_data_get_bool(obj, "collapsed");
|
||||
ClearAvailableTempvars();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacroSegment::PostLoad()
|
||||
{
|
||||
SetupTempVars();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -68,20 +71,111 @@ void MacroSegment::SetVariableValue(const std::string &value)
|
|||
}
|
||||
}
|
||||
|
||||
void MacroSegment::IncrementVariableRef()
|
||||
void MacroSegment::SetupTempVars()
|
||||
{
|
||||
if (!_supportsVariableValue) {
|
||||
return;
|
||||
}
|
||||
_variableRefs++;
|
||||
ClearAvailableTempvars();
|
||||
}
|
||||
|
||||
void MacroSegment::DecrementVariableRef()
|
||||
void MacroSegment::ClearAvailableTempvars()
|
||||
{
|
||||
if (!_supportsVariableValue || _variableRefs == 0) {
|
||||
_tempVariables.clear();
|
||||
NotifyUIAboutTempVarChange();
|
||||
}
|
||||
|
||||
static std::shared_ptr<MacroSegment>
|
||||
getSharedSegmentFromMacro(Macro *macro, const MacroSegment *segment)
|
||||
{
|
||||
auto matches = [segment](const std::shared_ptr<MacroSegment> &s) {
|
||||
return s.get() == segment;
|
||||
};
|
||||
auto condIt = std::find_if(macro->Conditions().begin(),
|
||||
macro->Conditions().end(), matches);
|
||||
if (condIt != macro->Conditions().end()) {
|
||||
return *condIt;
|
||||
}
|
||||
auto actionIt = std::find_if(macro->Actions().begin(),
|
||||
macro->Actions().end(), matches);
|
||||
if (actionIt != macro->Actions().end()) {
|
||||
return *actionIt;
|
||||
}
|
||||
auto elseIt = std::find_if(macro->ElseActions().begin(),
|
||||
macro->ElseActions().end(), matches);
|
||||
if (elseIt != macro->ElseActions().end()) {
|
||||
return *elseIt;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void MacroSegment::AddTempvar(const std::string &id, const std::string &name,
|
||||
const std::string &description)
|
||||
{
|
||||
auto macro = GetMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
_variableRefs--;
|
||||
|
||||
auto sharedSegment = getSharedSegmentFromMacro(macro, this);
|
||||
if (!sharedSegment) {
|
||||
return;
|
||||
}
|
||||
|
||||
TempVariable var(id, name, description, sharedSegment);
|
||||
_tempVariables.emplace_back(std::move(var));
|
||||
NotifyUIAboutTempVarChange();
|
||||
}
|
||||
|
||||
void MacroSegment::SetTempVarValue(const std::string &id,
|
||||
const std::string &value)
|
||||
{
|
||||
for (auto &var : _tempVariables) {
|
||||
if (var.ID() != id) {
|
||||
continue;
|
||||
}
|
||||
var.SetValue(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MacroSegment::InvalidateTempVarValues()
|
||||
{
|
||||
for (auto &var : _tempVariables) {
|
||||
var.InvalidateValue();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<const TempVariable>
|
||||
MacroSegment::GetTempVar(const std::string &id) const
|
||||
{
|
||||
TempVariable *result = nullptr;
|
||||
for (auto &var : _tempVariables) {
|
||||
if (var.ID() == id) {
|
||||
return var;
|
||||
}
|
||||
}
|
||||
vblog(LOG_INFO, "cannot get value of unknown tempvar %s", id.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
bool SupportsVariableValue(MacroSegment *segment)
|
||||
{
|
||||
return segment && segment->_supportsVariableValue;
|
||||
}
|
||||
|
||||
void IncrementVariableRef(MacroSegment *segment)
|
||||
{
|
||||
if (!segment || !segment->_supportsVariableValue) {
|
||||
return;
|
||||
}
|
||||
segment->_variableRefs++;
|
||||
}
|
||||
|
||||
void DecrementVariableRef(MacroSegment *segment)
|
||||
{
|
||||
if (!segment || !segment->_supportsVariableValue ||
|
||||
segment->_variableRefs == 0) {
|
||||
return;
|
||||
}
|
||||
segment->_variableRefs--;
|
||||
}
|
||||
|
||||
MacroSegmentEdit::MacroSegmentEdit(bool highlight, QWidget *parent)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
// The following helpers are used by all macro seements,
|
||||
// The following helpers are used by all macro segments,
|
||||
// so it makes sense to include them here:
|
||||
#include "log-helper.hpp"
|
||||
#include "obs-module-helper.hpp"
|
||||
#include "sync-helper.hpp"
|
||||
#include "temp-variable.hpp"
|
||||
|
||||
#include <QWidget>
|
||||
#include <QFrame>
|
||||
|
|
@ -34,16 +35,26 @@ public:
|
|||
virtual std::string GetId() const = 0;
|
||||
void SetHighlight();
|
||||
bool Highlight();
|
||||
bool SupportsVariableValue() const { return _supportsVariableValue; }
|
||||
virtual std::string GetVariableValue() const;
|
||||
void IncrementVariableRef();
|
||||
void DecrementVariableRef();
|
||||
|
||||
protected:
|
||||
friend bool SupportsVariableValue(MacroSegment *);
|
||||
friend void IncrementVariableRef(MacroSegment *);
|
||||
friend void DecrementVariableRef(MacroSegment *);
|
||||
void SetVariableValue(const std::string &value);
|
||||
bool IsReferencedInVars() { return _variableRefs != 0; }
|
||||
|
||||
virtual void SetupTempVars();
|
||||
void AddTempvar(const std::string &id, const std::string &name,
|
||||
const std::string &description = "");
|
||||
void SetTempVarValue(const std::string &id, const std::string &value);
|
||||
|
||||
private:
|
||||
void ClearAvailableTempvars();
|
||||
std::optional<const TempVariable>
|
||||
GetTempVar(const std::string &id) const;
|
||||
void InvalidateTempVarValues();
|
||||
|
||||
// Macro helpers
|
||||
Macro *_macro = nullptr;
|
||||
int _idx = 0;
|
||||
|
|
@ -56,6 +67,9 @@ private:
|
|||
const bool _supportsVariableValue = false;
|
||||
int _variableRefs = 0;
|
||||
std::string _variableValue;
|
||||
std::vector<TempVariable> _tempVariables;
|
||||
|
||||
friend class Macro;
|
||||
};
|
||||
|
||||
class Section;
|
||||
|
|
@ -70,6 +84,7 @@ public:
|
|||
void SetFocusPolicyOfWidgets();
|
||||
void SetCollapsed(bool collapsed);
|
||||
void SetSelected(bool);
|
||||
virtual std::shared_ptr<MacroSegment> Data() const = 0;
|
||||
|
||||
protected slots:
|
||||
void HeaderInfoChanged(const QString &);
|
||||
|
|
@ -99,7 +114,6 @@ private:
|
|||
BELOW,
|
||||
};
|
||||
|
||||
virtual std::shared_ptr<MacroSegment> Data() = 0;
|
||||
void ShowDropLine(DropLineState);
|
||||
|
||||
// The reason for using two separate frame widget each with their own
|
||||
|
|
|
|||
|
|
@ -361,6 +361,126 @@ void Macro::Stop()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<TempVariable> Macro::GetTempVars(MacroSegment *filter) const
|
||||
{
|
||||
std::vector<TempVariable> res;
|
||||
|
||||
auto addTempVars = [&res](const std::deque<std::shared_ptr<MacroSegment>>
|
||||
&segments) {
|
||||
for (const auto &s : segments) {
|
||||
const auto &tempVars = s->_tempVariables;
|
||||
res.insert(res.end(), tempVars.begin(), tempVars.end());
|
||||
}
|
||||
};
|
||||
|
||||
addTempVars({_conditions.begin(), _conditions.end()});
|
||||
addTempVars({_actions.begin(), _actions.end()});
|
||||
addTempVars({_elseActions.begin(), _elseActions.end()});
|
||||
|
||||
if (!filter) {
|
||||
return res;
|
||||
}
|
||||
|
||||
auto isCondition = [this](const MacroSegment *segment) -> bool {
|
||||
return std::find_if(_conditions.begin(), _conditions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
&ptr) {
|
||||
return ptr.get() == segment;
|
||||
}) != _conditions.end();
|
||||
};
|
||||
auto isAction = [this](MacroSegment *segment) -> bool {
|
||||
return std::find_if(_actions.begin(), _actions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
&ptr) {
|
||||
return ptr.get() == segment;
|
||||
}) != _actions.end();
|
||||
};
|
||||
auto isElseAction = [this](MacroSegment *segment) -> bool {
|
||||
return std::find_if(_elseActions.begin(), _elseActions.end(),
|
||||
[segment](
|
||||
const std::shared_ptr<MacroSegment>
|
||||
&ptr) {
|
||||
return ptr.get() == segment;
|
||||
}) != _elseActions.end();
|
||||
};
|
||||
|
||||
const int filterIndex = filter->GetIndex();
|
||||
// Remove all actions and else actions and conditions after filterIndex
|
||||
if (isCondition(filter)) {
|
||||
for (auto it = res.begin(); it != res.end();) {
|
||||
auto segment = it->Segment().lock().get();
|
||||
if (isCondition(segment) &&
|
||||
segment->GetIndex() >= filterIndex) {
|
||||
it = res.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (isAction(segment) || isElseAction(segment)) {
|
||||
it = res.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
// Remove all else actions and actions after filterIndex
|
||||
if (isAction(filter)) {
|
||||
for (auto it = res.begin(); it != res.end();) {
|
||||
auto segment = it->Segment().lock().get();
|
||||
if (isAction(segment) &&
|
||||
segment->GetIndex() >= filterIndex) {
|
||||
it = res.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (isElseAction(segment)) {
|
||||
it = res.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
// Remove all actions and elseActions after filterIndex
|
||||
for (auto it = res.begin(); it != res.end();) {
|
||||
auto segment = it->Segment().lock().get();
|
||||
if (isElseAction(segment) &&
|
||||
segment->GetIndex() >= filterIndex) {
|
||||
it = res.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (isAction(segment)) {
|
||||
it = res.erase(it);
|
||||
continue;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::optional<const TempVariable> Macro::GetTempVar(const MacroSegment *segment,
|
||||
const std::string &id) const
|
||||
{
|
||||
if (!segment) {
|
||||
return {};
|
||||
}
|
||||
return segment->GetTempVar(id);
|
||||
}
|
||||
|
||||
void Macro::InvalidateTempVarValues() const
|
||||
{
|
||||
auto invalidateHelper =
|
||||
[](const std::deque<std::shared_ptr<MacroSegment>> &segments) {
|
||||
for (const auto &s : segments) {
|
||||
s->InvalidateTempVarValues();
|
||||
}
|
||||
};
|
||||
|
||||
invalidateHelper({_conditions.begin(), _conditions.end()});
|
||||
invalidateHelper({_actions.begin(), _actions.end()});
|
||||
invalidateHelper({_elseActions.begin(), _elseActions.end()});
|
||||
}
|
||||
|
||||
std::deque<std::shared_ptr<MacroCondition>> &Macro::Conditions()
|
||||
{
|
||||
return _conditions;
|
||||
|
|
@ -1200,4 +1320,11 @@ std::weak_ptr<Macro> GetWeakMacroByName(const char *name)
|
|||
return {};
|
||||
}
|
||||
|
||||
void InvalidateMacroTempVarValues()
|
||||
{
|
||||
for (auto &m : switcher->macros) {
|
||||
m->InvalidateTempVarValues();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "macro-condition.hpp"
|
||||
#include "macro-ref.hpp"
|
||||
#include "variable-string.hpp"
|
||||
#include "temp-variable.hpp"
|
||||
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
|
|
@ -47,6 +48,13 @@ public:
|
|||
bool GetStop() const { return _stop; }
|
||||
void Stop();
|
||||
|
||||
// Temporary variable helpers
|
||||
std::vector<TempVariable> GetTempVars(MacroSegment *filter) const;
|
||||
std::optional<const TempVariable>
|
||||
GetTempVar(const MacroSegment *, const std::string &id) const;
|
||||
void InvalidateTempVarValues() const;
|
||||
|
||||
// Macro segments
|
||||
std::deque<std::shared_ptr<MacroCondition>> &Conditions();
|
||||
std::deque<std::shared_ptr<MacroAction>> &Actions();
|
||||
std::deque<std::shared_ptr<MacroAction>> &ElseActions();
|
||||
|
|
@ -121,11 +129,13 @@ private:
|
|||
void SetupHotkeys();
|
||||
void ClearHotkeys() const;
|
||||
void SetHotkeysDesc() const;
|
||||
|
||||
bool RunActionsHelper(
|
||||
const std::deque<std::shared_ptr<MacroAction>> &actions,
|
||||
bool ignorePause);
|
||||
bool RunActions(bool ignorePause);
|
||||
bool RunElseActions(bool ignorePause);
|
||||
|
||||
bool DockIsVisible() const;
|
||||
void SetDockWidgetName() const;
|
||||
void SaveDockSettings(obs_data_t *obj) const;
|
||||
|
|
@ -195,5 +205,6 @@ private:
|
|||
Macro *GetMacroByName(const char *name);
|
||||
Macro *GetMacroByQString(const QString &name);
|
||||
std::weak_ptr<Macro> GetWeakMacroByName(const char *name);
|
||||
void InvalidateMacroTempVarValues();
|
||||
|
||||
} // namespace advss
|
||||
|
|
|
|||
467
src/utils/temp-variable.cpp
Normal file
467
src/utils/temp-variable.cpp
Normal file
|
|
@ -0,0 +1,467 @@
|
|||
#include "temp-variable.hpp"
|
||||
#include "advanced-scene-switcher.hpp"
|
||||
#include "macro.hpp"
|
||||
#include "macro-segment.hpp"
|
||||
#include "switcher-data.hpp"
|
||||
#include "utility.hpp"
|
||||
|
||||
#include <QVariant>
|
||||
#include <QAbstractItemView>
|
||||
|
||||
Q_DECLARE_METATYPE(advss::TempVariableRef);
|
||||
|
||||
namespace advss {
|
||||
|
||||
TempVariable::TempVariable(const std::string &id, const std::string &name,
|
||||
const std::string &description,
|
||||
const std::shared_ptr<MacroSegment> &segment)
|
||||
: _id(id), _name(name), _description(description), _segment(segment)
|
||||
{
|
||||
}
|
||||
|
||||
TempVariable::TempVariable(const TempVariable &other) noexcept
|
||||
{
|
||||
_id = other._id;
|
||||
_value = other._value;
|
||||
_name = other._name;
|
||||
_description = other._description;
|
||||
_valueIsValid = other._valueIsValid;
|
||||
_segment = other._segment;
|
||||
|
||||
std::lock_guard<std::mutex> lock(other._lastValuesMutex);
|
||||
_lastValues = other._lastValues;
|
||||
}
|
||||
|
||||
TempVariable::TempVariable(const TempVariable &&other) noexcept
|
||||
{
|
||||
_id = other._id;
|
||||
_value = other._value;
|
||||
_name = other._name;
|
||||
_description = other._description;
|
||||
_valueIsValid = other._valueIsValid;
|
||||
_segment = other._segment;
|
||||
|
||||
std::lock_guard<std::mutex> lock(other._lastValuesMutex);
|
||||
_lastValues = other._lastValues;
|
||||
}
|
||||
|
||||
TempVariable &TempVariable::operator=(const TempVariable &other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
_id = other._id;
|
||||
_value = other._value;
|
||||
_name = other._name;
|
||||
_description = other._description;
|
||||
_valueIsValid = other._valueIsValid;
|
||||
_segment = other._segment;
|
||||
|
||||
std::lock_guard<std::mutex> lockOther(other._lastValuesMutex);
|
||||
std::lock_guard<std::mutex> lock(_lastValuesMutex);
|
||||
_lastValues = other._lastValues;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
TempVariable &TempVariable::operator=(const TempVariable &&other) noexcept
|
||||
{
|
||||
if (this != &other) {
|
||||
_id = other._id;
|
||||
_value = other._value;
|
||||
_name = other._name;
|
||||
_description = other._description;
|
||||
_valueIsValid = other._valueIsValid;
|
||||
_segment = other._segment;
|
||||
|
||||
std::lock_guard<std::mutex> lockOther(other._lastValuesMutex);
|
||||
std::lock_guard<std::mutex> lock(_lastValuesMutex);
|
||||
_lastValues = other._lastValues;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::optional<std::string> TempVariable::Value() const
|
||||
{
|
||||
if (!_valueIsValid) {
|
||||
return {};
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
|
||||
void TempVariable::SetValue(const std::string &val)
|
||||
{
|
||||
_valueIsValid = true;
|
||||
if (_value == val) {
|
||||
return;
|
||||
}
|
||||
_value = val;
|
||||
std::lock_guard<std::mutex> lock(_lastValuesMutex);
|
||||
if (_lastValues.size() >= 3) {
|
||||
_lastValues.erase(_lastValues.begin());
|
||||
}
|
||||
_lastValues.push_back(val);
|
||||
}
|
||||
|
||||
void TempVariable::InvalidateValue()
|
||||
{
|
||||
_valueIsValid = false;
|
||||
}
|
||||
|
||||
TempVariableRef TempVariable::GetRef() const
|
||||
{
|
||||
TempVariableRef ref;
|
||||
ref._id = _id;
|
||||
ref._segment = _segment;
|
||||
return ref;
|
||||
}
|
||||
|
||||
TempVariableRef::SegmentType TempVariableRef::GetType() const
|
||||
{
|
||||
auto segment = _segment.lock();
|
||||
if (!segment) {
|
||||
return SegmentType::NONE;
|
||||
}
|
||||
auto macro = segment->GetMacro();
|
||||
if (!macro) {
|
||||
return SegmentType::NONE;
|
||||
}
|
||||
|
||||
if (std::find(macro->Conditions().begin(), macro->Conditions().end(),
|
||||
segment) != macro->Conditions().end()) {
|
||||
return SegmentType::CONDITION;
|
||||
}
|
||||
if (std::find(macro->Actions().begin(), macro->Actions().end(),
|
||||
segment) != macro->Actions().end()) {
|
||||
return SegmentType::ACTION;
|
||||
}
|
||||
if (std::find(macro->ElseActions().begin(), macro->ElseActions().end(),
|
||||
segment) != macro->ElseActions().end()) {
|
||||
return SegmentType::ELSEACTION;
|
||||
}
|
||||
return SegmentType::NONE;
|
||||
}
|
||||
|
||||
int TempVariableRef::GetIdx() const
|
||||
{
|
||||
auto segment = _segment.lock();
|
||||
if (!segment) {
|
||||
return -1;
|
||||
}
|
||||
return segment->GetIndex();
|
||||
}
|
||||
|
||||
void TempVariableRef::Save(obs_data_t *obj, const char *name) const
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
auto type = GetType();
|
||||
obs_data_set_int(data, "type", static_cast<int>(type));
|
||||
obs_data_set_int(data, "idx", GetIdx());
|
||||
obs_data_set_string(data, "id", _id.c_str());
|
||||
obs_data_set_obj(obj, name, data);
|
||||
}
|
||||
|
||||
void TempVariableRef::Load(obs_data_t *obj, Macro *macro, const char *name)
|
||||
{
|
||||
if (!macro) {
|
||||
_segment.reset();
|
||||
return;
|
||||
}
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, name);
|
||||
int idx = obs_data_get_int(data, "idx");
|
||||
_id = obs_data_get_string(data, "id");
|
||||
const auto type =
|
||||
static_cast<SegmentType>(obs_data_get_int(data, "type"));
|
||||
switcher->AddPostLoadStep([this, idx, type, macro]() {
|
||||
this->PostLoad(idx, type, macro);
|
||||
});
|
||||
}
|
||||
|
||||
void TempVariableRef::PostLoad(int idx, SegmentType type, Macro *macro)
|
||||
{
|
||||
std::deque<std::shared_ptr<MacroSegment>> segments;
|
||||
switch (type) {
|
||||
case SegmentType::NONE:
|
||||
_segment.reset();
|
||||
return;
|
||||
case SegmentType::CONDITION:
|
||||
segments = {macro->Conditions().begin(),
|
||||
macro->Conditions().end()};
|
||||
break;
|
||||
case SegmentType::ACTION:
|
||||
segments = {macro->Actions().begin(), macro->Actions().end()};
|
||||
break;
|
||||
case SegmentType::ELSEACTION:
|
||||
segments = {macro->ElseActions().begin(),
|
||||
macro->ElseActions().end()};
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (idx < 0 || idx >= (int)segments.size()) {
|
||||
_segment.reset();
|
||||
return;
|
||||
}
|
||||
_segment = segments[idx];
|
||||
}
|
||||
|
||||
std::optional<const TempVariable>
|
||||
TempVariableRef::GetTempVariable(Macro *macro) const
|
||||
{
|
||||
if (!macro) {
|
||||
return {};
|
||||
}
|
||||
auto segment = _segment.lock();
|
||||
if (!segment) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return macro->GetTempVar(segment.get(), _id);
|
||||
}
|
||||
|
||||
bool TempVariableRef::operator==(const TempVariableRef &other) const
|
||||
{
|
||||
if (_id != other._id) {
|
||||
return false;
|
||||
}
|
||||
auto segment = _segment.lock();
|
||||
if (!segment) {
|
||||
return false;
|
||||
}
|
||||
return segment == other._segment.lock();
|
||||
}
|
||||
|
||||
TempVariableSelection::TempVariableSelection(QWidget *parent)
|
||||
: QWidget(parent),
|
||||
_selection(new FilterComboBox(
|
||||
this, obs_module_text("AdvSceneSwitcher.tempVar.select"))),
|
||||
_info(new AutoUpdateTooltipLabel(this, [this]() {
|
||||
return SetupInfoLabel();
|
||||
}))
|
||||
{
|
||||
QString path = GetThemeTypeName() == "Light"
|
||||
? ":/res/images/help.svg"
|
||||
: ":/res/images/help_light.svg";
|
||||
QIcon icon(path);
|
||||
QPixmap pixmap = icon.pixmap(QSize(16, 16));
|
||||
_info->setPixmap(pixmap);
|
||||
_info->hide();
|
||||
|
||||
_selection->setDuplicatesEnabled(true);
|
||||
PopulateSelection();
|
||||
|
||||
QWidget::connect(_selection, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(SelectionIdxChanged(int)));
|
||||
QWidget::connect(_selection, SIGNAL(highlighted(int)), this,
|
||||
SLOT(HighlightChanged(int)));
|
||||
QWidget::connect(window(), SIGNAL(MacroSegmentOrderChanged()), this,
|
||||
SLOT(MacroSegmentsChanged()));
|
||||
QWidget::connect(window(), SIGNAL(SegmentTempVarsChanged()), this,
|
||||
SLOT(SegmentTempVarsChanged()));
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(_selection);
|
||||
layout->addWidget(_info);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void TempVariableSelection::SelectionIdxChanged(int idx)
|
||||
{
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
auto var = _selection->itemData(idx).value<TempVariableRef>();
|
||||
emit SelectionChanged(var);
|
||||
HighlightSelection(var);
|
||||
SetupInfoLabel();
|
||||
}
|
||||
|
||||
void TempVariableSelection::SetVariable(const TempVariableRef &var)
|
||||
{
|
||||
const QSignalBlocker b(_selection);
|
||||
QVariant variant;
|
||||
variant.setValue(var);
|
||||
_selection->setCurrentIndex(_selection->findData(variant));
|
||||
SetupInfoLabel();
|
||||
}
|
||||
|
||||
void TempVariableSelection::MacroSegmentsChanged()
|
||||
{
|
||||
auto currentSelection = _selection->itemData(_selection->currentIndex())
|
||||
.value<TempVariableRef>();
|
||||
const QSignalBlocker b(_selection);
|
||||
_selection->clear();
|
||||
PopulateSelection();
|
||||
SetVariable(currentSelection);
|
||||
}
|
||||
|
||||
void TempVariableSelection::SegmentTempVarsChanged()
|
||||
{
|
||||
MacroSegmentsChanged();
|
||||
}
|
||||
|
||||
void TempVariableSelection::HighlightChanged(int idx)
|
||||
{
|
||||
auto var = _selection->itemData(idx).value<TempVariableRef>();
|
||||
HighlightSelection(var);
|
||||
}
|
||||
|
||||
void TempVariableSelection::PopulateSelection()
|
||||
{
|
||||
auto advssWindow = qobject_cast<AdvSceneSwitcher *>(window());
|
||||
if (!advssWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto macro = advssWindow->GetSelectedMacro();
|
||||
if (!macro) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto vars = macro->GetTempVars(GetSegment());
|
||||
for (const auto &var : vars) {
|
||||
QVariant variant;
|
||||
variant.setValue(var.GetRef());
|
||||
_selection->addItem(QString::fromStdString(var.Name()),
|
||||
variant);
|
||||
}
|
||||
|
||||
// Make sure content is readable when expanding combobox
|
||||
auto view = _selection->view();
|
||||
if (view) {
|
||||
view->setMinimumWidth(view->sizeHintForColumn(0));
|
||||
_selection->setMinimumWidth(view->sizeHintForColumn(0));
|
||||
view->updateGeometry();
|
||||
_selection->updateGeometry();
|
||||
}
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void TempVariableSelection::HighlightSelection(const TempVariableRef &var)
|
||||
{
|
||||
auto advssWindow = qobject_cast<AdvSceneSwitcher *>(window());
|
||||
if (!advssWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto type = var.GetType();
|
||||
switch (type) {
|
||||
case TempVariableRef::SegmentType::NONE:
|
||||
return;
|
||||
case TempVariableRef::SegmentType::CONDITION:
|
||||
advssWindow->HighlightCondition(var.GetIdx(), Qt::white);
|
||||
return;
|
||||
case TempVariableRef::SegmentType::ACTION:
|
||||
advssWindow->HighlightAction(var.GetIdx(), Qt::white);
|
||||
return;
|
||||
case TempVariableRef::SegmentType::ELSEACTION:
|
||||
advssWindow->HighlightElseAction(var.GetIdx(), Qt::white);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString TempVariableSelection::SetupInfoLabel()
|
||||
{
|
||||
auto currentSelection = _selection->itemData(_selection->currentIndex())
|
||||
.value<TempVariableRef>();
|
||||
auto advssWindow = qobject_cast<AdvSceneSwitcher *>(window());
|
||||
if (!advssWindow) {
|
||||
_info->setToolTip("");
|
||||
_info->hide();
|
||||
return "";
|
||||
}
|
||||
auto macro = advssWindow->GetSelectedMacro();
|
||||
if (!macro) {
|
||||
_info->setToolTip("");
|
||||
_info->hide();
|
||||
return "";
|
||||
}
|
||||
auto var = currentSelection.GetTempVariable(macro.get());
|
||||
if (!var) {
|
||||
_info->setToolTip("");
|
||||
_info->hide();
|
||||
return "";
|
||||
}
|
||||
auto description = QString::fromStdString(var->_description);
|
||||
std::lock_guard<std::mutex> lock(var->_lastValuesMutex);
|
||||
if (!var->_lastValues.empty()) {
|
||||
if (!description.isEmpty()) {
|
||||
description += QString("\n\n");
|
||||
}
|
||||
description +=
|
||||
QString(obs_module_text(
|
||||
"AdvSceneSwitcher.tempVar.selectionInfo.lastValues")) +
|
||||
"\n";
|
||||
for (const auto &value : var->_lastValues) {
|
||||
description += "\n" + QString::fromStdString(value);
|
||||
}
|
||||
}
|
||||
_info->setToolTip(description);
|
||||
_info->setVisible(!description.isEmpty());
|
||||
return description;
|
||||
}
|
||||
|
||||
MacroSegment *TempVariableSelection::GetSegment() const
|
||||
{
|
||||
const QWidget *widget = this;
|
||||
{
|
||||
while (widget) {
|
||||
if (qobject_cast<const MacroSegmentEdit *>(widget)) {
|
||||
break;
|
||||
}
|
||||
widget = widget->parentWidget();
|
||||
}
|
||||
}
|
||||
if (!widget) {
|
||||
return nullptr;
|
||||
}
|
||||
auto segmentWidget = qobject_cast<const MacroSegmentEdit *>(widget);
|
||||
return segmentWidget->Data().get();
|
||||
}
|
||||
|
||||
void NotifyUIAboutTempVarChange()
|
||||
{
|
||||
obs_queue_task(
|
||||
OBS_TASK_UI,
|
||||
[](void *) {
|
||||
if (!GetSwitcher()->settingsWindowOpened) {
|
||||
return;
|
||||
}
|
||||
AdvSceneSwitcher::window->SegmentTempVarsChanged();
|
||||
},
|
||||
nullptr, false);
|
||||
}
|
||||
|
||||
AutoUpdateTooltipLabel::AutoUpdateTooltipLabel(
|
||||
QWidget *parent, std::function<QString()> updateFunc)
|
||||
: QLabel(parent), _updateFunc(updateFunc), _timer(new QTimer(this))
|
||||
{
|
||||
connect(_timer, &QTimer::timeout, this,
|
||||
&AutoUpdateTooltipLabel::UpdateTooltip);
|
||||
}
|
||||
|
||||
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
|
||||
void AutoUpdateTooltipLabel::enterEvent(QEnterEvent *event)
|
||||
#else
|
||||
void AutoUpdateTooltipLabel::enterEvent(QEvent *event)
|
||||
#endif
|
||||
{
|
||||
_timer->start(1000);
|
||||
QLabel::enterEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::leaveEvent(QEvent *event)
|
||||
{
|
||||
_timer->stop();
|
||||
QLabel::leaveEvent(event);
|
||||
}
|
||||
|
||||
void AutoUpdateTooltipLabel::UpdateTooltip()
|
||||
{
|
||||
setToolTip(_updateFunc());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
132
src/utils/temp-variable.hpp
Normal file
132
src/utils/temp-variable.hpp
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
#pragma once
|
||||
#include "filter-combo-box.hpp"
|
||||
|
||||
#include <obs.hpp>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <QEnterEvent>
|
||||
#include <QEvent>
|
||||
#include <QLabel>
|
||||
#include <QTimer>
|
||||
#include <QStringList>
|
||||
#include <string>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class Macro;
|
||||
class MacroSegment;
|
||||
class TempVariableRef;
|
||||
class TempVariableSelection;
|
||||
|
||||
// TempVariables are variables that are local to a given macro.
|
||||
// They can be created and used by macro segments.
|
||||
//
|
||||
// For example, a condition could create the TempVariable holding the property
|
||||
// "user name" which then might be used by a action to change the settings of a
|
||||
// source in OBS.
|
||||
|
||||
class TempVariable {
|
||||
public:
|
||||
TempVariable(const std::string &id, const std::string &name,
|
||||
const std::string &description,
|
||||
const std::shared_ptr<MacroSegment> &);
|
||||
TempVariable() = default;
|
||||
~TempVariable() = default;
|
||||
TempVariable(const TempVariable &) noexcept;
|
||||
TempVariable(const TempVariable &&) noexcept;
|
||||
TempVariable &operator=(const TempVariable &) noexcept;
|
||||
TempVariable &operator=(const TempVariable &&) noexcept;
|
||||
|
||||
std::string ID() const { return _id; }
|
||||
std::weak_ptr<MacroSegment> Segment() const { return _segment; }
|
||||
std::string Name() const { return _name; }
|
||||
std::optional<std::string> Value() const;
|
||||
void SetValue(const std::string &val);
|
||||
void InvalidateValue();
|
||||
TempVariableRef GetRef() const;
|
||||
|
||||
private:
|
||||
std::string _id = "";
|
||||
std::string _value = "";
|
||||
std::string _name = "";
|
||||
std::string _description = "";
|
||||
mutable std::mutex _lastValuesMutex;
|
||||
std::vector<std::string> _lastValues;
|
||||
bool _valueIsValid = false;
|
||||
|
||||
std::weak_ptr<MacroSegment> _segment;
|
||||
friend TempVariableSelection;
|
||||
friend TempVariableRef;
|
||||
};
|
||||
|
||||
class TempVariableRef {
|
||||
public:
|
||||
void Save(obs_data_t *, const char *name = "tempVar") const;
|
||||
void Load(obs_data_t *, Macro *, const char *name = "tempVar");
|
||||
std::optional<const TempVariable> GetTempVariable(Macro *) const;
|
||||
bool operator==(const TempVariableRef &other) const;
|
||||
|
||||
private:
|
||||
enum class SegmentType { NONE, CONDITION, ACTION, ELSEACTION };
|
||||
SegmentType GetType() const;
|
||||
int GetIdx() const;
|
||||
void PostLoad(int idx, SegmentType, Macro *);
|
||||
|
||||
std::string _id = "";
|
||||
std::weak_ptr<MacroSegment> _segment;
|
||||
friend TempVariable;
|
||||
friend TempVariableSelection;
|
||||
};
|
||||
|
||||
class AutoUpdateTooltipLabel : public QLabel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AutoUpdateTooltipLabel(QWidget *parent,
|
||||
std::function<QString()> updateFunc);
|
||||
|
||||
protected:
|
||||
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
|
||||
void enterEvent(QEnterEvent *event) override;
|
||||
#else
|
||||
void enterEvent(QEvent *event) override;
|
||||
#endif
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void UpdateTooltip();
|
||||
|
||||
private:
|
||||
std::function<QString()> _updateFunc;
|
||||
QTimer *_timer;
|
||||
};
|
||||
|
||||
class TempVariableSelection : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TempVariableSelection(QWidget *parent);
|
||||
void SetVariable(const TempVariableRef &);
|
||||
|
||||
private slots:
|
||||
void SelectionIdxChanged(int);
|
||||
void MacroSegmentsChanged();
|
||||
void SegmentTempVarsChanged();
|
||||
void HighlightChanged(int);
|
||||
|
||||
signals:
|
||||
void SelectionChanged(const TempVariableRef &);
|
||||
|
||||
private:
|
||||
void PopulateSelection();
|
||||
void HighlightSelection(const TempVariableRef &);
|
||||
QString SetupInfoLabel();
|
||||
MacroSegment *GetSegment() const;
|
||||
|
||||
FilterComboBox *_selection;
|
||||
AutoUpdateTooltipLabel *_info;
|
||||
};
|
||||
|
||||
void NotifyUIAboutTempVarChange();
|
||||
|
||||
} // namespace advss
|
||||
Loading…
Reference in New Issue
Block a user