Variable related refactors

This commit is contained in:
Przemek Pawlas 2024-03-02 16:32:34 +01:00 committed by WarmUpTill
parent e265e4828e
commit eec9244e4c
6 changed files with 217 additions and 183 deletions

View File

@ -72,16 +72,18 @@ AdvSceneSwitcher.generalTab.transitionBehaviorSelectionError="At least one optio
; Variables Tab
AdvSceneSwitcher.variableTab.title="Variables"
AdvSceneSwitcher.variableTab.help="Variables can be used in many places throughout the plugin.\n\nClick on the highlighted plus symbol to add a new variable."
AdvSceneSwitcher.variableTab.tooltip.variableAddButton="Add new variable"
AdvSceneSwitcher.variableTab.tooltip.variableRemoveButton="Remove selected variables"
AdvSceneSwitcher.variableTab.header.name="Name"
AdvSceneSwitcher.variableTab.header.value="Value"
AdvSceneSwitcher.variableTab.header.saveLoadBehavior="Save/Load behavior"
AdvSceneSwitcher.variableTab.header.lastUse="Last used"
AdvSceneSwitcher.variableTab.header.lastChanged="Last changed"
AdvSceneSwitcher.variableTab.neverNused="Never"
AdvSceneSwitcher.variableTab.lastUsed="%1 seconds ago"
AdvSceneSwitcher.variableTab.lastChanged="%1 seconds ago"
AdvSceneSwitcher.variableTab.variableAddButton.tooltip="Add new variable"
AdvSceneSwitcher.variableTab.variableRemoveButton.tooltip="Remove selected variables"
AdvSceneSwitcher.variableTab.name.header="Name"
AdvSceneSwitcher.variableTab.value.header="Value"
AdvSceneSwitcher.variableTab.saveLoadBehavior.header="Save/Load behavior"
AdvSceneSwitcher.variableTab.saveLoadBehavior.text.default="Default to \"%1\""
AdvSceneSwitcher.variableTab.lastUsed.header="Last used"
AdvSceneSwitcher.variableTab.lastUsed.text="%1 seconds ago"
AdvSceneSwitcher.variableTab.lastUsed.text.never="Never"
AdvSceneSwitcher.variableTab.lastChanged.header="Last changed"
AdvSceneSwitcher.variableTab.lastChanged.text="%1 seconds ago"
AdvSceneSwitcher.variableTab.lastChanged.text.none="No change since launch"
AdvSceneSwitcher.variableTab.lastChanged.tooltip="Previous value: %1"
; Macro Tab

View File

@ -1648,7 +1648,7 @@
</size>
</property>
<property name="toolTip">
<string>AdvSceneSwitcher.variableTab.tooltip.variableAddButton</string>
<string>AdvSceneSwitcher.variableTab.variableAddButton.tooltip</string>
</property>
<property name="flat">
<bool>true</bool>
@ -1667,7 +1667,7 @@
</size>
</property>
<property name="toolTip">
<string>AdvSceneSwitcher.variableTab.tooltip.variableRemoveButton</string>
<string>AdvSceneSwitcher.variableTab.variableRemoveButton.tooltip</string>
</property>
<property name="flat">
<bool>true</bool>

View File

@ -12,6 +12,7 @@ static void setVariableTabVisible(QTabWidget *tabWidget, bool visible)
obs_module_text("AdvSceneSwitcher.variableTab.title")) {
continue;
}
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// TODO: Switch to setTabVisible() once QT 5.15 is more wide spread
tabWidget->setTabEnabled(idx, visible);
@ -23,9 +24,10 @@ static void setVariableTabVisible(QTabWidget *tabWidget, bool visible)
}
}
static QString getSaveActionString(Variable *variable)
static QString formatSaveActionText(Variable *variable)
{
QString saveAction;
switch (variable->GetSaveAction()) {
case Variable::SaveAction::DONT_SAVE:
saveAction = obs_module_text(
@ -38,26 +40,27 @@ static QString getSaveActionString(Variable *variable)
case Variable::SaveAction::SET_DEFAULT:
saveAction =
QString(obs_module_text(
"AdvSceneSwitcher.variable.save.default")) +
" \"" +
QString::fromStdString(variable->GetDefaultValue()) +
"\"";
"AdvSceneSwitcher.variableTab.saveLoadBehavior.text.default"))
.arg(QString::fromStdString(
variable->GetDefaultValue()));
break;
default:
break;
}
return saveAction;
}
static QString getLastUsedString(Variable *variable)
static QString formatLastUsedText(Variable *variable)
{
auto lastUsed = variable->SecondsSinceLastUse();
auto lastUsed = variable->GetSecondsSinceLastUse();
if (!lastUsed) {
return obs_module_text(
"AdvSceneSwitcher.variableTab.neverNused");
"AdvSceneSwitcher.variableTab.lastUsed.text.never");
}
QString fmt = obs_module_text("AdvSceneSwitcher.variableTab.lastUsed");
return fmt.arg(QString::number(*lastUsed));
QString text = obs_module_text("AdvSceneSwitcher.variableTab.lastUsed.text");
return text.arg(QString::number(*lastUsed));
}
static QString formatLastChangedText(Variable *variable)
@ -65,11 +68,11 @@ static QString formatLastChangedText(Variable *variable)
auto lastChanged = variable->GetSecondsSinceLastChange();
if (!lastChanged) {
return obs_module_text(
"AdvSceneSwitcher.variableTab.lastChanged.text.never");
"AdvSceneSwitcher.variableTab.lastChanged.text.none");
}
QString text =
obs_module_text("AdvSceneSwitcher.variableTab.lastChanged");
obs_module_text("AdvSceneSwitcher.variableTab.lastChanged.text");
return text.arg(QString::number(*lastChanged));
}
@ -82,7 +85,7 @@ static QString formatLastChangedTooltip(Variable *variable)
QString tooltip = obs_module_text(
"AdvSceneSwitcher.variableTab.lastChanged.tooltip");
return tooltip.arg(QString::fromStdString(variable->PreviousValue()));
return tooltip.arg(QString::fromStdString(variable->GetPreviousValue()));
}
static void addVariableRow(QTableWidget *table, Variable *variable)
@ -104,9 +107,9 @@ static void addVariableRow(QTableWidget *table, Variable *variable)
item = new QTableWidgetItem(varValue);
item->setToolTip(varValue);
table->setItem(row, ++col, item);
item = new QTableWidgetItem(getSaveActionString(variable));
item = new QTableWidgetItem(formatSaveActionText(variable));
table->setItem(row, ++col, item);
item = new QTableWidgetItem(getLastUsedString(variable));
item = new QTableWidgetItem(formatLastUsedText(variable));
table->setItem(row, ++col, item);
item = new QTableWidgetItem(formatLastChangedText(variable));
item->setToolTip(formatLastChangedTooltip(variable));
@ -127,26 +130,28 @@ static void removeVariableRow(QTableWidget *table, const QString &name)
table->sortByColumn(0, Qt::AscendingOrder);
}
static void updateVaribleStatus(QTableWidget *table)
static void updateVariableStatus(QTableWidget *table)
{
for (int row = 0; row < table->rowCount(); row++) {
auto item = table->item(row, 0);
if (!item) {
continue;
}
auto weakVariable = GetWeakVariableByQString(item->text());
auto variable = weakVariable.lock();
if (!variable) {
continue;
}
item = table->item(row, 1);
auto varValue = QString::fromStdString(variable->Value(false));
item->setText(varValue);
item->setToolTip(varValue);
item = table->item(row, 2);
item->setText(getSaveActionString(variable.get()));
item->setText(formatSaveActionText(variable.get()));
item = table->item(row, 3);
item->setText(getLastUsedString(variable.get()));
item->setText(formatLastUsedText(variable.get()));
item = table->item(row, 4);
item->setText(formatLastChangedText(variable.get()));
item->setToolTip(formatLastChangedTooltip(variable.get()));
@ -161,6 +166,7 @@ static void renameVariable(QTableWidget *table, const QString &oldName,
if (!item) {
continue;
}
if (item->text() == oldName) {
item->setText(newName);
table->sortByColumn(0, Qt::AscendingOrder);
@ -178,13 +184,14 @@ static void openSettingsDialogAtRow(QTableWidget *table, int row)
if (!item) {
return;
}
auto weakVariable = GetWeakVariableByQString(item->text());
auto variable = weakVariable.lock();
if (!variable) {
return;
}
auto oldName = variable->Name();
auto oldName = variable->Name();
bool accepted =
VariableSettingsDialog::AskForSettings(table, *variable.get());
if (accepted && oldName != variable->Name()) {
@ -204,14 +211,14 @@ void AdvSceneSwitcher::SetupVariableTab()
static const QStringList horizontalHeaders =
QStringList()
<< obs_module_text("AdvSceneSwitcher.variableTab.header.name")
<< obs_module_text("AdvSceneSwitcher.variableTab.header.value")
<< obs_module_text("AdvSceneSwitcher.variableTab.name.header")
<< obs_module_text("AdvSceneSwitcher.variableTab.value.header")
<< obs_module_text(
"AdvSceneSwitcher.variableTab.header.saveLoadBehavior")
"AdvSceneSwitcher.variableTab.saveLoadBehavior.header")
<< obs_module_text(
"AdvSceneSwitcher.variableTab.header.lastUse")
"AdvSceneSwitcher.variableTab.lastUsed.header")
<< obs_module_text(
"AdvSceneSwitcher.variableTab.header.lastChanged");
"AdvSceneSwitcher.variableTab.lastChanged.header");
auto &variables = GetVariables();
@ -258,7 +265,7 @@ void AdvSceneSwitcher::SetupVariableTab()
auto timer = new QTimer(this);
timer->setInterval(1000);
QWidget::connect(timer, &QTimer::timeout,
[this]() { updateVaribleStatus(ui->variables); });
[this]() { updateVariableStatus(ui->variables); });
timer->start();
}
@ -270,6 +277,7 @@ void AdvSceneSwitcher::on_variableAdd_clicked()
if (!accepted) {
return;
}
{
auto lock = LockContext();
auto &variables = GetVariables();

View File

@ -13,11 +13,6 @@ static std::deque<std::shared_ptr<Item>> variables;
// when resolving strings containing variables, etc.
static std::chrono::high_resolution_clock::time_point lastVariableChange{};
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime()
{
return lastVariableChange;
}
Variable::Variable() : Item()
{
lastVariableChange = std::chrono::high_resolution_clock::now();
@ -34,11 +29,13 @@ void Variable::Load(obs_data_t *obj)
_saveAction =
static_cast<SaveAction>(obs_data_get_int(obj, "saveAction"));
_defaultValue = obs_data_get_string(obj, "defaultValue");
if (_saveAction == SaveAction::SAVE) {
SetValue(obs_data_get_string(obj, "value"));
} else if (_saveAction == SaveAction::SET_DEFAULT) {
SetValue(_defaultValue);
}
lastVariableChange = std::chrono::high_resolution_clock::now();
}
@ -46,9 +43,11 @@ void Variable::Save(obs_data_t *obj) const
{
Item::Save(obj);
obs_data_set_int(obj, "saveAction", static_cast<int>(_saveAction));
if (_saveAction == SaveAction::SAVE) {
obs_data_set_string(obj, "value", _value.c_str());
}
obs_data_set_string(obj, "defaultValue", _defaultValue.c_str());
}
@ -57,6 +56,7 @@ std::string Variable::Value(bool updateLastUsed) const
if (updateLastUsed) {
UpdateLastUsed();
}
return _value;
}
@ -70,11 +70,6 @@ std::optional<int> Variable::IntValue() const
return GetInt(Value());
}
std::string Variable::PreviousValue() const
{
return _previousValue;
}
void Variable::SetValue(const std::string &value)
{
_previousValue = _value;
@ -90,11 +85,12 @@ void Variable::SetValue(double value)
SetValue(ToString(value));
}
std::optional<uint64_t> Variable::SecondsSinceLastUse() const
std::optional<uint64_t> Variable::GetSecondsSinceLastUse() const
{
if (_lastUsed.time_since_epoch().count() == 0) {
return {};
}
const auto now = std::chrono::high_resolution_clock::now();
return std::chrono::duration_cast<std::chrono::seconds>(now - _lastUsed)
.count();
@ -124,121 +120,12 @@ void Variable::UpdateLastChanged() const
}
}
std::deque<std::shared_ptr<Item>> &GetVariables()
{
return variables;
}
Variable *GetVariableByName(const std::string &name)
{
for (const auto &v : variables) {
if (v->Name() == name) {
return dynamic_cast<Variable *>(v.get());
}
}
return nullptr;
}
Variable *GetVariableByQString(const QString &name)
{
return GetVariableByName(name.toStdString());
}
std::weak_ptr<Variable> GetWeakVariableByName(const std::string &name)
{
for (const auto &v : variables) {
if (v->Name() == name) {
std::weak_ptr<Variable> wp =
std::dynamic_pointer_cast<Variable>(v);
return wp;
}
}
return std::weak_ptr<Variable>();
}
std::weak_ptr<Variable> GetWeakVariableByQString(const QString &name)
{
return GetWeakVariableByName(name.toStdString());
}
QStringList GetVariablesNameList()
{
QStringList list;
for (const auto &var : variables) {
list << QString::fromStdString(var->Name());
}
list.sort();
return list;
}
std::string GetWeakVariableName(std::weak_ptr<Variable> var_)
{
auto var = var_.lock();
if (!var) {
return obs_module_text("AdvSceneSwitcher.variable.invalid");
}
return var->Name();
}
void SaveVariables(obs_data_t *obj)
{
obs_data_array_t *variablesArray = obs_data_array_create();
for (const auto &v : variables) {
obs_data_t *array_obj = obs_data_create();
v->Save(array_obj);
obs_data_array_push_back(variablesArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "variables", variablesArray);
obs_data_array_release(variablesArray);
}
void LoadVariables(obs_data_t *obj)
{
variables.clear();
obs_data_array_t *variablesArray = obs_data_get_array(obj, "variables");
size_t count = obs_data_array_count(variablesArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(variablesArray, i);
auto var = Variable::Create();
variables.emplace_back(var);
variables.back()->Load(array_obj);
obs_data_release(array_obj);
}
obs_data_array_release(variablesArray);
}
static bool variableWithNameExists(const std::string &name)
{
return !!GetVariableByName(name);
}
void ImportVariables(obs_data_t *data)
{
obs_data_array_t *array = obs_data_get_array(data, "variables");
size_t count = obs_data_array_count(array);
for (size_t i = 0; i < count; i++) {
obs_data_t *arrayElement = obs_data_array_item(array, i);
auto var = Variable::Create();
var->Load(arrayElement);
obs_data_release(arrayElement);
if (variableWithNameExists(var->Name())) {
continue;
}
GetVariables().emplace_back(var);
}
obs_data_array_release(array);
}
static void populateSaveActionSelection(QComboBox *list)
{
list->addItem(
obs_module_text("AdvSceneSwitcher.variable.save.dontSave"));
list->addItem(obs_module_text("AdvSceneSwitcher.variable.save.save"));
list->addItem(
obs_module_text("AdvSceneSwitcher.variable.save.default"));
list->addItems(
{obs_module_text("AdvSceneSwitcher.variable.save.dontSave"),
obs_module_text("AdvSceneSwitcher.variable.save.save"),
obs_module_text("AdvSceneSwitcher.variable.save.default")});
}
VariableSettingsDialog::VariableSettingsDialog(QWidget *parent,
@ -265,6 +152,7 @@ VariableSettingsDialog::VariableSettingsDialog(QWidget *parent,
layout->addWidget(
new QLabel(obs_module_text("AdvSceneSwitcher.variable.name")),
row, 0);
QHBoxLayout *nameLayout = new QHBoxLayout;
nameLayout->addWidget(_name);
nameLayout->addWidget(_nameHint);
@ -278,13 +166,14 @@ VariableSettingsDialog::VariableSettingsDialog(QWidget *parent,
layout->addWidget(
new QLabel(obs_module_text("AdvSceneSwitcher.variable.save")),
row, 0);
auto saveLayout = new QVBoxLayout;
saveLayout->addWidget(_save);
saveLayout->addWidget(_defaultValue);
saveLayout->addStretch();
layout->addLayout(saveLayout, row, 1);
++row;
layout->addWidget(_buttonbox, row, 0, 1, -1);
layout->addWidget(_buttonbox, ++row, 0, 1, -1);
layout->setSizeConstraint(QLayout::SetFixedSize);
setLayout(layout);
}
@ -313,6 +202,7 @@ bool VariableSettingsDialog::AskForSettings(QWidget *parent, Variable &settings)
settings._saveAction =
static_cast<Variable::SaveAction>(dialog._save->currentIndex());
lastVariableChange = std::chrono::high_resolution_clock::now();
return true;
}
@ -322,6 +212,7 @@ static bool AskForSettingsWrapper(QWidget *parent, Item &settings)
if (VariableSettingsDialog::AskForSettings(parent, VariableSettings)) {
return true;
}
return false;
}
@ -385,4 +276,128 @@ VariableSignalManager *VariableSignalManager::Instance()
return &manager;
}
std::deque<std::shared_ptr<Item>> &GetVariables()
{
return variables;
}
Variable *GetVariableByName(const std::string &name)
{
for (const auto &v : variables) {
if (v->Name() == name) {
return dynamic_cast<Variable *>(v.get());
}
}
return nullptr;
}
Variable *GetVariableByQString(const QString &name)
{
return GetVariableByName(name.toStdString());
}
std::weak_ptr<Variable> GetWeakVariableByName(const std::string &name)
{
for (const auto &v : variables) {
if (v->Name() == name) {
std::weak_ptr<Variable> wp =
std::dynamic_pointer_cast<Variable>(v);
return wp;
}
}
return std::weak_ptr<Variable>();
}
std::weak_ptr<Variable> GetWeakVariableByQString(const QString &name)
{
return GetWeakVariableByName(name.toStdString());
}
QStringList GetVariablesNameList()
{
QStringList list;
for (const auto &var : variables) {
list << QString::fromStdString(var->Name());
}
list.sort();
return list;
}
std::string GetWeakVariableName(std::weak_ptr<Variable> var_)
{
auto var = var_.lock();
if (!var) {
return obs_module_text("AdvSceneSwitcher.variable.invalid");
}
return var->Name();
}
static bool variableWithNameExists(const std::string &name)
{
return !!GetVariableByName(name);
}
void SaveVariables(obs_data_t *obj)
{
obs_data_array_t *variablesArray = obs_data_array_create();
for (const auto &v : variables) {
obs_data_t *array_obj = obs_data_create();
v->Save(array_obj);
obs_data_array_push_back(variablesArray, array_obj);
obs_data_release(array_obj);
}
obs_data_set_array(obj, "variables", variablesArray);
obs_data_array_release(variablesArray);
}
void LoadVariables(obs_data_t *obj)
{
variables.clear();
obs_data_array_t *variablesArray = obs_data_get_array(obj, "variables");
size_t count = obs_data_array_count(variablesArray);
for (size_t i = 0; i < count; i++) {
obs_data_t *array_obj = obs_data_array_item(variablesArray, i);
auto var = Variable::Create();
variables.emplace_back(var);
variables.back()->Load(array_obj);
obs_data_release(array_obj);
}
obs_data_array_release(variablesArray);
}
void ImportVariables(obs_data_t *data)
{
obs_data_array_t *array = obs_data_get_array(data, "variables");
size_t count = obs_data_array_count(array);
for (size_t i = 0; i < count; i++) {
obs_data_t *arrayElement = obs_data_array_item(array, i);
auto var = Variable::Create();
var->Load(arrayElement);
obs_data_release(arrayElement);
if (variableWithNameExists(var->Name())) {
continue;
}
GetVariables().emplace_back(var);
}
obs_data_array_release(array);
}
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime()
{
return lastVariableChange;
}
} // namespace advss

View File

@ -17,15 +17,6 @@ class Variable : public Item {
public:
Variable();
~Variable();
void Load(obs_data_t *obj);
void Save(obs_data_t *obj) const;
EXPORT std::string Value(bool updateLastUsed = true) const;
EXPORT std::optional<double> DoubleValue() const;
EXPORT std::optional<int> IntValue() const;
EXPORT std::string PreviousValue() const;
void SetValue(const std::string &value);
void SetValue(double value);
std::string GetDefaultValue() const { return _defaultValue; }
static std::shared_ptr<Item> Create()
{
return std::make_shared<Variable>();
@ -36,8 +27,18 @@ public:
SAVE,
SET_DEFAULT,
};
void Load(obs_data_t *obj);
void Save(obs_data_t *obj) const;
EXPORT std::string Value(bool updateLastUsed = true) const;
EXPORT std::optional<double> DoubleValue() const;
EXPORT std::optional<int> IntValue() const;
std::string GetPreviousValue() const { return _previousValue; };
std::string GetDefaultValue() const { return _defaultValue; }
void SetValue(const std::string &value);
void SetValue(double value);
SaveAction GetSaveAction() const { return _saveAction; }
std::optional<uint64_t> SecondsSinceLastUse() const;
std::optional<uint64_t> GetSecondsSinceLastUse() const;
std::optional<uint64_t> GetSecondsSinceLastChange() const;
void UpdateLastUsed() const;
void UpdateLastChanged() const;
@ -91,12 +92,7 @@ signals:
void Remove(const QString &);
};
void SaveVariables(obs_data_t *obj);
void LoadVariables(obs_data_t *obj);
void ImportVariables(obs_data_t *obj);
std::deque<std::shared_ptr<Item>> &GetVariables();
EXPORT Variable *GetVariableByName(const std::string &name);
EXPORT Variable *GetVariableByQString(const QString &name);
EXPORT std::weak_ptr<Variable> GetWeakVariableByName(const std::string &name);
@ -104,6 +100,10 @@ EXPORT std::weak_ptr<Variable> GetWeakVariableByQString(const QString &name);
std::string GetWeakVariableName(std::weak_ptr<Variable>);
EXPORT QStringList GetVariablesNameList();
void SaveVariables(obs_data_t *obj);
void LoadVariables(obs_data_t *obj);
void ImportVariables(obs_data_t *obj);
std::chrono::high_resolution_clock::time_point GetLastVariableChangeTime();
} // namespace advss

View File

@ -6,7 +6,7 @@
TEST_CASE("Variable", "[variable]")
{
advss::Variable variable;
REQUIRE_FALSE(variable.SecondsSinceLastUse());
REQUIRE_FALSE(variable.GetSecondsSinceLastUse());
REQUIRE(variable.Value() == "");
REQUIRE(variable.GetDefaultValue() == "");
@ -25,14 +25,23 @@ TEST_CASE("Variable", "[variable]")
variable.SetValue(123.123);
REQUIRE(variable.Value() == "123.123");
REQUIRE(*variable.SecondsSinceLastUse() == 0);
REQUIRE(*variable.GetSecondsSinceLastUse() == 0);
REQUIRE(*variable.GetSecondsSinceLastChange() == 0);
std::this_thread::sleep_for(std::chrono::seconds(2));
REQUIRE(*variable.SecondsSinceLastUse() > 1);
REQUIRE(*variable.GetSecondsSinceLastUse() > 1);
REQUIRE(*variable.GetSecondsSinceLastChange() > 1);
variable.Value(false);
REQUIRE(*variable.SecondsSinceLastUse() > 1);
REQUIRE(*variable.GetSecondsSinceLastUse() > 1);
variable.UpdateLastUsed();
REQUIRE(*variable.SecondsSinceLastUse() == 0);
REQUIRE(*variable.GetSecondsSinceLastUse() == 0);
variable.SetValue(123);
REQUIRE(*variable.GetSecondsSinceLastChange() == 0);
std::this_thread::sleep_for(std::chrono::seconds(1));
variable.SetValue(123);
REQUIRE(*variable.GetSecondsSinceLastChange() > 0);
}