summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorLéo Lam <leo@leolam.fr>2020-11-26 01:30:12 +0100
committerGitHub <noreply@github.com>2020-11-26 01:30:12 +0100
commit3891ac26826db06d0c8a2829d1ae7494225231db (patch)
tree251fca7742cfa54f6414d3a213649290a78ff76d /Source
parente2a019ae9a793292220c654f29e1ddabb2806e65 (diff)
parent11e226a91a1f38061b33deb247ca2e33e748305b (diff)
Merge pull request #9232 from AdmiralCurtiss/show-result-value-in-expression-editor
Qt/IOWindow: Show result value in expression editor.
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp171
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/IOWindow.h22
-rw-r--r--Source/Core/InputCommon/ControlReference/ControlReference.cpp3
-rw-r--r--Source/Core/InputCommon/ControlReference/ControlReference.h4
4 files changed, 142 insertions, 58 deletions
diff --git a/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp b/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp
index 1648175360..887063e8aa 100644
--- a/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp
+++ b/Source/Core/DolphinQt/Config/Mapping/IOWindow.cpp
@@ -93,9 +93,8 @@ QTextCharFormat GetCommentCharFormat()
}
} // namespace
-ControlExpressionSyntaxHighlighter::ControlExpressionSyntaxHighlighter(QTextDocument* parent,
- QLineEdit* result)
- : QSyntaxHighlighter(parent), m_result_text(result)
+ControlExpressionSyntaxHighlighter::ControlExpressionSyntaxHighlighter(QTextDocument* parent)
+ : QSyntaxHighlighter(parent)
{
}
@@ -168,18 +167,11 @@ void ControlExpressionSyntaxHighlighter::highlightBlock(const QString&)
}
// This doesn't need to be run for every "block", but it works.
- if (ciface::ExpressionParser::ParseStatus::Successful != tokenize_status)
- {
- m_result_text->setText(tr("Invalid Token."));
- }
- else
+ if (ciface::ExpressionParser::ParseStatus::Successful == tokenize_status)
{
ciface::ExpressionParser::RemoveInertTokens(&tokens);
const auto parse_status = ciface::ExpressionParser::ParseTokens(tokens);
- m_result_text->setText(
- QString::fromStdString(parse_status.description.value_or(_trans("Success."))));
-
if (ciface::ExpressionParser::ParseStatus::Successful != parse_status.status)
{
const auto token = *parse_status.token;
@@ -192,18 +184,33 @@ void ControlExpressionSyntaxHighlighter::highlightBlock(const QString&)
class InputStateDelegate : public QItemDelegate
{
public:
- explicit InputStateDelegate(IOWindow* parent);
+ explicit InputStateDelegate(IOWindow* parent, int column,
+ std::function<ControlState(int row)> state_evaluator);
void paint(QPainter* painter, const QStyleOptionViewItem& option,
const QModelIndex& index) const override;
private:
- IOWindow* m_parent;
+ std::function<ControlState(int row)> m_state_evaluator;
+ int m_column;
+};
+
+class InputStateLineEdit : public QLineEdit
+{
+public:
+ explicit InputStateLineEdit(std::function<ControlState()> state_evaluator);
+ void SetShouldPaintStateIndicator(bool value);
+ void paintEvent(QPaintEvent* event) override;
+
+private:
+ std::function<ControlState()> m_state_evaluator;
+ bool m_should_paint_state_indicator;
};
IOWindow::IOWindow(MappingWidget* parent, ControllerEmu::EmulatedController* controller,
ControlReference* ref, IOWindow::Type type)
- : QDialog(parent), m_reference(ref), m_controller(controller), m_type(type)
+ : QDialog(parent), m_reference(ref), m_original_expression(ref->GetExpression()),
+ m_controller(controller), m_type(type)
{
CreateMainLayout();
@@ -233,16 +240,18 @@ void IOWindow::CreateMainLayout()
m_test_button = new QPushButton(tr("Test"), this);
m_button_box = new QDialogButtonBox();
m_clear_button = new QPushButton(tr("Clear"));
- m_apply_button = new QPushButton(tr("Apply"));
m_range_slider = new QSlider(Qt::Horizontal);
m_range_spinbox = new QSpinBox();
- m_parse_text = new QLineEdit();
+ m_parse_text = new InputStateLineEdit([this] {
+ const auto lock = m_controller->GetStateLock();
+ return m_reference->GetState<ControlState>();
+ });
m_parse_text->setReadOnly(true);
m_expression_text = new QPlainTextEdit();
m_expression_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
- new ControlExpressionSyntaxHighlighter(m_expression_text->document(), m_parse_text);
+ new ControlExpressionSyntaxHighlighter(m_expression_text->document());
m_operators_combo = new QComboBox();
m_operators_combo->addItem(tr("Operators"));
@@ -315,7 +324,10 @@ void IOWindow::CreateMainLayout()
m_option_list->setColumnWidth(1, 64);
m_option_list->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Fixed);
- m_option_list->setItemDelegate(new InputStateDelegate(this));
+ m_option_list->setItemDelegate(new InputStateDelegate(this, 1, [&](int row) {
+ // Clamp off negative values but allow greater than one in the text display.
+ return std::max(GetSelectedDevice()->Inputs()[row]->GetState(), 0.0);
+ }));
}
else
{
@@ -363,7 +375,6 @@ void IOWindow::CreateMainLayout()
// Button Box
m_main_layout->addWidget(m_button_box);
m_button_box->addButton(m_clear_button, QDialogButtonBox::ActionRole);
- m_button_box->addButton(m_apply_button, QDialogButtonBox::ActionRole);
m_button_box->addButton(QDialogButtonBox::Ok);
setLayout(m_main_layout);
@@ -372,6 +383,10 @@ void IOWindow::CreateMainLayout()
void IOWindow::ConfigChanged()
{
const QSignalBlocker blocker(this);
+ const auto lock = m_controller->GetStateLock();
+
+ // ensure m_parse_text is in the right state
+ UpdateExpression(m_reference->GetExpression(), UpdateMode::Force);
m_expression_text->setPlainText(QString::fromStdString(m_reference->GetExpression()));
m_expression_text->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
@@ -387,6 +402,7 @@ void IOWindow::ConfigChanged()
void IOWindow::Update()
{
m_option_list->viewport()->update();
+ m_parse_text->update();
}
void IOWindow::ConnectWidgets()
@@ -401,10 +417,8 @@ void IOWindow::ConnectWidgets()
connect(m_range_spinbox, qOverload<int>(&QSpinBox::valueChanged), this,
&IOWindow::OnRangeChanged);
- connect(m_expression_text, &QPlainTextEdit::textChanged, [this] {
- m_apply_button->setText(m_apply_button->text().remove(QStringLiteral("*")));
- m_apply_button->setText(m_apply_button->text() + QStringLiteral("*"));
- });
+ connect(m_expression_text, &QPlainTextEdit::textChanged,
+ [this] { UpdateExpression(m_expression_text->toPlainText().toStdString()); });
connect(m_operators_combo, qOverload<int>(&QComboBox::activated), [this](int index) {
if (0 == index)
@@ -423,6 +437,9 @@ void IOWindow::ConnectWidgets()
m_functions_combo->setCurrentIndex(0);
});
+
+ // revert the expression when the window closes without using the OK button
+ connect(this, &IOWindow::finished, [this] { UpdateExpression(m_original_expression); });
}
void IOWindow::AppendSelectedOption()
@@ -448,18 +465,18 @@ void IOWindow::OnDialogButtonPressed(QAbstractButton* button)
return;
}
- m_reference->SetExpression(m_expression_text->toPlainText().toStdString());
- m_controller->UpdateSingleControlReference(g_controller_interface, m_reference);
+ const auto lock = m_controller->GetStateLock();
- m_apply_button->setText(m_apply_button->text().remove(QStringLiteral("*")));
+ UpdateExpression(m_expression_text->toPlainText().toStdString());
+ m_original_expression = m_reference->GetExpression();
if (ciface::ExpressionParser::ParseStatus::SyntaxError == m_reference->GetParseStatus())
{
ModalMessageBox::warning(this, tr("Error"), tr("The expression contains a syntax error."));
}
- if (button != m_apply_button)
- accept();
+ // must be the OK button
+ accept();
}
void IOWindow::OnDetectButtonPressed()
@@ -532,44 +549,98 @@ void IOWindow::UpdateDeviceList()
QString::fromStdString(m_controller->GetDefaultDevice().ToString()));
}
-InputStateDelegate::InputStateDelegate(IOWindow* parent) : QItemDelegate(parent), m_parent(parent)
+void IOWindow::UpdateExpression(std::string new_expression, UpdateMode mode)
{
+ const auto lock = m_controller->GetStateLock();
+ if (mode != UpdateMode::Force && new_expression == m_reference->GetExpression())
+ return;
+
+ const auto error = m_reference->SetExpression(std::move(new_expression));
+ const auto status = m_reference->GetParseStatus();
+ m_controller->UpdateSingleControlReference(g_controller_interface, m_reference);
+
+ if (error)
+ {
+ m_parse_text->SetShouldPaintStateIndicator(false);
+ m_parse_text->setText(QString::fromStdString(*error));
+ }
+ else if (status == ciface::ExpressionParser::ParseStatus::EmptyExpression)
+ {
+ m_parse_text->SetShouldPaintStateIndicator(false);
+ m_parse_text->setText(QString());
+ }
+ else if (status != ciface::ExpressionParser::ParseStatus::Successful)
+ {
+ m_parse_text->SetShouldPaintStateIndicator(false);
+ m_parse_text->setText(tr("Invalid Expression."));
+ }
+ else
+ {
+ m_parse_text->SetShouldPaintStateIndicator(true);
+ m_parse_text->setText(QString());
+ }
}
-void InputStateDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
- const QModelIndex& index) const
+InputStateDelegate::InputStateDelegate(IOWindow* parent, int column,
+ std::function<ControlState(int row)> state_evaluator)
+ : QItemDelegate(parent), m_state_evaluator(std::move(state_evaluator)), m_column(column)
{
- QItemDelegate::paint(painter, option, index);
+}
- // Don't do anything special for the first column.
- if (index.column() == 0)
- return;
+InputStateLineEdit::InputStateLineEdit(std::function<ControlState()> state_evaluator)
+ : m_state_evaluator(std::move(state_evaluator))
+{
+}
- // Clamp off negative values but allow greater than one in the text display.
- const auto state =
- std::max(m_parent->GetSelectedDevice()->Inputs()[index.row()]->GetState(), 0.0);
- const auto state_str = QString::number(state, 'g', 4);
+static void PaintStateIndicator(QPainter& painter, const QRect& region, ControlState state)
+{
+ const QString state_string = QString::number(state, 'g', 4);
- QRect rect = option.rect;
- rect.setWidth(rect.width() * std::clamp(state, 0.0, 1.0));
+ QRect meter_region = region;
+ meter_region.setWidth(region.width() * std::clamp(state, 0.0, 1.0));
// Create a temporary indicator object to retreive color constants.
MappingIndicator indicator;
- painter->save();
-
// Normal text.
- painter->setPen(indicator.GetTextColor());
- painter->drawText(option.rect, Qt::AlignCenter, state_str);
+ painter.setPen(indicator.GetTextColor());
+ painter.drawText(region, Qt::AlignCenter, state_string);
// Input state meter.
- painter->fillRect(rect, indicator.GetAdjustedInputColor());
+ painter.fillRect(meter_region, indicator.GetAdjustedInputColor());
// Text on top of meter.
- painter->setPen(indicator.GetAltTextColor());
- painter->setClipping(true);
- painter->setClipRect(rect);
- painter->drawText(option.rect, Qt::AlignCenter, state_str);
+ painter.setPen(indicator.GetAltTextColor());
+ painter.setClipping(true);
+ painter.setClipRect(meter_region);
+ painter.drawText(region, Qt::AlignCenter, state_string);
+}
+
+void InputStateDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
+ const QModelIndex& index) const
+{
+ QItemDelegate::paint(painter, option, index);
+
+ if (index.column() != m_column)
+ return;
+ painter->save();
+ PaintStateIndicator(*painter, option.rect, m_state_evaluator(index.row()));
painter->restore();
}
+
+void InputStateLineEdit::SetShouldPaintStateIndicator(bool value)
+{
+ m_should_paint_state_indicator = value;
+}
+
+void InputStateLineEdit::paintEvent(QPaintEvent* event)
+{
+ QLineEdit::paintEvent(event);
+
+ if (!m_should_paint_state_indicator)
+ return;
+
+ QPainter painter(this);
+ PaintStateIndicator(painter, this->rect(), m_state_evaluator());
+}
diff --git a/Source/Core/DolphinQt/Config/Mapping/IOWindow.h b/Source/Core/DolphinQt/Config/Mapping/IOWindow.h
index 9870a4c954..28294fc284 100644
--- a/Source/Core/DolphinQt/Config/Mapping/IOWindow.h
+++ b/Source/Core/DolphinQt/Config/Mapping/IOWindow.h
@@ -4,6 +4,9 @@
#pragma once
+#include <memory>
+#include <string>
+
#include <QDialog>
#include <QString>
#include <QSyntaxHighlighter>
@@ -30,17 +33,16 @@ namespace ControllerEmu
class EmulatedController;
}
+class InputStateLineEdit;
+
class ControlExpressionSyntaxHighlighter final : public QSyntaxHighlighter
{
Q_OBJECT
public:
- ControlExpressionSyntaxHighlighter(QTextDocument* parent, QLineEdit* result);
+ explicit ControlExpressionSyntaxHighlighter(QTextDocument* parent);
protected:
void highlightBlock(const QString& text) final override;
-
-private:
- QLineEdit* const m_result_text;
};
class IOWindow final : public QDialog
@@ -74,6 +76,14 @@ private:
void UpdateOptionList();
void UpdateDeviceList();
+ enum class UpdateMode
+ {
+ Normal,
+ Force,
+ };
+
+ void UpdateExpression(std::string new_expression, UpdateMode mode = UpdateMode::Normal);
+
// Main Layout
QVBoxLayout* m_main_layout;
@@ -100,14 +110,14 @@ private:
// Textarea
QPlainTextEdit* m_expression_text;
- QLineEdit* m_parse_text;
+ InputStateLineEdit* m_parse_text;
// Buttonbox
QDialogButtonBox* m_button_box;
QPushButton* m_clear_button;
- QPushButton* m_apply_button;
ControlReference* m_reference;
+ std::string m_original_expression;
ControllerEmu::EmulatedController* m_controller;
ciface::Core::DeviceQualifier m_devq;
diff --git a/Source/Core/InputCommon/ControlReference/ControlReference.cpp b/Source/Core/InputCommon/ControlReference/ControlReference.cpp
index b1dd5deee3..671f2f3379 100644
--- a/Source/Core/InputCommon/ControlReference/ControlReference.cpp
+++ b/Source/Core/InputCommon/ControlReference/ControlReference.cpp
@@ -50,12 +50,13 @@ std::string ControlReference::GetExpression() const
return m_expression;
}
-void ControlReference::SetExpression(std::string expr)
+std::optional<std::string> ControlReference::SetExpression(std::string expr)
{
m_expression = std::move(expr);
auto parse_result = ParseExpression(m_expression);
m_parse_status = parse_result.status;
m_parsed_expression = std::move(parse_result.expr);
+ return parse_result.description;
}
ControlReference::ControlReference() : range(1), m_parsed_expression(nullptr)
diff --git a/Source/Core/InputCommon/ControlReference/ControlReference.h b/Source/Core/InputCommon/ControlReference/ControlReference.h
index de289ba265..fb4b5cc1df 100644
--- a/Source/Core/InputCommon/ControlReference/ControlReference.h
+++ b/Source/Core/InputCommon/ControlReference/ControlReference.h
@@ -38,7 +38,9 @@ public:
ciface::ExpressionParser::ParseStatus GetParseStatus() const;
void UpdateReference(ciface::ExpressionParser::ControlEnvironment& env);
std::string GetExpression() const;
- void SetExpression(std::string expr);
+
+ // Returns a human-readable error description when the given expression is invalid.
+ std::optional<std::string> SetExpression(std::string expr);
ControlState range;