mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-10-24 17:44:14 -05:00
Add variable action options
* Current scene * Previous scene * Preview scene * Current transition * Date / time * Date / time with offset * Unix timestamp * Time since last scene change * Json array length * Set json field * Format number
This commit is contained in:
@@ -129,6 +129,8 @@ target_sources(
|
||||
lib/macro/macro-action-variable-scene.hpp
|
||||
lib/macro/macro-action-variable-string.cpp
|
||||
lib/macro/macro-action-variable-string.hpp
|
||||
lib/macro/macro-action-variable-time.cpp
|
||||
lib/macro/macro-action-variable-time.hpp
|
||||
lib/macro/macro-action-variable.cpp
|
||||
lib/macro/macro-action-variable.hpp
|
||||
lib/macro/macro-action.cpp
|
||||
|
||||
@@ -1382,6 +1382,15 @@ AdvSceneSwitcher.action.variable.type.mathExpression="Mathematical expression"
|
||||
AdvSceneSwitcher.action.variable.type.askForValue="Get user input"
|
||||
AdvSceneSwitcher.action.variable.type.environmentVariable="Set to environment variable value"
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemCount="Set to scene item count of scene"
|
||||
AdvSceneSwitcher.action.variable.type.currentScene="Set to current scene name"
|
||||
AdvSceneSwitcher.action.variable.type.previousScene="Set to previous scene name"
|
||||
AdvSceneSwitcher.action.variable.type.previewScene="Set to preview scene name"
|
||||
AdvSceneSwitcher.action.variable.type.currentTransition="Set to current transition name"
|
||||
AdvSceneSwitcher.action.variable.type.currentDateTime="Set to current date and time"
|
||||
AdvSceneSwitcher.action.variable.type.dateTimeWithOffset="Set to date and time with offset"
|
||||
AdvSceneSwitcher.action.variable.type.unixTimestamp="Set to Unix timestamp"
|
||||
AdvSceneSwitcher.action.variable.type.timeSinceSceneChange="Set to time since last scene change"
|
||||
AdvSceneSwitcher.action.variable.type.currentDateTime.help="Uses the Qt date format syntax.\nFor example:\n\n • yyyy-MM-dd -> 2026-10-19\n • dd.MM.yyyy hh:mm:ss -> 19.10.2026 14:05:09\n • dddd, MMMM d -> Monday, October 19\n\nText in single quotes is copied as is."
|
||||
AdvSceneSwitcher.action.variable.type.stringLength="Set to length of string"
|
||||
AdvSceneSwitcher.action.variable.type.extractJsonField="Extract JSON field with name"
|
||||
AdvSceneSwitcher.action.variable.type.queryJson="Query JSON"
|
||||
@@ -1389,6 +1398,9 @@ AdvSceneSwitcher.action.variable.type.queryJson.info="You can use \"JSONPath\" (
|
||||
AdvSceneSwitcher.action.variable.type.queryJson.extractSingle="Extract value if single result"
|
||||
AdvSceneSwitcher.action.variable.type.queryJson.extractSingle.info="When enabled and the query returns exactly one result, the value is extracted from the result array and stored directly.\nIf the query matches zero or more than one element, the full JSON array is stored as usual."
|
||||
AdvSceneSwitcher.action.variable.type.accessJsonArray="Access JSON array at index"
|
||||
AdvSceneSwitcher.action.variable.type.jsonArrayLength="Get length of JSON array"
|
||||
AdvSceneSwitcher.action.variable.type.setJsonField="Set JSON field"
|
||||
AdvSceneSwitcher.action.variable.type.formatNumber="Format number"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar="Set to macro property"
|
||||
AdvSceneSwitcher.action.variable.type.setToTempvar.help="This action type will allow you to extract values out of segments of the current macro and assign those values to the selected variable.\nFor example, you can get the current scene name from a scene condition and assign this name to a variable."
|
||||
AdvSceneSwitcher.action.variable.type.sceneItemName="Set to scene item name at index"
|
||||
@@ -1425,6 +1437,7 @@ AdvSceneSwitcher.action.variable.layout.variable2="{{actions}}{{variables}}{{var
|
||||
AdvSceneSwitcher.action.variable.layout.changeCase="{{actions}}{{variables}}{{caseType}}"
|
||||
AdvSceneSwitcher.action.variable.layout.queryJson="{{actions}}{{variables}}{{jsonQuery}}{{jsonQueryHelp}}"
|
||||
AdvSceneSwitcher.action.variable.layout.accessJsonArray="{{actions}}{{variables}}{{jsonIndex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.jsonArrayLength="{{actions}}{{variables2}}and store it in{{variables}}"
|
||||
AdvSceneSwitcher.action.variable.layout.setToTempvar="{{actions}}{{variables}}{{tempVars}}{{tempVarsHelp}}"
|
||||
AdvSceneSwitcher.action.variable.layout.segmentValue="{{actions}}{{variables}}{{segmentIndex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.mathExpression="{{actions}}{{variables}}{{mathExpression}}"
|
||||
@@ -1432,6 +1445,11 @@ AdvSceneSwitcher.action.variable.layout.numValue="{{actions}}{{variables}}{{numV
|
||||
AdvSceneSwitcher.action.variable.layout.environmentVariable="{{actions}}{{variables}}{{envVariableName}}"
|
||||
AdvSceneSwitcher.action.variable.layout.sceneItemName="{{actions}}{{variables}}{{scenes}}{{sceneItemIndex}}"
|
||||
AdvSceneSwitcher.action.variable.layout.sceneItemCount="{{actions}}{{variables}}{{scenes}}"
|
||||
AdvSceneSwitcher.action.variable.layout.currentDateTime="{{actions}}{{variables}}using format{{dateFormat}}{{dateFormatHelp}}"
|
||||
AdvSceneSwitcher.action.variable.layout.dateTimeWithOffset="{{actions}}{{variables}}shifted by{{dateOffset}}{{dateOffsetUnit}}using format{{dateFormat}}{{dateFormatHelp}}"
|
||||
AdvSceneSwitcher.action.variable.layout.timeUnit="{{actions}}{{variables}}in{{timeUnit}}"
|
||||
AdvSceneSwitcher.action.variable.layout.setJsonField="{{actions}}{{strValue}}of{{variables}}to{{jsonValue}}"
|
||||
AdvSceneSwitcher.action.variable.layout.formatNumber="{{actions}}{{variables}}with{{decimalPlaces}}decimal places{{groupDigits}}use thousands separator"
|
||||
AdvSceneSwitcher.action.variable.layout.copy="{{actions}}{{variables2}}to{{variables}}"
|
||||
AdvSceneSwitcher.action.variable.layout.pad="{{actions}}of{{variables}}to length{{stringLength}}by adding{{paddingCharSelection}}to the{{direction}}"
|
||||
AdvSceneSwitcher.action.variable.layout.truncate="{{actions}}of{{variables}}to length{{stringLength}}by removing characters from the{{direction}}"
|
||||
|
||||
@@ -17,6 +17,12 @@ static bool registered = RegisterVariableActionGroup(
|
||||
{Action::ARRAY_JSON,
|
||||
"AdvSceneSwitcher.action.variable.type.accessJsonArray",
|
||||
"AdvSceneSwitcher.action.variable.layout.accessJsonArray"},
|
||||
{Action::JSON_ARRAY_LENGTH,
|
||||
"AdvSceneSwitcher.action.variable.type.jsonArrayLength",
|
||||
"AdvSceneSwitcher.action.variable.layout.jsonArrayLength"},
|
||||
{Action::SET_JSON_FIELD,
|
||||
"AdvSceneSwitcher.action.variable.type.setJsonField",
|
||||
"AdvSceneSwitcher.action.variable.layout.setJsonField", true},
|
||||
},
|
||||
[]() { return std::make_unique<VariableActionJson>(); },
|
||||
VariableActionJsonEdit::Create});
|
||||
@@ -33,6 +39,7 @@ void VariableActionJson::Save(obs_data_t *obj,
|
||||
_jsonIndex.Save(obj, "jsonIndex");
|
||||
obs_data_set_bool(obj, "jsonQueryExtractSingle",
|
||||
_jsonQueryExtractSingle);
|
||||
_jsonValue.Save(obj, "jsonValue");
|
||||
}
|
||||
|
||||
void VariableActionJson::Load(obs_data_t *obj, MacroActionVariable &)
|
||||
@@ -41,12 +48,16 @@ void VariableActionJson::Load(obs_data_t *obj, MacroActionVariable &)
|
||||
_jsonIndex.Load(obj, "jsonIndex");
|
||||
_jsonQueryExtractSingle =
|
||||
obs_data_get_bool(obj, "jsonQueryExtractSingle");
|
||||
if (obs_data_has_user_value(obj, "jsonValue")) {
|
||||
_jsonValue.Load(obj, "jsonValue");
|
||||
}
|
||||
}
|
||||
|
||||
void VariableActionJson::ResolveVariables()
|
||||
{
|
||||
_jsonQuery.ResolveVariables();
|
||||
_jsonIndex.ResolveVariables();
|
||||
_jsonValue.ResolveVariables();
|
||||
}
|
||||
|
||||
bool VariableActionJson::Perform(MacroActionVariable &action,
|
||||
@@ -89,6 +100,27 @@ bool VariableActionJson::Perform(MacroActionVariable &action,
|
||||
var.SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
case Action::JSON_ARRAY_LENGTH: {
|
||||
auto input = action._variable2.lock();
|
||||
if (!input) {
|
||||
return true;
|
||||
}
|
||||
auto length = GetJsonArrayLength(input->Value());
|
||||
if (!length.has_value()) {
|
||||
return true;
|
||||
}
|
||||
var.SetValue(*length);
|
||||
return true;
|
||||
}
|
||||
case Action::SET_JSON_FIELD: {
|
||||
auto value =
|
||||
SetJsonField(var.Value(), action._strValue, _jsonValue);
|
||||
if (!value.has_value()) {
|
||||
return true;
|
||||
}
|
||||
var.SetValue(*value);
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
@@ -112,7 +144,8 @@ VariableActionJsonEdit::VariableActionJsonEdit(
|
||||
_jsonExtractSingleHelp(new HelpIcon(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.queryJson.extractSingle.info"),
|
||||
this))
|
||||
this)),
|
||||
_jsonValue(new VariableTextEdit(this, 5, 1, 1))
|
||||
{
|
||||
_jsonIndex->setMaximum(999);
|
||||
|
||||
@@ -124,6 +157,8 @@ VariableActionJsonEdit::VariableActionJsonEdit(
|
||||
this, SLOT(JsonIndexChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(_jsonExtractSingle, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(JsonQueryExtractSingleChanged(int)));
|
||||
QWidget::connect(_jsonValue, SIGNAL(textChanged()), this,
|
||||
SLOT(JsonValueChanged()));
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
@@ -147,6 +182,7 @@ VariableActionJsonEdit::GetInlineWidgets()
|
||||
{"{{jsonQuery}}", _jsonQuery},
|
||||
{"{{jsonQueryHelp}}", _jsonQueryHelp},
|
||||
{"{{jsonIndex}}", _jsonIndex},
|
||||
{"{{jsonValue}}", _jsonValue},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -159,6 +195,7 @@ void VariableActionJsonEdit::UpdateEntryData()
|
||||
_jsonQuery->setText(_data->_jsonQuery);
|
||||
_jsonIndex->SetValue(_data->_jsonIndex);
|
||||
_jsonExtractSingle->setChecked(_data->_jsonQueryExtractSingle);
|
||||
_jsonValue->setPlainText(_data->_jsonValue);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -186,4 +223,11 @@ void VariableActionJsonEdit::JsonQueryExtractSingleChanged(int value)
|
||||
_data->_jsonQueryExtractSingle = value;
|
||||
}
|
||||
|
||||
void VariableActionJsonEdit::JsonValueChanged()
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_data->_jsonValue = _jsonValue->toPlainText().toStdString();
|
||||
UpdateSize();
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
StringVariable _jsonQuery = "$.some.nested.value";
|
||||
IntVariable _jsonIndex = 0;
|
||||
bool _jsonQueryExtractSingle = true;
|
||||
StringVariable _jsonValue = "value";
|
||||
};
|
||||
|
||||
class VariableActionJsonEdit : public VariableActionGroupEdit {
|
||||
@@ -36,6 +37,7 @@ private slots:
|
||||
void JsonQueryChanged();
|
||||
void JsonIndexChanged(const NumberVariable<int> &);
|
||||
void JsonQueryExtractSingleChanged(int);
|
||||
void JsonValueChanged();
|
||||
|
||||
private:
|
||||
VariableActionJson *_data;
|
||||
@@ -45,6 +47,7 @@ private:
|
||||
VariableSpinBox *_jsonIndex;
|
||||
QCheckBox *_jsonExtractSingle;
|
||||
HelpIcon *_jsonExtractSingleHelp;
|
||||
VariableTextEdit *_jsonValue;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include "log-helper.hpp"
|
||||
#include "math-helpers.hpp"
|
||||
|
||||
#include <QLocale>
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace advss {
|
||||
@@ -24,6 +26,9 @@ static bool registered = RegisterVariableActionGroup(
|
||||
"AdvSceneSwitcher.action.variable.layout.numValue"},
|
||||
{Action::ROUND_TO_INT,
|
||||
"AdvSceneSwitcher.action.variable.type.roundToInt"},
|
||||
{Action::FORMAT_NUMBER,
|
||||
"AdvSceneSwitcher.action.variable.type.formatNumber",
|
||||
"AdvSceneSwitcher.action.variable.layout.formatNumber"},
|
||||
{Action::RANDOM_NUMBER,
|
||||
"AdvSceneSwitcher.action.variable.type.randomNumber"},
|
||||
{Action::RANDOM_LIST_VALUE,
|
||||
@@ -61,6 +66,8 @@ void VariableActionMath::Save(obs_data_t *obj,
|
||||
obs_data_set_bool(obj, "generateInteger", _generateInteger);
|
||||
_randomValues.Save(obj, "randomValues", "value");
|
||||
obs_data_set_bool(obj, "allowRepeatValues", _allowRepeatValues);
|
||||
_decimalPlaces.Save(obj, "decimalPlaces");
|
||||
obs_data_set_bool(obj, "groupDigits", _groupDigits);
|
||||
}
|
||||
|
||||
void VariableActionMath::Load(obs_data_t *obj, MacroActionVariable &)
|
||||
@@ -80,11 +87,31 @@ void VariableActionMath::Load(obs_data_t *obj, MacroActionVariable &)
|
||||
_generateInteger = obs_data_get_bool(obj, "generateInteger");
|
||||
_randomValues.Load(obj, "randomValues", "value");
|
||||
_allowRepeatValues = obs_data_get_bool(obj, "allowRepeatValues");
|
||||
if (obs_data_has_user_value(obj, "decimalPlaces")) {
|
||||
_decimalPlaces.Load(obj, "decimalPlaces");
|
||||
}
|
||||
_groupDigits = obs_data_get_bool(obj, "groupDigits");
|
||||
}
|
||||
|
||||
void VariableActionMath::ResolveVariables()
|
||||
{
|
||||
_mathExpression.ResolveVariables();
|
||||
_decimalPlaces.ResolveVariables();
|
||||
}
|
||||
|
||||
void VariableActionMath::FormatNumber(Variable &var)
|
||||
{
|
||||
auto value = var.DoubleValue();
|
||||
if (!value.has_value()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// C locale to keep the output parsable by other variable actions
|
||||
auto locale = QLocale::c();
|
||||
locale.setNumberOptions(_groupDigits ? QLocale::NumberOptions()
|
||||
: QLocale::OmitGroupSeparator);
|
||||
var.SetValue(locale.toString(*value, 'f', _decimalPlaces.GetValue())
|
||||
.toStdString());
|
||||
}
|
||||
|
||||
void VariableActionMath::HandleMathExpression(Variable &var)
|
||||
@@ -177,6 +204,9 @@ bool VariableActionMath::Perform(MacroActionVariable &,
|
||||
var.SetValue(std::to_string(int(std::round(*curValue))));
|
||||
break;
|
||||
}
|
||||
case Action::FORMAT_NUMBER:
|
||||
FormatNumber(var);
|
||||
break;
|
||||
case Action::RANDOM_NUMBER:
|
||||
GenerateRandomNumber(var);
|
||||
break;
|
||||
@@ -209,8 +239,12 @@ VariableActionMathEdit::VariableActionMathEdit(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.allowRepeat"),
|
||||
this)),
|
||||
_randomValueLayout(new QVBoxLayout())
|
||||
_randomValueLayout(new QVBoxLayout()),
|
||||
_decimalPlaces(new VariableSpinBox(this)),
|
||||
_groupDigits(new QCheckBox(this))
|
||||
{
|
||||
_decimalPlaces->setMinimum(0);
|
||||
_decimalPlaces->setMaximum(15);
|
||||
_numValue->setMinimum(-9999999999);
|
||||
_numValue->setMaximum(9999999999);
|
||||
_randomNumberStart->setMinimum(-9999999999);
|
||||
@@ -242,6 +276,12 @@ VariableActionMathEdit::VariableActionMathEdit(
|
||||
SLOT(RandomValueListChanged(const StringList &)));
|
||||
QWidget::connect(_allowRepeatValues, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(AllowRepeatValuesChanged(int)));
|
||||
QWidget::connect(
|
||||
_decimalPlaces,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(DecimalPlacesChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(_groupDigits, SIGNAL(stateChanged(int)), this,
|
||||
SLOT(GroupDigitsChanged(int)));
|
||||
|
||||
auto randomLayout = new QHBoxLayout();
|
||||
PlaceWidgets(
|
||||
@@ -277,6 +317,8 @@ VariableActionMathEdit::GetInlineWidgets()
|
||||
return {
|
||||
{"{{numValue}}", _numValue},
|
||||
{"{{mathExpression}}", _mathExpression},
|
||||
{"{{decimalPlaces}}", _decimalPlaces},
|
||||
{"{{groupDigits}}", _groupDigits},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -293,6 +335,8 @@ void VariableActionMathEdit::UpdateEntryData()
|
||||
_generateInteger->setChecked(_data->_generateInteger);
|
||||
_allowRepeatValues->setChecked(_data->_allowRepeatValues);
|
||||
_randomValues->SetStringList(_data->_randomValues);
|
||||
_decimalPlaces->SetValue(_data->_decimalPlaces);
|
||||
_groupDigits->setChecked(_data->_groupDigits);
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
@@ -363,4 +407,17 @@ void VariableActionMathEdit::AllowRepeatValuesChanged(int value)
|
||||
_data->_allowRepeatValues = value;
|
||||
}
|
||||
|
||||
void VariableActionMathEdit::DecimalPlacesChanged(
|
||||
const NumberVariable<int> &value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_data->_decimalPlaces = value;
|
||||
}
|
||||
|
||||
void VariableActionMathEdit::GroupDigitsChanged(int value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_data->_groupDigits = value;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -25,9 +25,12 @@ public:
|
||||
bool _generateInteger = true;
|
||||
StringList _randomValues = {"value1", "value2", "value3"};
|
||||
bool _allowRepeatValues = true;
|
||||
IntVariable _decimalPlaces = 2;
|
||||
bool _groupDigits = false;
|
||||
|
||||
private:
|
||||
void HandleMathExpression(Variable &);
|
||||
void FormatNumber(Variable &);
|
||||
void GenerateRandomNumber(Variable &);
|
||||
void PickRandomValue(Variable &);
|
||||
|
||||
@@ -54,6 +57,8 @@ private slots:
|
||||
void GenerateIntegerChanged(int);
|
||||
void RandomValueListChanged(const StringList &);
|
||||
void AllowRepeatValuesChanged(int);
|
||||
void DecimalPlacesChanged(const NumberVariable<int> &);
|
||||
void GroupDigitsChanged(int);
|
||||
|
||||
private:
|
||||
VariableActionMath *_data;
|
||||
@@ -68,6 +73,8 @@ private:
|
||||
StringListEdit *_randomValues;
|
||||
QCheckBox *_allowRepeatValues;
|
||||
QVBoxLayout *_randomValueLayout;
|
||||
VariableSpinBox *_decimalPlaces;
|
||||
QCheckBox *_groupDigits;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#include "macro-action-variable-scene.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
#include "source-helpers.hpp"
|
||||
|
||||
#include <obs-frontend-api.h>
|
||||
|
||||
namespace advss {
|
||||
|
||||
using Action = MacroActionVariable::Action;
|
||||
@@ -8,6 +11,14 @@ using Action = MacroActionVariable::Action;
|
||||
static bool registered = RegisterVariableActionGroup(
|
||||
{60,
|
||||
{
|
||||
{Action::CURRENT_SCENE,
|
||||
"AdvSceneSwitcher.action.variable.type.currentScene"},
|
||||
{Action::PREVIOUS_SCENE,
|
||||
"AdvSceneSwitcher.action.variable.type.previousScene"},
|
||||
{Action::PREVIEW_SCENE,
|
||||
"AdvSceneSwitcher.action.variable.type.previewScene"},
|
||||
{Action::CURRENT_TRANSITION,
|
||||
"AdvSceneSwitcher.action.variable.type.currentTransition"},
|
||||
{Action::SCENE_ITEM_NAME,
|
||||
"AdvSceneSwitcher.action.variable.type.sceneItemName",
|
||||
"AdvSceneSwitcher.action.variable.layout.sceneItemName"},
|
||||
@@ -96,6 +107,25 @@ bool VariableActionScene::Perform(MacroActionVariable &,
|
||||
case Action::SCENE_ITEM_COUNT:
|
||||
var.SetValue(GetSceneItemCount(_scene.GetScene(false)));
|
||||
break;
|
||||
case Action::CURRENT_SCENE:
|
||||
var.SetValue(GetWeakSourceName(GetCurrentScene()));
|
||||
break;
|
||||
case Action::PREVIOUS_SCENE:
|
||||
var.SetValue(GetWeakSourceName(GetPreviousScene()));
|
||||
break;
|
||||
case Action::PREVIEW_SCENE: {
|
||||
// Only available in studio mode
|
||||
OBSSourceAutoRelease scene =
|
||||
obs_frontend_get_current_preview_scene();
|
||||
var.SetValue(scene ? obs_source_get_name(scene) : "");
|
||||
break;
|
||||
}
|
||||
case Action::CURRENT_TRANSITION: {
|
||||
OBSSourceAutoRelease transition =
|
||||
obs_frontend_get_current_transition();
|
||||
var.SetValue(transition ? obs_source_get_name(transition) : "");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
268
lib/macro/macro-action-variable-time.cpp
Normal file
268
lib/macro/macro-action-variable-time.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
#include "macro-action-variable-time.hpp"
|
||||
#include "scene-switch-helpers.hpp"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
namespace advss {
|
||||
|
||||
using Action = MacroActionVariable::Action;
|
||||
|
||||
static bool registered = RegisterVariableActionGroup(
|
||||
{70,
|
||||
{
|
||||
{Action::CURRENT_DATE_TIME,
|
||||
"AdvSceneSwitcher.action.variable.type.currentDateTime",
|
||||
"AdvSceneSwitcher.action.variable.layout.currentDateTime",
|
||||
true},
|
||||
{Action::DATE_TIME_WITH_OFFSET,
|
||||
"AdvSceneSwitcher.action.variable.type.dateTimeWithOffset",
|
||||
"AdvSceneSwitcher.action.variable.layout.dateTimeWithOffset",
|
||||
true},
|
||||
{Action::UNIX_TIMESTAMP,
|
||||
"AdvSceneSwitcher.action.variable.type.unixTimestamp",
|
||||
"AdvSceneSwitcher.action.variable.layout.timeUnit"},
|
||||
{Action::TIME_SINCE_SCENE_CHANGE,
|
||||
"AdvSceneSwitcher.action.variable.type.timeSinceSceneChange",
|
||||
"AdvSceneSwitcher.action.variable.layout.timeUnit"},
|
||||
},
|
||||
[]() { return std::make_unique<VariableActionTime>(); },
|
||||
VariableActionTimeEdit::Create});
|
||||
|
||||
std::unique_ptr<VariableActionGroup> VariableActionTime::Copy() const
|
||||
{
|
||||
return std::make_unique<VariableActionTime>(*this);
|
||||
}
|
||||
|
||||
void VariableActionTime::Save(obs_data_t *obj,
|
||||
const MacroActionVariable &) const
|
||||
{
|
||||
_dateFormat.Save(obj, "dateFormat");
|
||||
obs_data_set_int(obj, "timeUnit", static_cast<int>(_timeUnit));
|
||||
_dateOffset.Save(obj, "dateOffset");
|
||||
obs_data_set_int(obj, "dateOffsetUnit",
|
||||
static_cast<int>(_dateOffsetUnit));
|
||||
}
|
||||
|
||||
void VariableActionTime::Load(obs_data_t *obj, MacroActionVariable &)
|
||||
{
|
||||
if (obs_data_has_user_value(obj, "dateFormat")) {
|
||||
_dateFormat.Load(obj, "dateFormat");
|
||||
}
|
||||
_timeUnit = static_cast<TimeUnit>(obs_data_get_int(obj, "timeUnit"));
|
||||
if (obs_data_has_user_value(obj, "dateOffset")) {
|
||||
_dateOffset.Load(obj, "dateOffset");
|
||||
}
|
||||
obs_data_set_default_int(obj, "dateOffsetUnit",
|
||||
static_cast<int>(OffsetUnit::DAYS));
|
||||
_dateOffsetUnit = static_cast<OffsetUnit>(
|
||||
obs_data_get_int(obj, "dateOffsetUnit"));
|
||||
}
|
||||
|
||||
void VariableActionTime::ResolveVariables()
|
||||
{
|
||||
_dateFormat.ResolveVariables();
|
||||
_dateOffset.ResolveVariables();
|
||||
}
|
||||
|
||||
void VariableActionTime::SetToTimeSinceSceneChange(Variable &var) const
|
||||
{
|
||||
const auto lastChange = GetLastSceneChangeTime();
|
||||
// Default constructed until the first scene change was observed
|
||||
if (lastChange == std::chrono::high_resolution_clock::time_point{}) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto elapsed =
|
||||
std::chrono::high_resolution_clock::now() - lastChange;
|
||||
if (_timeUnit == TimeUnit::MILLISECONDS) {
|
||||
var.SetValue(std::to_string(
|
||||
std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
elapsed)
|
||||
.count()));
|
||||
return;
|
||||
}
|
||||
var.SetValue(std::to_string(
|
||||
std::chrono::duration_cast<std::chrono::seconds>(elapsed)
|
||||
.count()));
|
||||
}
|
||||
|
||||
QDateTime VariableActionTime::GetDateTimeWithOffset() const
|
||||
{
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
const int offset = _dateOffset.GetValue();
|
||||
|
||||
switch (_dateOffsetUnit) {
|
||||
case OffsetUnit::SECONDS:
|
||||
return now.addSecs(offset);
|
||||
case OffsetUnit::MINUTES:
|
||||
return now.addSecs(static_cast<qint64>(offset) * 60);
|
||||
case OffsetUnit::HOURS:
|
||||
return now.addSecs(static_cast<qint64>(offset) * 60 * 60);
|
||||
case OffsetUnit::DAYS:
|
||||
return now.addDays(offset);
|
||||
case OffsetUnit::WEEKS:
|
||||
return now.addDays(static_cast<qint64>(offset) * 7);
|
||||
case OffsetUnit::MONTHS:
|
||||
return now.addMonths(offset);
|
||||
case OffsetUnit::YEARS:
|
||||
return now.addYears(offset);
|
||||
}
|
||||
return now;
|
||||
}
|
||||
|
||||
bool VariableActionTime::Perform(MacroActionVariable &,
|
||||
MacroActionVariable::Action type,
|
||||
Variable &var)
|
||||
{
|
||||
const auto format = QString::fromStdString(_dateFormat);
|
||||
|
||||
switch (type) {
|
||||
case Action::CURRENT_DATE_TIME:
|
||||
var.SetValue(QDateTime::currentDateTime()
|
||||
.toString(format)
|
||||
.toStdString());
|
||||
break;
|
||||
case Action::DATE_TIME_WITH_OFFSET:
|
||||
var.SetValue(
|
||||
GetDateTimeWithOffset().toString(format).toStdString());
|
||||
break;
|
||||
case Action::UNIX_TIMESTAMP: {
|
||||
const auto now = QDateTime::currentDateTime();
|
||||
const auto timestamp = _timeUnit == TimeUnit::MILLISECONDS
|
||||
? now.toMSecsSinceEpoch()
|
||||
: now.toSecsSinceEpoch();
|
||||
var.SetValue(std::to_string(timestamp));
|
||||
break;
|
||||
}
|
||||
case Action::TIME_SINCE_SCENE_CHANGE:
|
||||
SetToTimeSinceSceneChange(var);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void populateTimeUnitSelection(QComboBox *list)
|
||||
{
|
||||
list->addItem(obs_module_text("AdvSceneSwitcher.unit.seconds"),
|
||||
static_cast<int>(VariableActionTime::TimeUnit::SECONDS));
|
||||
list->addItem(
|
||||
obs_module_text("AdvSceneSwitcher.unit.milliseconds"),
|
||||
static_cast<int>(VariableActionTime::TimeUnit::MILLISECONDS));
|
||||
}
|
||||
|
||||
static void populateOffsetUnitSelection(QComboBox *list)
|
||||
{
|
||||
using Unit = VariableActionTime::OffsetUnit;
|
||||
const std::vector<std::pair<Unit, const char *>> units = {
|
||||
{Unit::SECONDS, "AdvSceneSwitcher.unit.seconds"},
|
||||
{Unit::MINUTES, "AdvSceneSwitcher.unit.minutes"},
|
||||
{Unit::HOURS, "AdvSceneSwitcher.unit.hours"},
|
||||
{Unit::DAYS, "AdvSceneSwitcher.unit.days"},
|
||||
{Unit::WEEKS, "AdvSceneSwitcher.unit.weeks"},
|
||||
{Unit::MONTHS, "AdvSceneSwitcher.unit.months"},
|
||||
{Unit::YEARS, "AdvSceneSwitcher.unit.years"},
|
||||
};
|
||||
for (const auto &[unit, name] : units) {
|
||||
list->addItem(obs_module_text(name), static_cast<int>(unit));
|
||||
}
|
||||
}
|
||||
|
||||
VariableActionTimeEdit::VariableActionTimeEdit(
|
||||
QWidget *parent, std::shared_ptr<MacroActionVariable> entryData)
|
||||
: VariableActionGroupEdit(parent, entryData),
|
||||
_data(entryData ? entryData->GetGroup<VariableActionTime>()
|
||||
: nullptr),
|
||||
_dateFormat(new VariableLineEdit(this)),
|
||||
_dateFormatHelp(new HelpIcon(
|
||||
obs_module_text(
|
||||
"AdvSceneSwitcher.action.variable.type.currentDateTime.help"),
|
||||
this)),
|
||||
_timeUnit(new QComboBox(this)),
|
||||
_dateOffset(new VariableSpinBox(this)),
|
||||
_dateOffsetUnit(new QComboBox(this))
|
||||
{
|
||||
_dateOffset->setMinimum(-99999);
|
||||
_dateOffset->setMaximum(99999);
|
||||
populateTimeUnitSelection(_timeUnit);
|
||||
populateOffsetUnitSelection(_dateOffsetUnit);
|
||||
|
||||
QWidget::connect(_dateFormat, SIGNAL(editingFinished()), this,
|
||||
SLOT(DateFormatChanged()));
|
||||
QWidget::connect(_timeUnit, SIGNAL(currentIndexChanged(int)), this,
|
||||
SLOT(TimeUnitChanged(int)));
|
||||
QWidget::connect(
|
||||
_dateOffset,
|
||||
SIGNAL(NumberVariableChanged(const NumberVariable<int> &)),
|
||||
this, SLOT(DateOffsetChanged(const NumberVariable<int> &)));
|
||||
QWidget::connect(_dateOffsetUnit, SIGNAL(currentIndexChanged(int)),
|
||||
this, SLOT(DateOffsetUnitChanged(int)));
|
||||
}
|
||||
|
||||
VariableActionGroupEdit *
|
||||
VariableActionTimeEdit::Create(QWidget *parent,
|
||||
std::shared_ptr<MacroActionVariable> entryData)
|
||||
{
|
||||
return new VariableActionTimeEdit(parent, entryData);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, QWidget *>
|
||||
VariableActionTimeEdit::GetInlineWidgets()
|
||||
{
|
||||
return {
|
||||
{"{{dateFormat}}", _dateFormat},
|
||||
{"{{dateFormatHelp}}", _dateFormatHelp},
|
||||
{"{{timeUnit}}", _timeUnit},
|
||||
{"{{dateOffset}}", _dateOffset},
|
||||
{"{{dateOffsetUnit}}", _dateOffsetUnit},
|
||||
};
|
||||
}
|
||||
|
||||
void VariableActionTimeEdit::UpdateEntryData()
|
||||
{
|
||||
if (!_data) {
|
||||
return;
|
||||
}
|
||||
|
||||
_dateFormat->setText(_data->_dateFormat);
|
||||
_timeUnit->setCurrentIndex(
|
||||
_timeUnit->findData(static_cast<int>(_data->_timeUnit)));
|
||||
_dateOffset->SetValue(_data->_dateOffset);
|
||||
_dateOffsetUnit->setCurrentIndex(_dateOffsetUnit->findData(
|
||||
static_cast<int>(_data->_dateOffsetUnit)));
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
void VariableActionTimeEdit::SetWidgetVisibility(MacroActionVariable::Action)
|
||||
{
|
||||
hide();
|
||||
}
|
||||
|
||||
void VariableActionTimeEdit::DateFormatChanged()
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_data->_dateFormat = _dateFormat->text().toStdString();
|
||||
}
|
||||
|
||||
void VariableActionTimeEdit::TimeUnitChanged(int)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_data->_timeUnit = static_cast<VariableActionTime::TimeUnit>(
|
||||
_timeUnit->currentData().toInt());
|
||||
}
|
||||
|
||||
void VariableActionTimeEdit::DateOffsetChanged(const NumberVariable<int> &value)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_data->_dateOffset = value;
|
||||
}
|
||||
|
||||
void VariableActionTimeEdit::DateOffsetUnitChanged(int)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_data->_dateOffsetUnit = static_cast<VariableActionTime::OffsetUnit>(
|
||||
_dateOffsetUnit->currentData().toInt());
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
69
lib/macro/macro-action-variable-time.hpp
Normal file
69
lib/macro/macro-action-variable-time.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
#include "macro-action-variable-group.hpp"
|
||||
#include "help-icon.hpp"
|
||||
#include "variable-line-edit.hpp"
|
||||
#include "variable-spinbox.hpp"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class VariableActionTime : public VariableActionGroup {
|
||||
public:
|
||||
std::unique_ptr<VariableActionGroup> Copy() const override;
|
||||
void Save(obs_data_t *, const MacroActionVariable &) const override;
|
||||
void Load(obs_data_t *, MacroActionVariable &) override;
|
||||
void ResolveVariables() override;
|
||||
bool Perform(MacroActionVariable &, MacroActionVariable::Action,
|
||||
Variable &) override;
|
||||
|
||||
enum class TimeUnit { SECONDS, MILLISECONDS };
|
||||
enum class OffsetUnit {
|
||||
SECONDS,
|
||||
MINUTES,
|
||||
HOURS,
|
||||
DAYS,
|
||||
WEEKS,
|
||||
MONTHS,
|
||||
YEARS,
|
||||
};
|
||||
|
||||
StringVariable _dateFormat = "yyyy-MM-dd hh:mm:ss";
|
||||
TimeUnit _timeUnit = TimeUnit::SECONDS;
|
||||
IntVariable _dateOffset = 1;
|
||||
OffsetUnit _dateOffsetUnit = OffsetUnit::DAYS;
|
||||
|
||||
private:
|
||||
void SetToTimeSinceSceneChange(Variable &) const;
|
||||
QDateTime GetDateTimeWithOffset() const;
|
||||
};
|
||||
|
||||
class VariableActionTimeEdit : public VariableActionGroupEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
VariableActionTimeEdit(QWidget *parent,
|
||||
std::shared_ptr<MacroActionVariable> entryData);
|
||||
static VariableActionGroupEdit *
|
||||
Create(QWidget *parent, std::shared_ptr<MacroActionVariable> entryData);
|
||||
std::unordered_map<std::string, QWidget *> GetInlineWidgets() override;
|
||||
void UpdateEntryData() override;
|
||||
void SetWidgetVisibility(MacroActionVariable::Action) override;
|
||||
|
||||
private slots:
|
||||
void DateFormatChanged();
|
||||
void TimeUnitChanged(int);
|
||||
void DateOffsetChanged(const NumberVariable<int> &);
|
||||
void DateOffsetUnitChanged(int);
|
||||
|
||||
private:
|
||||
VariableActionTime *_data;
|
||||
|
||||
VariableLineEdit *_dateFormat;
|
||||
HelpIcon *_dateFormatHelp;
|
||||
QComboBox *_timeUnit;
|
||||
VariableSpinBox *_dateOffset;
|
||||
QComboBox *_dateOffsetUnit;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
@@ -67,6 +67,17 @@ public:
|
||||
ARRAY_JSON,
|
||||
COPY_VAR,
|
||||
RANDOM_LIST_VALUE,
|
||||
CURRENT_SCENE,
|
||||
PREVIOUS_SCENE,
|
||||
PREVIEW_SCENE,
|
||||
CURRENT_TRANSITION,
|
||||
CURRENT_DATE_TIME,
|
||||
DATE_TIME_WITH_OFFSET,
|
||||
UNIX_TIMESTAMP,
|
||||
TIME_SINCE_SCENE_CHANGE,
|
||||
JSON_ARRAY_LENGTH,
|
||||
SET_JSON_FIELD,
|
||||
FORMAT_NUMBER,
|
||||
};
|
||||
|
||||
Action _action = Action::SET_VALUE;
|
||||
|
||||
@@ -121,6 +121,44 @@ ExtractSingleJsonArrayElement(const std::string &jsonStr)
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<int> GetJsonArrayLength(const std::string &jsonStr)
|
||||
{
|
||||
try {
|
||||
nlohmann::json json = nlohmann::json::parse(jsonStr);
|
||||
if (!json.is_array()) {
|
||||
return {};
|
||||
}
|
||||
return static_cast<int>(json.size());
|
||||
} catch (const nlohmann::json::exception &) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> SetJsonField(const std::string &jsonStr,
|
||||
const std::string &id,
|
||||
const std::string &value)
|
||||
{
|
||||
try {
|
||||
auto json = jsonStr.empty() ? nlohmann::json::object()
|
||||
: nlohmann::json::parse(jsonStr);
|
||||
if (!json.is_object()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Store valid JSON values (numbers, objects, ...) as is and
|
||||
// everything else as a plain string
|
||||
auto parsedValue = nlohmann::json::parse(value, nullptr, false);
|
||||
if (parsedValue.is_discarded()) {
|
||||
json[id] = value;
|
||||
} else {
|
||||
json[id] = parsedValue;
|
||||
}
|
||||
return json.dump();
|
||||
} catch (const nlohmann::json::exception &) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
static void collectStrings(const nlohmann::json &json,
|
||||
std::vector<std::pair<std::string, int>> &result,
|
||||
std::unordered_map<std::string, size_t> &index)
|
||||
|
||||
@@ -21,6 +21,10 @@ EXPORT std::optional<std::string> AccessJsonArrayIndex(const std::string &json,
|
||||
const int index);
|
||||
EXPORT std::optional<std::string>
|
||||
ExtractSingleJsonArrayElement(const std::string &json);
|
||||
EXPORT std::optional<int> GetJsonArrayLength(const std::string &json);
|
||||
EXPORT std::optional<std::string> SetJsonField(const std::string &json,
|
||||
const std::string &id,
|
||||
const std::string &value);
|
||||
|
||||
EXPORT std::vector<std::pair<std::string, int>>
|
||||
CollectDistinctJsonStringValues(const std::string &json);
|
||||
|
||||
Reference in New Issue
Block a user