summaryrefslogtreecommitdiff
path: root/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp
diff options
context:
space:
mode:
authorspycrab <spycrab@users.noreply.github.com>2018-07-07 00:58:37 +0200
committerGitHub <noreply@github.com>2018-07-07 00:58:37 +0200
commit3d1a7737d86f4ecdf0131f5b84198f288800da3b (patch)
tree747e394036c189c46add1b3e1451e50f48230e11 /Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp
parent059880bb1640d5a3b0e1fbbf66e1a356df4b9f41 (diff)
parent13ba24c5a6795532c8893eccf2a21ae95682e1b7 (diff)
Merge pull request #7205 from spycrab/qt_rename
Move DolphinQt2 to DolphinQt
Diffstat (limited to 'Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp')
-rw-r--r--Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp235
1 files changed, 235 insertions, 0 deletions
diff --git a/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp b/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp
new file mode 100644
index 0000000000..0e575a774b
--- /dev/null
+++ b/Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp
@@ -0,0 +1,235 @@
+// Copyright 2017 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <future>
+#include <thread>
+#include <utility>
+
+#include <QApplication>
+#include <QFontMetrics>
+#include <QMouseEvent>
+#include <QRegExp>
+#include <QString>
+#include <QTimer>
+
+#include "DolphinQt/Config/Mapping/MappingButton.h"
+
+#include "Common/Thread.h"
+#include "Core/Core.h"
+
+#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 "DolphinQt/QtUtils/BlockUserInputFilter.h"
+#include "DolphinQt/Settings.h"
+
+#include "InputCommon/ControlReference/ControlReference.h"
+#include "InputCommon/ControllerEmu/ControllerEmu.h"
+#include "InputCommon/ControllerInterface/ControllerInterface.h"
+#include "InputCommon/ControllerInterface/Device.h"
+
+constexpr int SLIDER_TICK_COUNT = 100;
+constexpr int VERTICAL_PADDING = 2;
+
+static QString EscapeAmpersand(QString&& string)
+{
+ return string.replace(QStringLiteral("&"), QStringLiteral("&&"));
+}
+
+bool MappingButton::IsInput() const
+{
+ return m_reference->IsInput();
+}
+
+MappingButton::MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator)
+ : ElidedButton(EscapeAmpersand(QString::fromStdString(ref->GetExpression()))), m_parent(widget),
+ m_reference(ref)
+{
+ // Force all mapping buttons to use stay at a minimal height
+ int height = QFontMetrics(qApp->font()).height() + 2 * VERTICAL_PADDING;
+
+ setMinimumHeight(height);
+
+ // macOS needs some wiggle room to always get round buttons
+ setMaximumHeight(height + 8);
+
+ // Make sure that long entries don't throw our layout out of whack
+ setMaximumWidth(115);
+
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+
+ Connect();
+ setToolTip(
+ tr("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options."));
+ if (!m_reference->IsInput() || !indicator)
+ return;
+
+ m_timer = new QTimer(this);
+ connect(m_timer, &QTimer::timeout, this, [this] {
+ if (!isActiveWindow())
+ return;
+
+ Settings::Instance().SetControllerStateNeeded(true);
+
+ if (Core::GetState() == Core::State::Uninitialized || Core::GetState() == Core::State::Paused)
+ g_controller_interface.UpdateInput();
+
+ auto state = m_reference->State();
+
+ QFont f = m_parent->font();
+ QPalette p = m_parent->palette();
+
+ if (state != 0)
+ {
+ f.setBold(true);
+ p.setColor(QPalette::ButtonText, Qt::red);
+ }
+
+ setFont(f);
+ setPalette(p);
+
+ Settings::Instance().SetControllerStateNeeded(false);
+ });
+
+ m_timer->start(1000 / 30);
+}
+
+void MappingButton::Connect()
+{
+ connect(this, &MappingButton::pressed, this, &MappingButton::Detect);
+}
+
+void MappingButton::Detect()
+{
+ if (m_parent->GetDevice() == nullptr || !m_reference->IsInput())
+ return;
+
+ installEventFilter(BlockUserInputFilter::Instance());
+ grabKeyboard();
+
+ // Make sure that we don't block event handling
+ std::thread thread([this] {
+ setText(QStringLiteral("..."));
+
+ // Avoid that the button press itself is registered as an event
+ Common::SleepCurrentThread(100);
+
+ std::vector<std::future<std::pair<QString, QString>>> futures;
+ QString expr;
+
+ if (m_parent->GetParent()->IsMappingAllDevices())
+ {
+ for (const std::string& device_str : g_controller_interface.GetAllDeviceStrings())
+ {
+ ciface::Core::DeviceQualifier devq;
+ devq.FromString(device_str);
+
+ auto dev = g_controller_interface.FindDevice(devq);
+
+ auto future = std::async(std::launch::async, [this, devq, dev, device_str] {
+ return std::make_pair(
+ QString::fromStdString(device_str),
+ MappingCommon::DetectExpression(m_reference, dev.get(),
+ m_parent->GetController()->GetDefaultDevice()));
+ });
+
+ futures.push_back(std::move(future));
+ }
+
+ bool done = false;
+
+ while (!done)
+ {
+ for (auto& future : futures)
+ {
+ const auto status = future.wait_for(std::chrono::milliseconds(10));
+ if (status == std::future_status::ready)
+ {
+ const auto pair = future.get();
+
+ done = true;
+
+ if (pair.second.isEmpty())
+ break;
+
+ expr = QStringLiteral("`%1:%2`")
+ .arg(pair.first)
+ .arg(pair.second.startsWith(QLatin1Char('`')) ? pair.second.mid(1) :
+ pair.second);
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ const auto dev = m_parent->GetDevice();
+ expr = MappingCommon::DetectExpression(m_reference, dev.get(),
+ m_parent->GetController()->GetDefaultDevice());
+ }
+
+ releaseKeyboard();
+ removeEventFilter(BlockUserInputFilter::Instance());
+
+ if (!expr.isEmpty())
+ {
+ m_reference->SetExpression(expr.toStdString());
+ m_parent->SaveSettings();
+ Update();
+ m_parent->GetController()->UpdateReferences(g_controller_interface);
+
+ if (m_parent->IsIterativeInput())
+ m_parent->NextButton(this);
+ }
+ else
+ {
+ OnButtonTimeout();
+ }
+ });
+
+ thread.detach();
+}
+
+void MappingButton::OnButtonTimeout()
+{
+ setText(EscapeAmpersand(QString::fromStdString(m_reference->GetExpression())));
+}
+
+void MappingButton::Clear()
+{
+ m_reference->SetExpression("");
+ m_reference->range = 100.0 / SLIDER_TICK_COUNT;
+ m_parent->SaveSettings();
+ Update();
+}
+
+void MappingButton::Update()
+{
+ const auto lock = ControllerEmu::EmulatedController::GetStateLock();
+ m_reference->UpdateReference(g_controller_interface,
+ m_parent->GetController()->GetDefaultDevice());
+ setText(EscapeAmpersand(QString::fromStdString(m_reference->GetExpression())));
+}
+
+void MappingButton::mouseReleaseEvent(QMouseEvent* event)
+{
+ switch (event->button())
+ {
+ case Qt::MouseButton::LeftButton:
+ if (m_reference->IsInput())
+ QPushButton::mouseReleaseEvent(event);
+ else
+ emit AdvancedPressed();
+ return;
+ case Qt::MouseButton::MidButton:
+ Clear();
+ return;
+ case Qt::MouseButton::RightButton:
+ emit AdvancedPressed();
+ return;
+ default:
+ return;
+ }
+}