diff options
| author | spycrab <spycrab@users.noreply.github.com> | 2018-07-07 00:40:15 +0200 |
|---|---|---|
| committer | spycrab <spycrab@users.noreply.github.com> | 2018-07-07 00:48:38 +0200 |
| commit | 13ba24c5a6795532c8893eccf2a21ae95682e1b7 (patch) | |
| tree | 747e394036c189c46add1b3e1451e50f48230e11 /Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp | |
| parent | 059880bb1640d5a3b0e1fbbf66e1a356df4b9f41 (diff) | |
Move DolphinQt2 to DolphinQt
Diffstat (limited to 'Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp')
| -rw-r--r-- | Source/Core/DolphinQt/Config/Mapping/MappingButton.cpp | 235 |
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; + } +} |
