Skip to content
Permalink
Browse files
Merge pull request #9581 from Filoppi/expose_input_expr_vars
Expose Control Expression variables to mappings UI
  • Loading branch information
JMC47 committed May 24, 2021
2 parents 975f8e2 + 93e3e69 commit 509b24a
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 12 deletions.
@@ -275,6 +275,7 @@ void IOWindow::CreateMainLayout()
m_operators_combo->addItem(tr("^ Xor"));
}
m_operators_combo->addItem(tr("| Or"));
m_operators_combo->addItem(tr("$ User Variable"));
if (m_type == Type::Input)
{
m_operators_combo->addItem(tr(", Comma"));
@@ -305,6 +306,15 @@ void IOWindow::CreateMainLayout()
m_functions_combo->addItem(QStringLiteral("max"));
m_functions_combo->addItem(QStringLiteral("clamp"));

m_variables_combo = new QComboBoxWithMouseWheelDisabled(this);
m_variables_combo->addItem(tr("User Variables"));
m_variables_combo->setToolTip(
tr("User defined variables usable in the control expression.\nYou can use them to save or "
"retrieve values between\ninputs and outputs of the same parent controller."));
m_variables_combo->insertSeparator(m_variables_combo->count());
m_variables_combo->addItem(tr("Reset Values"));
m_variables_combo->insertSeparator(m_variables_combo->count());

// Devices
m_main_layout->addWidget(m_devices_combo);

@@ -366,6 +376,8 @@ void IOWindow::CreateMainLayout()
button_vbox->addWidget(m_test_button);
}

button_vbox->addWidget(m_variables_combo);

button_vbox->addWidget(m_operators_combo);

if (m_type == Type::Input)
@@ -425,8 +437,26 @@ void IOWindow::ConnectWidgets()
connect(m_expression_text, &QPlainTextEdit::textChanged,
[this] { UpdateExpression(m_expression_text->toPlainText().toStdString()); });

connect(m_variables_combo, qOverload<int>(&QComboBox::activated), [this](int index) {
if (index == 0)
return;

// Reset button. 1 and 3 are separators.
if (index == 2)
{
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
m_controller->ResetExpressionVariables();
}
else
{
m_expression_text->insertPlainText(QLatin1Char('$') + m_variables_combo->currentText());
}

m_variables_combo->setCurrentIndex(0);
});

connect(m_operators_combo, qOverload<int>(&QComboBox::activated), [this](int index) {
if (0 == index)
if (index == 0)
return;

m_expression_text->insertPlainText(m_operators_combo->currentText().left(1));
@@ -435,7 +465,7 @@ void IOWindow::ConnectWidgets()
});

connect(m_functions_combo, qOverload<int>(&QComboBox::activated), [this](int index) {
if (0 == index)
if (index == 0)
return;

m_expression_text->insertPlainText(m_functions_combo->currentText() + QStringLiteral("()"));
@@ -564,6 +594,16 @@ void IOWindow::UpdateExpression(std::string new_expression, UpdateMode mode)
const auto status = m_reference->GetParseStatus();
m_controller->UpdateSingleControlReference(g_controller_interface, m_reference);

// This is the only place where we need to update the user variables. Keep the first 4 items.
while (m_variables_combo->count() > 4)
{
m_variables_combo->removeItem(m_variables_combo->count() - 1);
}
for (const auto& expression : m_controller->GetExpressionVariables())
{
m_variables_combo->addItem(QString::fromStdString(expression.first));
}

if (error)
{
m_parse_text->SetShouldPaintStateIndicator(false);
@@ -111,6 +111,7 @@ class IOWindow final : public QDialog
// Shared actions
QPushButton* m_select_button;
QComboBox* m_operators_combo;
QComboBox* m_variables_combo;

// Input actions
QPushButton* m_detect_button;
@@ -461,20 +461,24 @@ class VariableExpression : public Expression
public:
VariableExpression(std::string name) : m_name(name) {}

ControlState GetValue() const override { return *m_value_ptr; }
ControlState GetValue() const override { return m_variable_ptr ? *m_variable_ptr : 0; }

void SetValue(ControlState value) override { *m_value_ptr = value; }
void SetValue(ControlState value) override
{
if (m_variable_ptr)
*m_variable_ptr = value;
}

int CountNumControls() const override { return 1; }

void UpdateReferences(ControlEnvironment& env) override
{
m_value_ptr = env.GetVariablePtr(m_name);
m_variable_ptr = env.GetVariablePtr(m_name);
}

protected:
const std::string m_name;
ControlState* m_value_ptr{};
std::shared_ptr<ControlState> m_variable_ptr;
};

class HotkeyExpression : public Expression
@@ -621,9 +625,30 @@ Device::Output* ControlEnvironment::FindOutput(ControlQualifier qualifier) const
return device->FindOutput(qualifier.control_name);
}

ControlState* ControlEnvironment::GetVariablePtr(const std::string& name)
std::shared_ptr<ControlState> ControlEnvironment::GetVariablePtr(const std::string& name)
{
return &m_variables[name];
// Do not accept an empty string as key, even if the expression parser already prevents this case.
if (name.empty())
return nullptr;
std::shared_ptr<ControlState>& variable = m_variables[name];
// If new, make a shared ptr
if (!variable)
{
variable = std::make_shared<ControlState>();
}
return variable;
}

void ControlEnvironment::CleanUnusedVariables()
{
for (auto it = m_variables.begin(); it != m_variables.end();)
{
// Don't count ourselves as reference
if (it->second.use_count() <= 1)
m_variables.erase(it++);
else
++it;
}
}

ParseResult ParseResult::MakeEmptyResult()
@@ -785,7 +810,10 @@ class Parser
}
case TOK_VARIABLE:
{
return ParseResult::MakeSuccessfulResult(std::make_unique<VariableExpression>(tok.data));
if (tok.data.empty())
return ParseResult::MakeErrorResult(tok, _trans("Expected variable name."));
else
return ParseResult::MakeSuccessfulResult(std::make_unique<VariableExpression>(tok.data));
}
case TOK_LPAREN:
{
@@ -143,7 +143,7 @@ class ControlQualifier
class ControlEnvironment
{
public:
using VariableContainer = std::map<std::string, ControlState>;
using VariableContainer = std::map<std::string, std::shared_ptr<ControlState>>;

ControlEnvironment(const Core::DeviceContainer& container_, const Core::DeviceQualifier& default_,
VariableContainer& vars)
@@ -154,7 +154,10 @@ class ControlEnvironment
std::shared_ptr<Core::Device> FindDevice(ControlQualifier qualifier) const;
Core::Device::Input* FindInput(ControlQualifier qualifier) const;
Core::Device::Output* FindOutput(ControlQualifier qualifier) const;
ControlState* GetVariablePtr(const std::string& name);
// Returns an existing variable by the specified name if already existing. Creates it otherwise.
std::shared_ptr<ControlState> GetVariablePtr(const std::string& name);

void CleanUnusedVariables();

private:
VariableContainer& m_variables;
@@ -44,6 +44,8 @@ void EmulatedController::UpdateReferences(const ControllerInterface& devi)
ciface::ExpressionParser::ControlEnvironment env(devi, GetDefaultDevice(), m_expression_vars);

UpdateReferences(env);

env.CleanUnusedVariables();
}

void EmulatedController::UpdateReferences(ciface::ExpressionParser::ControlEnvironment& env)
@@ -75,7 +77,27 @@ void EmulatedController::UpdateSingleControlReference(const ControllerInterface&
ControlReference* ref)
{
ciface::ExpressionParser::ControlEnvironment env(devi, GetDefaultDevice(), m_expression_vars);

ref->UpdateReference(env);

env.CleanUnusedVariables();
}

const ciface::ExpressionParser::ControlEnvironment::VariableContainer&
EmulatedController::GetExpressionVariables() const
{
return m_expression_vars;
}

void EmulatedController::ResetExpressionVariables()
{
for (auto& var : m_expression_vars)
{
if (var.second)
{
*var.second = 0;
}
}
}

bool EmulatedController::IsDefaultDeviceConnected() const
@@ -191,6 +191,11 @@ class EmulatedController
// which happens while handling a hotplug event because a control reference's State()
// could be called before we have finished updating the reference.
[[nodiscard]] static std::unique_lock<std::recursive_mutex> GetStateLock();
const ciface::ExpressionParser::ControlEnvironment::VariableContainer&
GetExpressionVariables() const;

// Resets the values while keeping the list.
void ResetExpressionVariables();

std::vector<std::unique_ptr<ControlGroup>> groups;

@@ -218,7 +223,8 @@ class EmulatedController
}

protected:
// TODO: Wiimote attachment has its own member that isn't being used.
// TODO: Wiimote attachments actually end up using their parent controller value for this,
// so theirs won't be used (and thus shouldn't even exist).
ciface::ExpressionParser::ControlEnvironment::VariableContainer m_expression_vars;

void UpdateReferences(ciface::ExpressionParser::ControlEnvironment& env);

0 comments on commit 509b24a

Please sign in to comment.