mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-11-02 08:35:08 -04:00
373 lines
12 KiB
C++
373 lines
12 KiB
C++
#include "InputEditor.h"
|
|
#include "Controller.h"
|
|
#include "Window.h"
|
|
#include "Lib/ImGui/imgui.h"
|
|
#include "ImGuiImpl.h"
|
|
#include "Utils/StringHelper.h"
|
|
#include "Lib/ImGui/imgui_internal.h"
|
|
#include "Cvar.h"
|
|
|
|
namespace Ship {
|
|
|
|
#define SEPARATION() ImGui::Dummy(ImVec2(0, 5))
|
|
|
|
void InputEditor::Init() {
|
|
BtnReading = -1;
|
|
}
|
|
|
|
std::shared_ptr<Controller> GetControllerPerSlot(int slot) {
|
|
auto controlDeck = Ship::Window::GetInstance()->GetControlDeck();
|
|
return controlDeck->GetPhysicalDeviceFromVirtualSlot(slot);
|
|
}
|
|
|
|
void InputEditor::DrawButton(const char* label, int32_t n64Btn) {
|
|
const std::shared_ptr<Controller> backend = GetControllerPerSlot(CurrentPort);
|
|
|
|
float size = 40;
|
|
bool readingMode = BtnReading == n64Btn;
|
|
bool disabled = (BtnReading != -1 && !readingMode) || !backend->Connected() || backend->GetGuid() == "Auto";
|
|
ImVec2 len = ImGui::CalcTextSize(label);
|
|
ImVec2 pos = ImGui::GetCursorPos();
|
|
ImGui::SetCursorPosY(pos.y + len.y / 4);
|
|
ImGui::SetCursorPosX(pos.x + abs(len.x - size));
|
|
ImGui::Text("%s", label);
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPosY(pos.y);
|
|
|
|
if(disabled) {
|
|
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
|
|
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
|
|
}
|
|
|
|
if(readingMode) {
|
|
const int32_t btn = backend->ReadRawPress();
|
|
|
|
if(btn != -1) {
|
|
backend->SetButtonMapping(CurrentPort, n64Btn, btn);
|
|
BtnReading = -1;
|
|
|
|
// avoid immediately triggering another button during gamepad nav
|
|
ImGui::SetKeyboardFocusHere(0);
|
|
}
|
|
}
|
|
|
|
const std::string BtnName = backend->GetButtonName(CurrentPort, n64Btn);
|
|
|
|
if (ImGui::Button(StringHelper::Sprintf("%s##HBTNID_%d", readingMode ? "Press a Key..." : BtnName.c_str(), n64Btn).c_str())) {
|
|
BtnReading = n64Btn;
|
|
backend->ClearRawPress();
|
|
}
|
|
|
|
if(disabled) {
|
|
ImGui::PopItemFlag();
|
|
ImGui::PopStyleVar();
|
|
}
|
|
}
|
|
|
|
void InputEditor::DrawVirtualStick(const char* label, ImVec2 stick) {
|
|
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 5, ImGui::GetCursorPos().y));
|
|
ImGui::BeginChild(label, ImVec2(68, 75), false);
|
|
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
|
const ImVec2 p = ImGui::GetCursorScreenPos();
|
|
|
|
float sz = 45.0f;
|
|
float rad = sz * 0.5f;
|
|
ImVec2 pos = ImVec2(p.x + sz * 0.5f + 12, p.y + sz * 0.5f + 11);
|
|
|
|
float stickX = (stick.x / 83.0f) * (rad * 0.5f);
|
|
float stickY = -(stick.y / 83.0f) * (rad * 0.5f);
|
|
|
|
ImVec4 rect = ImVec4(p.x + 2, p.y + 2, 65, 65);
|
|
draw_list->AddRect(ImVec2(rect.x, rect.y), ImVec2(rect.x + rect.z, rect.y + rect.w), ImColor(100, 100, 100, 255), 0.0f, 0, 1.5f);
|
|
draw_list->AddCircleFilled(pos, rad, ImColor(130, 130, 130, 255), 8);
|
|
draw_list->AddCircleFilled(ImVec2(pos.x + stickX, pos.y + stickY), 5, ImColor(15, 15, 15, 255), 7);
|
|
ImGui::EndChild();
|
|
}
|
|
|
|
void InputEditor::DrawControllerSchema() {
|
|
auto controlDeck = Ship::Window::GetInstance()->GetControlDeck();
|
|
auto Backend = controlDeck->GetPhysicalDeviceFromVirtualSlot(CurrentPort);
|
|
auto profile = Backend->getProfile(CurrentPort);
|
|
bool IsKeyboard = Backend->GetGuid() == "Keyboard" || Backend->GetGuid() == "Auto" || !Backend->Connected();
|
|
std::string ControllerName = Backend->GetControllerName();
|
|
|
|
if (ImGui::BeginCombo("##ControllerEntries", ControllerName.c_str())) {
|
|
for (uint8_t i = 0; i < controlDeck->GetNumPhysicalDevices(); i++) {
|
|
std::string DeviceName = controlDeck->GetPhysicalDevice(i)->GetControllerName();
|
|
if (DeviceName != "Keyboard" && DeviceName != "Auto") {
|
|
DeviceName += "##"+std::to_string(i);
|
|
}
|
|
if (ImGui::Selectable(DeviceName.c_str(), i == controlDeck->GetVirtualDevice(CurrentPort))) {
|
|
controlDeck->SetPhysicalDevice(CurrentPort, i);
|
|
}
|
|
}
|
|
ImGui::EndCombo();
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
if(ImGui::Button("Refresh")) {
|
|
controlDeck->ScanPhysicalDevices();
|
|
}
|
|
|
|
SohImGui::BeginGroupPanel("Buttons", ImVec2(150, 20));
|
|
DrawButton("A", BTN_A);
|
|
DrawButton("B", BTN_B);
|
|
DrawButton("L", BTN_L);
|
|
DrawButton("R", BTN_R);
|
|
DrawButton("Z", BTN_Z);
|
|
DrawButton("START", BTN_START);
|
|
SEPARATION();
|
|
#ifdef __SWITCH__
|
|
SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 56.0f);
|
|
#else
|
|
SohImGui::EndGroupPanel(IsKeyboard ? 7.0f : 48.0f);
|
|
#endif
|
|
ImGui::SameLine();
|
|
SohImGui::BeginGroupPanel("Digital Pad", ImVec2(150, 20));
|
|
DrawButton("Up", BTN_DUP);
|
|
DrawButton("Down", BTN_DDOWN);
|
|
DrawButton("Left", BTN_DLEFT);
|
|
DrawButton("Right", BTN_DRIGHT);
|
|
SEPARATION();
|
|
#ifdef __SWITCH__
|
|
SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 122.0f);
|
|
#else
|
|
SohImGui::EndGroupPanel(IsKeyboard ? 53.0f : 94.0f);
|
|
#endif
|
|
ImGui::SameLine();
|
|
SohImGui::BeginGroupPanel("Analog Stick", ImVec2(150, 20));
|
|
DrawButton("Up", BTN_STICKUP);
|
|
DrawButton("Down", BTN_STICKDOWN);
|
|
DrawButton("Left", BTN_STICKLEFT);
|
|
DrawButton("Right", BTN_STICKRIGHT);
|
|
|
|
if (!IsKeyboard) {
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
|
|
DrawVirtualStick("##MainVirtualStick", ImVec2(Backend->getLeftStickX(CurrentPort), Backend->getLeftStickY(CurrentPort)));
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
|
|
|
|
#ifdef __WIIU__
|
|
ImGui::BeginChild("##MSInput", ImVec2(90 * 2, 50 * 2), false);
|
|
#else
|
|
ImGui::BeginChild("##MSInput", ImVec2(90, 50), false);
|
|
#endif
|
|
ImGui::Text("Deadzone");
|
|
#ifdef __WIIU__
|
|
ImGui::PushItemWidth(80 * 2);
|
|
#else
|
|
ImGui::PushItemWidth(80);
|
|
#endif
|
|
// The window has deadzone per stick, so we need to
|
|
// set the deadzone for both left stick axes here
|
|
// SDL_CONTROLLER_AXIS_LEFTX: 0
|
|
// SDL_CONTROLLER_AXIS_LEFTY: 1
|
|
ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[0], 1.0f, 0.0f, "%.0f");
|
|
profile->AxisDeadzones[1] = profile->AxisDeadzones[0];
|
|
ImGui::PopItemWidth();
|
|
ImGui::EndChild();
|
|
} else {
|
|
ImGui::Dummy(ImVec2(0, 6));
|
|
}
|
|
#ifdef __SWITCH__
|
|
SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 52.0f);
|
|
#else
|
|
SohImGui::EndGroupPanel(IsKeyboard ? 52.0f : 24.0f);
|
|
#endif
|
|
ImGui::SameLine();
|
|
|
|
if (!IsKeyboard) {
|
|
ImGui::SameLine();
|
|
SohImGui::BeginGroupPanel("Right Stick", ImVec2(150, 20));
|
|
DrawButton("Up", BTN_VSTICKUP);
|
|
DrawButton("Down", BTN_VSTICKDOWN);
|
|
DrawButton("Left", BTN_VSTICKLEFT);
|
|
DrawButton("Right", BTN_VSTICKRIGHT);
|
|
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8);
|
|
// 2 is the SDL value for right stick X axis
|
|
// 3 is the SDL value for right stick Y axis.
|
|
DrawVirtualStick("##RightVirtualStick", ImVec2(Backend->getRightStickX(CurrentPort), Backend->getRightStickY(CurrentPort)));
|
|
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
|
|
#ifdef __WIIU__
|
|
ImGui::BeginChild("##CSInput", ImVec2(90 * 2, 85 * 2), false);
|
|
#else
|
|
ImGui::BeginChild("##CSInput", ImVec2(90, 85), false);
|
|
#endif
|
|
ImGui::Text("Deadzone");
|
|
#ifdef __WIIU__
|
|
ImGui::PushItemWidth(80 * 2);
|
|
#else
|
|
ImGui::PushItemWidth(80);
|
|
#endif
|
|
// The window has deadzone per stick, so we need to
|
|
// set the deadzone for both right stick axes here
|
|
// SDL_CONTROLLER_AXIS_RIGHTX: 2
|
|
// SDL_CONTROLLER_AXIS_RIGHTY: 3
|
|
ImGui::InputFloat("##MDZone", &profile->AxisDeadzones[2], 1.0f, 0.0f, "%.0f");
|
|
profile->AxisDeadzones[3] = profile->AxisDeadzones[2];
|
|
ImGui::PopItemWidth();
|
|
ImGui::EndChild();
|
|
#ifdef __SWITCH__
|
|
SohImGui::EndGroupPanel(43.0f);
|
|
#else
|
|
SohImGui::EndGroupPanel(14.0f);
|
|
#endif
|
|
}
|
|
|
|
if(Backend->CanGyro()) {
|
|
#ifndef __WIIU__
|
|
ImGui::SameLine();
|
|
#endif
|
|
SohImGui::BeginGroupPanel("Gyro Options", ImVec2(175, 20));
|
|
float cursorX = ImGui::GetCursorPosX() + 5;
|
|
ImGui::SetCursorPosX(cursorX);
|
|
ImGui::Checkbox("Enable Gyro", &profile->UseGyro);
|
|
ImGui::SetCursorPosX(cursorX);
|
|
ImGui::Text("Gyro Sensitivity: %d%%", static_cast<int>(100.0f * profile->GyroData[GYRO_SENSITIVITY]));
|
|
#ifdef __WIIU__
|
|
ImGui::PushItemWidth(135.0f * 2);
|
|
#else
|
|
ImGui::PushItemWidth(135.0f);
|
|
#endif
|
|
ImGui::SetCursorPosX(cursorX);
|
|
ImGui::SliderFloat("##GSensitivity", &profile->GyroData[GYRO_SENSITIVITY], 0.0f, 1.0f, "");
|
|
ImGui::PopItemWidth();
|
|
ImGui::Dummy(ImVec2(0, 1));
|
|
ImGui::SetCursorPosX(cursorX);
|
|
if (ImGui::Button("Recalibrate Gyro##RGyro")) {
|
|
profile->GyroData[DRIFT_X] = 0.0f;
|
|
profile->GyroData[DRIFT_Y] = 0.0f;
|
|
}
|
|
ImGui::SetCursorPosX(cursorX);
|
|
DrawVirtualStick("##GyroPreview", ImVec2(-10.0f * Backend->getGyroY(CurrentPort), 10.0f * Backend->getGyroX(CurrentPort)));
|
|
|
|
ImGui::SameLine();
|
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
|
|
#ifdef __WIIU__
|
|
ImGui::BeginChild("##GyInput", ImVec2(90 * 2, 85 * 2), false);
|
|
#else
|
|
ImGui::BeginChild("##GyInput", ImVec2(90, 85), false);
|
|
#endif
|
|
ImGui::Text("Drift X");
|
|
#ifdef __WIIU__
|
|
ImGui::PushItemWidth(80 * 2);
|
|
#else
|
|
ImGui::PushItemWidth(80);
|
|
#endif
|
|
ImGui::InputFloat("##GDriftX", &profile->GyroData[DRIFT_X], 1.0f, 0.0f, "%.1f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::Text("Drift Y");
|
|
#ifdef __WIIU__
|
|
ImGui::PushItemWidth(80 * 2);
|
|
#else
|
|
ImGui::PushItemWidth(80);
|
|
#endif
|
|
ImGui::InputFloat("##GDriftY", &profile->GyroData[DRIFT_Y], 1.0f, 0.0f, "%.1f");
|
|
ImGui::PopItemWidth();
|
|
ImGui::EndChild();
|
|
#ifdef __SWITCH__
|
|
SohImGui::EndGroupPanel(46.0f);
|
|
#else
|
|
SohImGui::EndGroupPanel(14.0f);
|
|
#endif
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
const ImVec2 cursor = ImGui::GetCursorPos();
|
|
|
|
SohImGui::BeginGroupPanel("C-Buttons", ImVec2(158, 20));
|
|
DrawButton("Up", BTN_CUP);
|
|
DrawButton("Down", BTN_CDOWN);
|
|
DrawButton("Left", BTN_CLEFT);
|
|
DrawButton("Right", BTN_CRIGHT);
|
|
ImGui::Dummy(ImVec2(0, 5));
|
|
SohImGui::EndGroupPanel();
|
|
|
|
ImGui::SetCursorPosX(cursor.x);
|
|
#ifdef __SWITCH__
|
|
ImGui::SetCursorPosY(cursor.y + 167);
|
|
#elif defined(__WIIU__)
|
|
ImGui::SetCursorPosY(cursor.y + 120 * 2);
|
|
#else
|
|
ImGui::SetCursorPosY(cursor.y + 120);
|
|
#endif
|
|
SohImGui::BeginGroupPanel("Options", ImVec2(158, 20));
|
|
float cursorX = ImGui::GetCursorPosX() + 5;
|
|
ImGui::SetCursorPosX(cursorX);
|
|
ImGui::Checkbox("Rumble Enabled", &profile->UseRumble);
|
|
if (Backend->CanRumble()) {
|
|
ImGui::SetCursorPosX(cursorX);
|
|
ImGui::Text("Rumble Force: %d%%", static_cast<int>(100.0f * profile->RumbleStrength));
|
|
ImGui::SetCursorPosX(cursorX);
|
|
#ifdef __WIIU__
|
|
ImGui::PushItemWidth(135.0f * 2);
|
|
#else
|
|
ImGui::PushItemWidth(135.0f);
|
|
#endif
|
|
ImGui::SliderFloat("##RStrength", &profile->RumbleStrength, 0.0f, 1.0f, "");
|
|
ImGui::PopItemWidth();
|
|
}
|
|
ImGui::Dummy(ImVec2(0, 5));
|
|
SohImGui::EndGroupPanel(IsKeyboard ? 0.0f : 2.0f);
|
|
}
|
|
|
|
void InputEditor::DrawHud() {
|
|
if (!this->Opened) {
|
|
BtnReading = -1;
|
|
CVar_SetS32("gControllerConfigurationEnabled", 0);
|
|
return;
|
|
}
|
|
|
|
#ifdef __SWITCH__
|
|
ImVec2 minSize = ImVec2(641, 250);
|
|
ImVec2 maxSize = ImVec2(2200, 505);
|
|
#elif defined(__WIIU__)
|
|
ImVec2 minSize = ImVec2(641 * 2, 250 * 2);
|
|
ImVec2 maxSize = ImVec2(1200 * 2, 290 * 2);
|
|
#else
|
|
ImVec2 minSize = ImVec2(641, 250);
|
|
ImVec2 maxSize = ImVec2(1200, 290);
|
|
#endif
|
|
|
|
ImGui::SetNextWindowSizeConstraints(minSize, maxSize);
|
|
//OTRTODO: Disable this stupid workaround ( ReadRawPress() only works when the window is on the main viewport )
|
|
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
|
|
ImGui::Begin("Controller Configuration", &this->Opened, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);
|
|
|
|
ImGui::BeginTabBar("##Controllers");
|
|
|
|
for (int i = 0; i < 4; i++) {
|
|
if (ImGui::BeginTabItem(StringHelper::Sprintf("Port %d", i + 1).c_str())) {
|
|
CurrentPort = i;
|
|
ImGui::EndTabItem();
|
|
}
|
|
}
|
|
|
|
ImGui::EndTabBar();
|
|
|
|
// Draw current cfg
|
|
|
|
DrawControllerSchema();
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
bool InputEditor::IsOpened() {
|
|
return Opened;
|
|
}
|
|
|
|
void InputEditor::Open() {
|
|
Opened = true;
|
|
}
|
|
|
|
void InputEditor::Close() {
|
|
Opened = false;
|
|
}
|
|
}
|