early-access version 1315

This commit is contained in:
pineappleEA 2021-01-13 20:34:26 +01:00
parent cdca8a3cd5
commit 2a59cc55e2
15 changed files with 2689 additions and 897 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access
=============
This is the source code for early-access 1314.
This is the source code for early-access 1315.
## Legal Notice

View file

@ -1,26 +1,5 @@
<RCC>
<qresource prefix="controller">
<file alias="dual_joycon">dual_joycon.png</file>
<file alias="dual_joycon_dark">dual_joycon_dark.png</file>
<file alias="dual_joycon_midnight">dual_joycon_midnight.png</file>
<file alias="handheld">handheld.png</file>
<file alias="handheld_dark">handheld_dark.png</file>
<file alias="handheld_midnight">handheld_midnight.png</file>
<file alias="pro_controller">pro_controller.png</file>
<file alias="pro_controller_dark">pro_controller_dark.png</file>
<file alias="pro_controller_midnight">pro_controller_midnight.png</file>
<file alias="single_joycon_left">single_joycon_left.png</file>
<file alias="single_joycon_left_dark">single_joycon_left_dark.png</file>
<file alias="single_joycon_left_midnight">single_joycon_left_midnight.png</file>
<file alias="single_joycon_right">single_joycon_right.png</file>
<file alias="single_joycon_right_dark">single_joycon_right_dark.png</file>
<file alias="single_joycon_right_midnight">single_joycon_right_midnight.png</file>
<file alias="single_joycon_left_vertical">single_joycon_left_vertical.png</file>
<file alias="single_joycon_left_vertical_dark">single_joycon_left_vertical_dark.png</file>
<file alias="single_joycon_left_vertical_midnight">single_joycon_left_vertical_midnight.png</file>
<file alias="single_joycon_right_vertical">single_joycon_right_vertical.png</file>
<file alias="single_joycon_right_vertical_dark">single_joycon_right_vertical_dark.png</file>
<file alias="single_joycon_right_vertical_midnight">single_joycon_right_vertical_midnight.png</file>
<file alias="applet_dual_joycon">applet_dual_joycon.png</file>
<file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.png</file>
<file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>

View file

@ -16,17 +16,30 @@ class IntrusiveRedBlackTreeImpl;
}
struct IntrusiveRedBlackTreeNode {
public:
using EntryType = RBEntry<IntrusiveRedBlackTreeNode>;
constexpr IntrusiveRedBlackTreeNode() = default;
void SetEntry(const EntryType& new_entry) {
entry = new_entry;
}
[[nodiscard]] EntryType& GetEntry() {
return entry;
}
[[nodiscard]] const EntryType& GetEntry() const {
return entry;
}
private:
RB_ENTRY(IntrusiveRedBlackTreeNode) entry{};
EntryType entry{};
friend class impl::IntrusiveRedBlackTreeImpl;
template <class, class, class>
friend class IntrusiveRedBlackTree;
public:
constexpr IntrusiveRedBlackTreeNode() = default;
};
template <class T, class Traits, class Comparator>
@ -35,17 +48,12 @@ class IntrusiveRedBlackTree;
namespace impl {
class IntrusiveRedBlackTreeImpl {
private:
template <class, class, class>
friend class ::Common::IntrusiveRedBlackTree;
private:
RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode);
using RootType = IntrusiveRedBlackTreeRoot;
private:
IntrusiveRedBlackTreeRoot root;
using RootType = RBHead<IntrusiveRedBlackTreeNode>;
RootType root;
public:
template <bool Const>
@ -121,57 +129,45 @@ public:
}
};
protected:
// Generate static implementations for non-comparison operations for IntrusiveRedBlackTreeRoot.
RB_GENERATE_WITHOUT_COMPARE_STATIC(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode, entry);
private:
// Define accessors using RB_* functions.
constexpr void InitializeImpl() {
RB_INIT(&this->root);
}
bool EmptyImpl() const {
return RB_EMPTY(&this->root);
return root.IsEmpty();
}
IntrusiveRedBlackTreeNode* GetMinImpl() const {
return RB_MIN(IntrusiveRedBlackTreeRoot,
const_cast<IntrusiveRedBlackTreeRoot*>(&this->root));
return RB_MIN(const_cast<RootType*>(&root));
}
IntrusiveRedBlackTreeNode* GetMaxImpl() const {
return RB_MAX(IntrusiveRedBlackTreeRoot,
const_cast<IntrusiveRedBlackTreeRoot*>(&this->root));
return RB_MAX(const_cast<RootType*>(&root));
}
IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) {
return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node);
return RB_REMOVE(&root, node);
}
public:
static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) {
return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node);
return RB_NEXT(node);
}
static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* node) {
return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node);
return RB_PREV(node);
}
static IntrusiveRedBlackTreeNode const* GetNext(const IntrusiveRedBlackTreeNode* node) {
static const IntrusiveRedBlackTreeNode* GetNext(const IntrusiveRedBlackTreeNode* node) {
return static_cast<const IntrusiveRedBlackTreeNode*>(
GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node)));
}
static IntrusiveRedBlackTreeNode const* GetPrev(const IntrusiveRedBlackTreeNode* node) {
static const IntrusiveRedBlackTreeNode* GetPrev(const IntrusiveRedBlackTreeNode* node) {
return static_cast<const IntrusiveRedBlackTreeNode*>(
GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(node)));
}
public:
constexpr IntrusiveRedBlackTreeImpl() : root() {
this->InitializeImpl();
}
constexpr IntrusiveRedBlackTreeImpl() {}
// Iterator accessors.
iterator begin() {
@ -269,8 +265,6 @@ private:
ImplType impl{};
public:
struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot {};
template <bool Const>
class Iterator;
@ -362,11 +356,6 @@ public:
}
};
private:
// Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot.
RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode,
entry, CompareImpl, LightCompareImpl);
private:
static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs,
const IntrusiveRedBlackTreeNode* rhs) {
@ -379,41 +368,27 @@ private:
// Define accessors using RB_* functions.
IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) {
return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare,
static_cast<IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root),
node);
return RB_INSERT(&impl.root, node, CompareImpl);
}
IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const {
return RB_FIND(
IntrusiveRedBlackTreeRootWithCompare,
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
const_cast<IntrusiveRedBlackTreeNode*>(node));
return RB_FIND(const_cast<ImplType::RootType*>(&impl.root),
const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl);
}
IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const {
return RB_NFIND(
IntrusiveRedBlackTreeRootWithCompare,
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
const_cast<IntrusiveRedBlackTreeNode*>(node));
return RB_NFIND(const_cast<ImplType::RootType*>(&impl.root),
const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl);
}
IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const {
return RB_FIND_LIGHT(
IntrusiveRedBlackTreeRootWithCompare,
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
static_cast<const void*>(lelm));
return RB_FIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root),
static_cast<const void*>(lelm), LightCompareImpl);
}
IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const {
return RB_NFIND_LIGHT(
IntrusiveRedBlackTreeRootWithCompare,
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
static_cast<const void*>(lelm));
return RB_NFIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root),
static_cast<const void*>(lelm), LightCompareImpl);
}
public:

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,11 @@ enum class AnalogDirection : u8 {
UP,
DOWN,
};
struct AnalogProperties {
float deadzone;
float range;
float threshold;
};
/// An abstract class template for an input device (a button, an analog input, etc.).
template <typename StatusType>
@ -30,6 +35,12 @@ public:
virtual StatusType GetStatus() const {
return {};
}
virtual StatusType GetRawStatus() const {
return GetStatus();
}
virtual AnalogProperties GetAnalogProperties() const {
return {};
}
virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
return {};
}

View file

@ -185,6 +185,16 @@ public:
return {0.0f, 0.0f};
}
std::tuple<float, float> GetRawStatus() const override {
const float x = GetAxis(axis_x);
const float y = GetAxis(axis_y);
return {x, y};
}
Input::AnalogProperties GetAnalogProperties() const override {
return {deadzone, range, 0.5f};
}
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
const auto [x, y] = GetStatus();
const float directional_deadzone = 0.5f;

View file

@ -373,6 +373,16 @@ public:
return {};
}
std::tuple<float, float> GetRawStatus() const override {
const float x = joystick->GetAxis(axis_x, range);
const float y = joystick->GetAxis(axis_y, range);
return {x, -y};
}
Input::AnalogProperties GetAnalogProperties() const override {
return {deadzone, range, 0.5f};
}
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
const auto [x, y] = GetStatus();
const float directional_deadzone = 0.5f;

View file

@ -71,6 +71,8 @@ add_executable(yuzu
configuration/configure_input_player.cpp
configuration/configure_input_player.h
configuration/configure_input_player.ui
configuration/configure_input_player_widget.cpp
configuration/configure_input_player_widget.h
configuration/configure_input_profile_dialog.cpp
configuration/configure_input_profile_dialog.h
configuration/configure_input_profile_dialog.ui

View file

@ -290,8 +290,8 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
QString::fromUtf8(Common::g_scm_branch),
QString::fromUtf8(Common::g_scm_desc)));
setAttribute(Qt::WA_AcceptTouchEvents);
auto layout = new QHBoxLayout(this);
layout->setMargin(0);
auto* layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
input_subsystem->Initialize();

View file

@ -23,6 +23,7 @@
#include "ui_configure_input_player.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_input_player.h"
#include "yuzu/configuration/configure_input_player_widget.h"
#include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h"
#include "yuzu/util/limitable_input_dialog.h"
@ -254,11 +255,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup};
analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param,
int default_val, InputCommon::Polling::DeviceType type) {
const auto ConfigureButtonClick = [&](QPushButton* button, std::size_t button_id,
Common::ParamPackage* param, int default_val,
InputCommon::Polling::DeviceType type) {
connect(button, &QPushButton::clicked, [=, this] {
HandleClick(
button,
button, button_id,
[=, this](Common::ParamPackage params) {
// Workaround for ZL & ZR for analog triggers like on XBOX
// controllers. Analog triggers (from controllers like the XBOX
@ -286,12 +288,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
continue;
}
ConfigureButtonClick(button_map[button_id], &buttons_param[button_id],
ConfigureButtonClick(button_map[button_id], button_id, &buttons_param[button_id],
Config::default_buttons[button_id],
InputCommon::Polling::DeviceType::Button);
button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
@ -300,6 +301,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
button_map[button_id]->setText(tr("[not set]"));
});
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
});
}
@ -309,7 +311,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
continue;
}
ConfigureButtonClick(motion_map[motion_id], &motions_param[motion_id],
ConfigureButtonClick(motion_map[motion_id], motion_id, &motions_param[motion_id],
Config::default_motions[motion_id],
InputCommon::Polling::DeviceType::Motion);
@ -348,7 +350,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
}
}
HandleClick(
analog_map_buttons[analog_id][sub_button_id],
analog_map_buttons[analog_id][sub_button_id], analog_id,
[=, this](const Common::ParamPackage& params) {
SetAnalogParam(params, analogs_param[analog_id],
analog_sub_buttons[sub_button_id]);
@ -358,41 +360,43 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(analog_button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
analogs_param[analog_id].Clear();
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
});
context_menu.addAction(tr("Invert axis"), [&] {
if (sub_button_id == 2 || sub_button_id == 3) {
const bool invert_value =
analogs_param[analog_id].Get("invert_x", "+") == "-";
const std::string invert_str = invert_value ? "+" : "-";
analogs_param[analog_id].Set("invert_x", invert_str);
}
if (sub_button_id == 0 || sub_button_id == 1) {
const bool invert_value =
analogs_param[analog_id].Get("invert_y", "+") == "-";
const std::string invert_str = invert_value ? "+" : "-";
analogs_param[analog_id].Set("invert_y", invert_str);
}
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM;
++sub_button_id) {
analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
}
});
context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
menu_location));
connect(
analog_button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
analogs_param[analog_id].Clear();
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
});
context_menu.addAction(tr("Invert axis"), [&] {
if (sub_button_id == 2 || sub_button_id == 3) {
const bool invert_value =
analogs_param[analog_id].Get("invert_x", "+") == "-";
const std::string invert_str = invert_value ? "+" : "-";
analogs_param[analog_id].Set("invert_x", invert_str);
}
if (sub_button_id == 0 || sub_button_id == 1) {
const bool invert_value =
analogs_param[analog_id].Get("invert_y", "+") == "-";
const std::string invert_str = invert_value ? "+" : "-";
analogs_param[analog_id].Set("invert_y", invert_str);
}
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM;
++sub_button_id) {
analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText(
analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
}
});
context_menu.exec(
analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(menu_location));
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
});
}
// Handle clicks for the modifier buttons as well.
connect(analog_map_modifier_button[analog_id], &QPushButton::clicked, [=, this] {
HandleClick(
analog_map_modifier_button[analog_id],
analog_map_modifier_button[analog_id], analog_id,
[=, this](const Common::ParamPackage& params) {
analogs_param[analog_id].Set("modifier", params.Serialize());
},
@ -416,12 +420,14 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
[=, this] {
const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
analogs_param[analog_id].Set("range", spinbox_value / 100.0f);
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
});
connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] {
const auto slider_value = analog_map_deadzone_slider[analog_id]->value();
analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value));
analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
});
connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] {
@ -433,8 +439,10 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
}
// Player Connected checkbox
connect(ui->groupConnectedController, &QGroupBox::toggled,
[this](bool checked) { emit Connected(checked); });
connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) {
emit Connected(checked);
ui->controllerFrame->SetConnectedStatus(checked);
});
if (player_index == 0) {
connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged),
@ -553,6 +561,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
// TODO(wwylele): enable this when we actually emulate it
ui->buttonHome->setEnabled(false);
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked());
}
ConfigureInputPlayer::~ConfigureInputPlayer() = default;
@ -849,6 +859,7 @@ void ConfigureInputPlayer::UpdateUI() {
modifier_label->setVisible(!is_controller);
modifier_slider->setVisible(!is_controller);
range_groupbox->setVisible(is_controller);
ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param);
}
}
@ -965,8 +976,8 @@ void ConfigureInputPlayer::UpdateControllerIcon() {
return QString{};
}
}();
ui->controllerFrame->setStyleSheet(stylesheet.arg(theme));
ui->controllerFrame->SetControllerType(
GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()));
}
void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
@ -1103,7 +1114,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
}
void ConfigureInputPlayer::HandleClick(
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
QPushButton* button, std::size_t button_id,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
button->setText(tr("Shake!"));
@ -1147,6 +1159,12 @@ void ConfigureInputPlayer::HandleClick(
input_subsystem->GetMouseTouch()->BeginConfiguration();
}
if (type == InputCommon::Polling::DeviceType::Button) {
ui->controllerFrame->BeginMappingButton(button_id);
} else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) {
ui->controllerFrame->BeginMappingAnalog(button_id);
}
timeout_timer->start(2500); // Cancel after 2.5 seconds
poll_timer->start(50); // Check for new inputs every 50ms
}
@ -1177,6 +1195,7 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
UpdateUI();
UpdateInputDeviceCombobox();
ui->controllerFrame->EndMapping();
input_setter = std::nullopt;
}

View file

@ -106,7 +106,7 @@ private:
void LoadConfiguration();
/// Called when the button was pressed.
void HandleClick(QPushButton* button,
void HandleClick(QPushButton* button, std::size_t button_id,
std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type);

View file

@ -1964,39 +1964,39 @@
</item>
</layout>
</item>
<item>
<widget class="QFrame" name="controllerFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/controller/pro);</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<widget class="PlayerControlPreview" name="controllerFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="styleSheet">
<string notr="true">image: url(:/controller/pro);</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="miscButtons">
<property name="spacing">
@ -3087,6 +3087,14 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>PlayerControlPreview</class>
<extends>QFrame</extends>
<header>yuzu/configuration/configure_input_player_widget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../../../dist/icons/controller/controller.qrc"/>
</resources>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,157 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <QFrame>
#include <QPointer>
#include "core/frontend/input.h"
#include "core/settings.h"
class QLabel;
using AnalogParam = std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs>;
using ButtonParam = std::array<Common::ParamPackage, Settings::NativeButton::NumButtons>;
// Widget for representing touchscreen coordinates
class PlayerControlPreview : public QFrame {
Q_OBJECT
public:
explicit PlayerControlPreview(QWidget* parent);
~PlayerControlPreview() override;
void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param,
const AnalogParam& analogs_param);
void SetConnectedStatus(bool checked);
void SetControllerType(Settings::ControllerType type);
void BeginMappingButton(std::size_t button_id);
void BeginMappingAnalog(std::size_t button_id);
void EndMapping();
protected:
void paintEvent(QPaintEvent* event) override;
private:
enum class Direction : std::size_t {
None,
Up,
Right,
Down,
Left,
};
struct AxisValue {
QPointF value{};
QPointF raw_value{};
Input::AnalogProperties properties{};
int size{};
QPoint offset{};
bool active{};
};
struct LedPattern {
bool position1;
bool position2;
bool position3;
bool position4;
};
struct ColorMapping {
QColor outline{};
QColor primary{};
QColor left{};
QColor right{};
QColor button{};
QColor button2{};
QColor font{};
QColor font2{};
QColor highlight{};
QColor highlight2{};
QColor transparent{};
QColor indicator{};
QColor led_on{};
QColor led_off{};
QColor slider{};
QColor slider_button{};
QColor slider_arrow{};
QColor deadzone{};
};
static LedPattern GetColorPattern(std::size_t index, bool player_on);
void UpdateColors();
// Draw controller functions
void DrawHandheldController(QPainter& p, QPointF center);
void DrawDualController(QPainter& p, QPointF center);
void DrawLeftController(QPainter& p, QPointF center);
void DrawRightController(QPainter& p, QPointF center);
void DrawProController(QPainter& p, QPointF center);
// Draw body functions
void DrawHandheldBody(QPainter& p, QPointF center);
void DrawDualBody(QPainter& p, QPointF center);
void DrawLeftBody(QPainter& p, QPointF center);
void DrawRightBody(QPainter& p, QPointF center);
void DrawProBody(QPainter& p, QPointF center);
// Draw triggers functions
void DrawProTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawHandheldTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawDualTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawDualZTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed);
void DrawLeftTriggers(QPainter& p, QPointF center, bool left_pressed);
void DrawLeftZTriggers(QPainter& p, QPointF center, bool left_pressed);
void DrawRightTriggers(QPainter& p, QPointF center, bool right_pressed);
void DrawRightZTriggers(QPainter& p, QPointF center, bool right_pressed);
// Draw joystick functions
void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed);
void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed);
void DrawRawJoystick(QPainter& p, QPointF center, const QPointF value,
const Input::AnalogProperties properties);
void DrawProJoystick(QPainter& p, QPointF center, bool pressed);
// Draw button functions
void DrawCircleButton(QPainter& p, QPointF center, bool pressed, int button_size);
void DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height,
const Direction direction = Direction::None, float radius = 2);
void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size);
void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size);
void DrawArrowButton(QPainter& p, QPointF center, const Direction direction, bool pressed);
// Draw icon functions
void DrawHouseIcon(QPainter& p, QPointF center, float icon_size);
void DrawArrow(QPainter& p, QPointF center, const Direction direction, float size);
// Draw primitive types
template <size_t N>
void DrawPolygon(QPainter& p, const std::array<QPointF, N>& polygon);
void DrawCircle(QPainter& p, QPointF center, float size);
void DrawRectangle(QPainter& p, QPointF center, float width, float height);
void DrawRoundRectangle(QPainter& p, QPointF center, float width, float height, float round);
void DrawText(QPainter& p, QPointF center, float text_size, const QString& text);
void SetTextFont(QPainter& p, float text_size,
const QString font_family = QStringLiteral("sans-serif"));
using ButtonArray =
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::BUTTON_NS_END>;
using StickArray =
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>;
bool mapping_active{};
int blink_counter{};
QColor button_color{};
ColorMapping colors{};
std::array<QColor, 4> led_color{};
ButtonArray buttons{};
StickArray sticks{};
std::size_t player_index{};
std::size_t button_mapping_index{Settings::NativeButton::BUTTON_NS_END};
std::size_t analog_mapping_index{Settings::NativeAnalog::NUM_STICKS_HID};
std::array<AxisValue, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{};
std::array<bool, Settings::NativeButton::NumButtons> button_values{};
Settings::ControllerType controller_type{Settings::ControllerType::ProController};
};

View file

@ -119,7 +119,7 @@ void GameListSearchField::setFocus() {
GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
auto* const key_release_eater = new KeyReleaseEater(parent, this);
layout_filter = new QHBoxLayout;
layout_filter->setMargin(8);
layout_filter->setContentsMargins(8, 8, 8, 8);
label_filter = new QLabel;
label_filter->setText(tr("Filter:"));
edit_filter = new QLineEdit;