early-access version 1315

main
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 yuzu emulator early access
============= =============
This is the source code for early-access 1314. This is the source code for early-access 1315.
## Legal Notice ## Legal Notice

View File

@ -1,26 +1,5 @@
<RCC> <RCC>
<qresource prefix="controller"> <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">applet_dual_joycon.png</file>
<file alias="applet_dual_joycon_dark">applet_dual_joycon_dark.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> <file alias="applet_dual_joycon_midnight">applet_dual_joycon_midnight.png</file>

View File

@ -16,17 +16,30 @@ class IntrusiveRedBlackTreeImpl;
} }
struct IntrusiveRedBlackTreeNode { 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: private:
RB_ENTRY(IntrusiveRedBlackTreeNode) entry{}; EntryType entry{};
friend class impl::IntrusiveRedBlackTreeImpl; friend class impl::IntrusiveRedBlackTreeImpl;
template <class, class, class> template <class, class, class>
friend class IntrusiveRedBlackTree; friend class IntrusiveRedBlackTree;
public:
constexpr IntrusiveRedBlackTreeNode() = default;
}; };
template <class T, class Traits, class Comparator> template <class T, class Traits, class Comparator>
@ -35,17 +48,12 @@ class IntrusiveRedBlackTree;
namespace impl { namespace impl {
class IntrusiveRedBlackTreeImpl { class IntrusiveRedBlackTreeImpl {
private: private:
template <class, class, class> template <class, class, class>
friend class ::Common::IntrusiveRedBlackTree; friend class ::Common::IntrusiveRedBlackTree;
private: using RootType = RBHead<IntrusiveRedBlackTreeNode>;
RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode); RootType root;
using RootType = IntrusiveRedBlackTreeRoot;
private:
IntrusiveRedBlackTreeRoot root;
public: public:
template <bool Const> 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: private:
// Define accessors using RB_* functions. // Define accessors using RB_* functions.
constexpr void InitializeImpl() {
RB_INIT(&this->root);
}
bool EmptyImpl() const { bool EmptyImpl() const {
return RB_EMPTY(&this->root); return root.IsEmpty();
} }
IntrusiveRedBlackTreeNode* GetMinImpl() const { IntrusiveRedBlackTreeNode* GetMinImpl() const {
return RB_MIN(IntrusiveRedBlackTreeRoot, return RB_MIN(const_cast<RootType*>(&root));
const_cast<IntrusiveRedBlackTreeRoot*>(&this->root));
} }
IntrusiveRedBlackTreeNode* GetMaxImpl() const { IntrusiveRedBlackTreeNode* GetMaxImpl() const {
return RB_MAX(IntrusiveRedBlackTreeRoot, return RB_MAX(const_cast<RootType*>(&root));
const_cast<IntrusiveRedBlackTreeRoot*>(&this->root));
} }
IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) { IntrusiveRedBlackTreeNode* RemoveImpl(IntrusiveRedBlackTreeNode* node) {
return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node); return RB_REMOVE(&root, node);
} }
public: public:
static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) { static IntrusiveRedBlackTreeNode* GetNext(IntrusiveRedBlackTreeNode* node) {
return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node); return RB_NEXT(node);
} }
static IntrusiveRedBlackTreeNode* GetPrev(IntrusiveRedBlackTreeNode* 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*>( return static_cast<const IntrusiveRedBlackTreeNode*>(
GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node))); GetNext(const_cast<IntrusiveRedBlackTreeNode*>(node)));
} }
static IntrusiveRedBlackTreeNode const* GetPrev(const IntrusiveRedBlackTreeNode* node) { static const IntrusiveRedBlackTreeNode* GetPrev(const IntrusiveRedBlackTreeNode* node) {
return static_cast<const IntrusiveRedBlackTreeNode*>( return static_cast<const IntrusiveRedBlackTreeNode*>(
GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(node))); GetPrev(const_cast<IntrusiveRedBlackTreeNode*>(node)));
} }
public: public:
constexpr IntrusiveRedBlackTreeImpl() : root() { constexpr IntrusiveRedBlackTreeImpl() {}
this->InitializeImpl();
}
// Iterator accessors. // Iterator accessors.
iterator begin() { iterator begin() {
@ -269,8 +265,6 @@ private:
ImplType impl{}; ImplType impl{};
public: public:
struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot {};
template <bool Const> template <bool Const>
class Iterator; 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: private:
static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs, static int CompareImpl(const IntrusiveRedBlackTreeNode* lhs,
const IntrusiveRedBlackTreeNode* rhs) { const IntrusiveRedBlackTreeNode* rhs) {
@ -379,41 +368,27 @@ private:
// Define accessors using RB_* functions. // Define accessors using RB_* functions.
IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) { IntrusiveRedBlackTreeNode* InsertImpl(IntrusiveRedBlackTreeNode* node) {
return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, return RB_INSERT(&impl.root, node, CompareImpl);
static_cast<IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root),
node);
} }
IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const { IntrusiveRedBlackTreeNode* FindImpl(const IntrusiveRedBlackTreeNode* node) const {
return RB_FIND( return RB_FIND(const_cast<ImplType::RootType*>(&impl.root),
IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl);
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
const_cast<IntrusiveRedBlackTreeNode*>(node));
} }
IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const { IntrusiveRedBlackTreeNode* NFindImpl(const IntrusiveRedBlackTreeNode* node) const {
return RB_NFIND( return RB_NFIND(const_cast<ImplType::RootType*>(&impl.root),
IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeNode*>(node), CompareImpl);
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
const_cast<IntrusiveRedBlackTreeNode*>(node));
} }
IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const { IntrusiveRedBlackTreeNode* FindLightImpl(const_light_pointer lelm) const {
return RB_FIND_LIGHT( return RB_FIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root),
IntrusiveRedBlackTreeRootWithCompare, static_cast<const void*>(lelm), LightCompareImpl);
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
static_cast<const void*>(lelm));
} }
IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const { IntrusiveRedBlackTreeNode* NFindLightImpl(const_light_pointer lelm) const {
return RB_NFIND_LIGHT( return RB_NFIND_LIGHT(const_cast<ImplType::RootType*>(&impl.root),
IntrusiveRedBlackTreeRootWithCompare, static_cast<const void*>(lelm), LightCompareImpl);
const_cast<IntrusiveRedBlackTreeRootWithCompare*>(
static_cast<const IntrusiveRedBlackTreeRootWithCompare*>(&this->impl.root)),
static_cast<const void*>(lelm));
} }
public: public:

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -185,6 +185,16 @@ public:
return {0.0f, 0.0f}; 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 { bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
const auto [x, y] = GetStatus(); const auto [x, y] = GetStatus();
const float directional_deadzone = 0.5f; const float directional_deadzone = 0.5f;

View File

@ -373,6 +373,16 @@ public:
return {}; 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 { bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
const auto [x, y] = GetStatus(); const auto [x, y] = GetStatus();
const float directional_deadzone = 0.5f; const float directional_deadzone = 0.5f;

View File

@ -71,6 +71,8 @@ add_executable(yuzu
configuration/configure_input_player.cpp configuration/configure_input_player.cpp
configuration/configure_input_player.h configuration/configure_input_player.h
configuration/configure_input_player.ui 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.cpp
configuration/configure_input_profile_dialog.h configuration/configure_input_profile_dialog.h
configuration/configure_input_profile_dialog.ui 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_branch),
QString::fromUtf8(Common::g_scm_desc))); QString::fromUtf8(Common::g_scm_desc)));
setAttribute(Qt::WA_AcceptTouchEvents); setAttribute(Qt::WA_AcceptTouchEvents);
auto layout = new QHBoxLayout(this); auto* layout = new QHBoxLayout(this);
layout->setMargin(0); layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout); setLayout(layout);
input_subsystem->Initialize(); input_subsystem->Initialize();

View File

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

View File

@ -106,7 +106,7 @@ private:
void LoadConfiguration(); void LoadConfiguration();
/// Called when the button was pressed. /// 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, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type); InputCommon::Polling::DeviceType type);

View File

@ -1964,39 +1964,39 @@
</item> </item>
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QFrame" name="controllerFrame"> <widget class="PlayerControlPreview" name="controllerFrame">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="font"> <property name="font">
<font> <font>
<weight>75</weight> <weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">image: url(:/controller/pro);</string> <string notr="true">image: url(:/controller/pro);</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_4"> <layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>0</number> <number>0</number>
</property> </property>
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
</layout> </layout>
</widget> </widget>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="miscButtons"> <layout class="QHBoxLayout" name="miscButtons">
<property name="spacing"> <property name="spacing">
@ -3087,6 +3087,14 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>PlayerControlPreview</class>
<extends>QFrame</extends>
<header>yuzu/configuration/configure_input_player_widget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources> <resources>
<include location="../../../dist/icons/controller/controller.qrc"/> <include location="../../../dist/icons/controller/controller.qrc"/>
</resources> </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} { GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
auto* const key_release_eater = new KeyReleaseEater(parent, this); auto* const key_release_eater = new KeyReleaseEater(parent, this);
layout_filter = new QHBoxLayout; layout_filter = new QHBoxLayout;
layout_filter->setMargin(8); layout_filter->setContentsMargins(8, 8, 8, 8);
label_filter = new QLabel; label_filter = new QLabel;
label_filter->setText(tr("Filter:")); label_filter->setText(tr("Filter:"));
edit_filter = new QLineEdit; edit_filter = new QLineEdit;