dolphin/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp
Filippo Tarpini a99932da12
Preserve spaces in mapping preview of control names
PR https://github.com/dolphin-emu/dolphin/pull/9700 removed spaces from within control names, which some user complained about, and their point of view is kind of understandable:
https://bugs.dolphin-emu.org/issues/12605
with this change, only spaces outside (between) control names are trimmed, which are the ones we wanted to trim in the first place.
This will still retain the major advantages from 9700.

Basically, "`Button 1`   +  `Button 2`" was showing as "`Button1`+`Button2`", while it will now show as "`Button 1`+`Button 2`".
2021-08-03 00:04:22 +03:00

198 lines
5.9 KiB
C++

// Copyright 2017 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "DolphinQt/Config/Mapping/MappingButton.h"
#include <QApplication>
#include <QFontMetrics>
#include <QMouseEvent>
#include <QString>
#include "DolphinQt/Config/Mapping/IOWindow.h"
#include "DolphinQt/Config/Mapping/MappingCommon.h"
#include "DolphinQt/Config/Mapping/MappingWidget.h"
#include "DolphinQt/Config/Mapping/MappingWindow.h"
#include "InputCommon/ControlReference/ControlReference.h"
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
#include "InputCommon/ControllerEmu/ControllerEmu.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
constexpr int SLIDER_TICK_COUNT = 100;
// Escape ampersands and simplify the text for a short preview
static QString RefToDisplayString(ControlReference* ref)
{
const bool expression_valid =
ref->GetParseStatus() != ciface::ExpressionParser::ParseStatus::SyntaxError;
QString expression;
{
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
expression = QString::fromStdString(ref->GetExpression());
}
// Split by "`" so that we can give a better preview of control,
// without including their device in front of them, which is usually
// too long to actually see the control.
QStringList controls = expression.split(QLatin1Char{'`'});
// Do try to simplify controls if the parsing had failed, as it might create false positives.
if (expression_valid)
{
for (int i = 0; i < controls.size(); i++)
{
// We have two ` for control so make sure to only consider the odd ones.
if (i % 2)
{
// Use the code from the ControlQualifier instead of duplicating it.
ciface::ExpressionParser::ControlQualifier qualifier;
qualifier.FromString(controls[i].toStdString());
// If the control has got a device specifier/path, add ":" in front of it, to make it clear.
controls[i] = qualifier.has_device ? QStringLiteral(":") : QString();
controls[i].append(QString::fromStdString(qualifier.control_name));
}
else
{
controls[i].remove(QLatin1Char{' '});
}
}
}
// Do not re-add "`" to the final string, we don't need to see it.
expression = controls.join(QStringLiteral(""));
expression.remove(QLatin1Char{'\t'});
expression.remove(QLatin1Char{'\n'});
expression.remove(QLatin1Char{'\r'});
expression.replace(QLatin1Char{'&'}, QStringLiteral("&&"));
return expression;
}
bool MappingButton::IsInput() const
{
return m_reference->IsInput();
}
MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref, bool indicator)
: ElidedButton(RefToDisplayString(ref)), m_parent(parent), m_reference(ref)
{
// Force all mapping buttons to stay at a minimal height.
setFixedHeight(minimumSizeHint().height());
// Make sure that long entries don't throw our layout out of whack.
setFixedWidth(WIDGET_MAX_WIDTH);
setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
if (IsInput())
{
setToolTip(
tr("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options."));
}
else
{
setToolTip(tr("Left/Right-click to configure output.\nMiddle-click to clear."));
}
connect(this, &MappingButton::clicked, this, &MappingButton::Clicked);
if (indicator)
connect(parent, &MappingWidget::Update, this, &MappingButton::UpdateIndicator);
connect(parent, &MappingWidget::ConfigChanged, this, &MappingButton::ConfigChanged);
}
void MappingButton::AdvancedPressed()
{
IOWindow io(m_parent, m_parent->GetController(), m_reference,
m_reference->IsInput() ? IOWindow::Type::Input : IOWindow::Type::Output);
io.exec();
ConfigChanged();
m_parent->SaveSettings();
}
void MappingButton::Clicked()
{
if (!m_reference->IsInput())
{
AdvancedPressed();
return;
}
const auto default_device_qualifier = m_parent->GetController()->GetDefaultDevice();
QString expression;
if (m_parent->GetParent()->IsMappingAllDevices())
{
expression = MappingCommon::DetectExpression(this, g_controller_interface,
g_controller_interface.GetAllDeviceStrings(),
default_device_qualifier);
}
else
{
expression = MappingCommon::DetectExpression(this, g_controller_interface,
{default_device_qualifier.ToString()},
default_device_qualifier);
}
if (expression.isEmpty())
return;
m_reference->SetExpression(expression.toStdString());
m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, m_reference);
ConfigChanged();
m_parent->SaveSettings();
}
void MappingButton::Clear()
{
m_reference->range = 100.0 / SLIDER_TICK_COUNT;
m_reference->SetExpression("");
m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, m_reference);
m_parent->SaveSettings();
ConfigChanged();
}
void MappingButton::UpdateIndicator()
{
if (!isActiveWindow())
return;
QFont f = m_parent->font();
// If the input state is "true" (we can't know the state of outputs), show it in bold.
if (m_reference->IsInput() && m_reference->GetState<bool>())
f.setBold(true);
// If the expression has failed to parse, show it in italic.
// Some expressions still work even the failed to parse so don't prevent the GetState() above.
if (m_reference->GetParseStatus() == ciface::ExpressionParser::ParseStatus::SyntaxError)
f.setItalic(true);
setFont(f);
}
void MappingButton::ConfigChanged()
{
setText(RefToDisplayString(m_reference));
}
void MappingButton::mouseReleaseEvent(QMouseEvent* event)
{
switch (event->button())
{
case Qt::MouseButton::MiddleButton:
Clear();
return;
case Qt::MouseButton::RightButton:
AdvancedPressed();
return;
default:
QPushButton::mouseReleaseEvent(event);
return;
}
}