Shipwright/soh/soh/Enhancements/controls/GameControlEditor.cpp

232 lines
9.3 KiB
C++

#include "GameControlEditor.h"
#include <string>
#include <list>
#include <unordered_map>
#include <utility>
#include <iterator>
#include "Lib/ImGui/imgui.h"
#include "Lib/ImGui/imgui_internal.h"
#include "Cvar.h"
#include "UltraController.h"
#include "Utils/StringHelper.h"
#include "../libultraship/ImGuiImpl.h"
namespace GameControlEditor {
const ImGuiTableFlags PANEL_TABLE_FLAGS =
ImGuiTableFlags_BordersH |
ImGuiTableFlags_BordersV;
const ImGuiTableColumnFlags PANEL_TABLE_COLUMN_FLAGS =
ImGuiTableColumnFlags_IndentEnable |
ImGuiTableColumnFlags_NoSort;
namespace TableHelper {
void InitHeader(bool has_header = true) {
if (has_header) {
ImGui::TableHeadersRow();
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding(); //This is to adjust Vertical pos of item in a cell to be normlized.
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextCol() {
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
void NextLine() {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
}
}
void DrawHelpIcon(const std::string& helptext, bool sameline = true, int Pos = 0) {
// place the ? button to the most of the right side of the cell it is using.
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetContentRegionAvail().x - 15);
ImGui::SmallButton("?");
SohImGui::Tooltip(helptext.c_str());
if (sameline) {
//I do not use ImGui::SameLine(); because it make some element vanish.
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 22);
}
}
typedef uint32_t N64ButtonMask;
// Used together for an incomplete linked hash map implementation in order to
// map button masks to their names and original mapping on N64
static std::list<std::pair<N64ButtonMask, const char*>> buttons;
static std::unordered_map<N64ButtonMask, decltype(buttons)::iterator> buttonNames;
void addButtonName(N64ButtonMask mask, const char* name) {
buttons.push_back(std::make_pair(mask, name));
buttonNames[mask] = std::prev(buttons.end());
}
typedef struct {
const char* label;
const char* cVarName;
N64ButtonMask defaultBtn;
} CustomButtonMap;
// Ocarina button maps
static CustomButtonMap ocarinaD5 = {"D5", "gOcarinaD5BtnMap", BTN_CUP};
static CustomButtonMap ocarinaB4 = {"B4", "gOcarinaB4BtnMap", BTN_CLEFT};
static CustomButtonMap ocarinaA4 = {"A4", "gOcarinaA4BtnMap", BTN_CRIGHT};
static CustomButtonMap ocarinaF4 = {"F4", "gOcarinaF4BtnMap", BTN_CDOWN};
static CustomButtonMap ocarinaD4 = {"D4", "gOcarinaD4BtnMap", BTN_A};
static CustomButtonMap ocarinaSongDisable = {"Disable songs", "gOcarinaDisableBtnMap", BTN_L};
static CustomButtonMap ocarinaSharp = {"Pitch up", "gOcarinaSharpBtnMap", BTN_R};
static CustomButtonMap ocarinaFlat = {"Pitch down", "gOcarinaFlatBtnMap", BTN_Z};
void DrawUI(bool&);
void Init() {
SohImGui::AddWindow("Enhancements", "Game Control Editor", DrawUI);
addButtonName(BTN_A, "A");
addButtonName(BTN_B, "B");
addButtonName(BTN_CUP, "C Up");
addButtonName(BTN_CDOWN, "C Down");
addButtonName(BTN_CLEFT, "C Left");
addButtonName(BTN_CRIGHT, "C Right");
addButtonName(BTN_L, "L");
addButtonName(BTN_Z, "Z");
addButtonName(BTN_R, "R");
addButtonName(BTN_START, "Start");
addButtonName(BTN_DUP, "D-pad up");
addButtonName(BTN_DDOWN, "D-pad down");
addButtonName(BTN_DLEFT, "D-pad left");
addButtonName(BTN_DRIGHT, "D-pad right");
addButtonName(0, "None");
}
// Draw a button mapping setting consisting of a padded label and button dropdown.
// excludedButtons indicates which buttons are unavailable to choose from.
void DrawMapping(CustomButtonMap& mapping, float labelWidth, N64ButtonMask excludedButtons) {
N64ButtonMask currentButton = CVar_GetS32(mapping.cVarName, mapping.defaultBtn);
const char* preview;
if (buttonNames.contains(currentButton)) {
preview = buttonNames[currentButton]->second;
} else {
preview = "Unknown";
}
SohImGui::InsertPadding();
ImVec2 cursorPos = ImGui::GetCursorPos();
ImVec2 textSize = ImGui::CalcTextSize(mapping.label);
ImGui::SetCursorPosY(cursorPos.y + textSize.y / 4);
ImGui::SetCursorPosX(cursorPos.x + abs(textSize.x - labelWidth));
ImGui::Text("%s", mapping.label);
ImGui::SameLine();
ImGui::SetCursorPosY(cursorPos.y);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
if (ImGui::BeginCombo(StringHelper::Sprintf("##%s", mapping.cVarName).c_str(), preview)) {
for (auto i = buttons.begin(); i != buttons.end(); i++) {
if ((i->first & excludedButtons) != 0) {
continue;
}
if (ImGui::Selectable(i->second, i->first == currentButton)) {
CVar_SetS32(mapping.cVarName, i->first);
}
}
ImGui::EndCombo();
}
SohImGui::InsertPadding();
}
void DrawOcarinaControlPanel() {
if (!ImGui::CollapsingHeader("Ocarina Controls")) {
return;
}
if (!ImGui::BeginTable("tableCustomOcarinaControls", 1, PANEL_TABLE_FLAGS)) {
return;
}
ImGui::TableSetupColumn("Custom Ocarina Controls", PANEL_TABLE_COLUMN_FLAGS | ImGuiTableColumnFlags_WidthStretch);
TableHelper::InitHeader(false);
ImVec2 cursor = ImGui::GetCursorPos();
ImGui::SetCursorPos(ImVec2(cursor.x + 5, cursor.y + 5));
SohImGui::EnhancementCheckbox("Customize Ocarina Controls", "gCustomOcarinaControls");
if (CVar_GetS32("gCustomOcarinaControls", 0) == 1) {
if (ImGui::BeginTable("tableCustomMainOcarinaControls", 2, ImGuiTableFlags_SizingStretchProp)) {
float labelWidth;
N64ButtonMask disableMask = BTN_B;
if (CVar_GetS32("gDpadOcarina", 0)) {
disableMask |= BTN_DUP | BTN_DDOWN | BTN_DLEFT | BTN_DRIGHT;
}
ImGui::TableSetupColumn("Notes##CustomOcarinaNotes", PANEL_TABLE_COLUMN_FLAGS);
ImGui::TableSetupColumn("Modifiers##CustomOcaranaModifiers", PANEL_TABLE_COLUMN_FLAGS);
TableHelper::InitHeader(false);
SohImGui::BeginGroupPanel("Notes", ImGui::GetContentRegionAvail());
labelWidth = ImGui::CalcTextSize("D5").x + 10;
DrawMapping(ocarinaD5, labelWidth, disableMask);
DrawMapping(ocarinaB4, labelWidth, disableMask);
DrawMapping(ocarinaA4, labelWidth, disableMask);
DrawMapping(ocarinaF4, labelWidth, disableMask);
DrawMapping(ocarinaD4, labelWidth, disableMask);
ImGui::Dummy(ImVec2(0, 5));
float cursorY = ImGui::GetCursorPosY();
SohImGui::EndGroupPanel();
TableHelper::NextCol();
SohImGui::BeginGroupPanel("Modifiers", ImGui::GetContentRegionAvail());
labelWidth = ImGui::CalcTextSize(ocarinaSongDisable.label).x + 10;
DrawMapping(ocarinaSongDisable, labelWidth, disableMask);
DrawMapping(ocarinaSharp, labelWidth, disableMask);
DrawMapping(ocarinaFlat, labelWidth, disableMask);
SohImGui::EndGroupPanel(cursorY - ImGui::GetCursorPosY() + 2);
ImGui::EndTable();
}
} else {
SohImGui::InsertPadding();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
ImGui::TextWrapped("To modify the main ocarina controls, select the \"Customize Ocarina Controls\" checkbox.");
SohImGui::InsertPadding();
}
SohImGui::BeginGroupPanel("Alternate controls", ImGui::GetContentRegionAvail());
if (ImGui::BeginTable("tableOcarinaAlternateControls", 2, ImGuiTableFlags_SizingFixedSame)) {
ImGui::TableSetupColumn("D-pad", PANEL_TABLE_COLUMN_FLAGS);
ImGui::TableSetupColumn("Right stick", PANEL_TABLE_COLUMN_FLAGS);
TableHelper::InitHeader(false);
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 5);
SohImGui::EnhancementCheckbox("Play with D-pad", "gDpadOcarina");
TableHelper::NextCol();
SohImGui::EnhancementCheckbox("Play with camera stick", "gRStickOcarina");
ImGui::EndTable();
}
SohImGui::EndGroupPanel();
ImGui::EndTable();
}
void DrawUI(bool& open) {
if (!open) {
CVar_SetS32("gGameControlEditorEnabled", false);
return;
}
ImGui::SetNextWindowSize(ImVec2(465, 430), ImGuiCond_FirstUseEver);
if (ImGui::Begin("Game Controls Configuration", &open)) {
DrawOcarinaControlPanel();
}
ImGui::End();
}
}