mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
overlay: combine buttons/analogs/overlay/lights (#752)
Same idea as #747 except for input/output binding.
This commit is contained in:
@@ -58,6 +58,7 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
// same width as dummy marker
|
// same width as dummy marker
|
||||||
const float INDENT = 22.f;
|
const float INDENT = 22.f;
|
||||||
|
const float ROW_INDENT = overlay::apply_scaling(8);
|
||||||
const auto PROJECT_URL = "https://spice2x.github.io";
|
const auto PROJECT_URL = "https://spice2x.github.io";
|
||||||
|
|
||||||
constexpr ImVec4 TEXT_COLOR_GREEN(0.f, 1.f, 0.f, 1.f);
|
constexpr ImVec4 TEXT_COLOR_GREEN(0.f, 1.f, 0.f, 1.f);
|
||||||
@@ -79,6 +80,16 @@ namespace overlay::windows {
|
|||||||
static const char *OPTIONS_TAB_SEARCH = "Search";
|
static const char *OPTIONS_TAB_SEARCH = "Search";
|
||||||
static const char *OPTIONS_TAB_QUICK = "Quick Settings";
|
static const char *OPTIONS_TAB_QUICK = "Quick Settings";
|
||||||
|
|
||||||
|
// sub-pages shown in the Controller tab left navigation, in display order
|
||||||
|
static const std::vector<std::pair<const char *, ControllerPage>> CONTROLLER_PAGE_GROUPS = {
|
||||||
|
{ "Buttons", ControllerPage::CONTROLLER_PAGE_BUTTONS },
|
||||||
|
{ "Keypads", ControllerPage::CONTROLLER_PAGE_KEYPADS },
|
||||||
|
{ "Analogs", ControllerPage::CONTROLLER_PAGE_ANALOGS },
|
||||||
|
{ "Overlay", ControllerPage::CONTROLLER_PAGE_OVERLAY },
|
||||||
|
{ "Lights", ControllerPage::CONTROLLER_PAGE_LIGHTS },
|
||||||
|
{ "Presets", ControllerPage::CONTROLLER_PAGE_PRESETS },
|
||||||
|
};
|
||||||
|
|
||||||
std::optional<std::vector<hooks::audio::AsioDriverScanEntry>> asio_driver_list;
|
std::optional<std::vector<hooks::audio::AsioDriverScanEntry>> asio_driver_list;
|
||||||
|
|
||||||
Config::Config(overlay::SpiceOverlay *overlay) : Window(overlay) {
|
Config::Config(overlay::SpiceOverlay *overlay) : Window(overlay) {
|
||||||
@@ -238,6 +249,41 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Renders an arrow-less, non-collapsible left-nav header row, highlighted when
|
||||||
|
// active. Returns true if the row was clicked this frame; callers apply their
|
||||||
|
// own selection side effects.
|
||||||
|
bool Config::build_nav_header(const char *label, bool active) {
|
||||||
|
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf;
|
||||||
|
if (active) {
|
||||||
|
flags |= ImGuiTreeNodeFlags_Selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
// give the active header a clear, distinct highlight
|
||||||
|
int colors_pushed = 0;
|
||||||
|
if (active) {
|
||||||
|
const ImVec4 accent = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Header, accent);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, accent);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
|
||||||
|
colors_pushed = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// taller frame padding so headers match the height of the category rows below
|
||||||
|
const ImVec2 frame_padding = ImGui::GetStyle().FramePadding;
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
||||||
|
ImVec2(frame_padding.x, frame_padding.y + overlay::apply_scaling(4)));
|
||||||
|
|
||||||
|
ImGui::CollapsingHeader(label, flags);
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
if (colors_pushed) {
|
||||||
|
ImGui::PopStyleColor(colors_pushed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImGui::IsItemClicked();
|
||||||
|
}
|
||||||
|
|
||||||
void Config::build_options_tab(float page_offset) {
|
void Config::build_options_tab(float page_offset) {
|
||||||
const float content_height = ImGui::GetWindowContentRegionMax().y - page_offset;
|
const float content_height = ImGui::GetWindowContentRegionMax().y - page_offset;
|
||||||
const float nav_width = overlay::apply_scaling(130);
|
const float nav_width = overlay::apply_scaling(130);
|
||||||
@@ -297,36 +343,7 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
// arrow-less, non-collapsible nav header; selecting it clears any highlighted category
|
// arrow-less, non-collapsible nav header; selecting it clears any highlighted category
|
||||||
auto nav_header = [this](const char *label) {
|
auto nav_header = [this](const char *label) {
|
||||||
const bool active = this->options_group_selected == label;
|
if (this->build_nav_header(label, this->options_group_selected == label)) {
|
||||||
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf;
|
|
||||||
if (active) {
|
|
||||||
flags |= ImGuiTreeNodeFlags_Selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
// give the active header a clear, distinct highlight
|
|
||||||
int colors_pushed = 0;
|
|
||||||
if (active) {
|
|
||||||
const ImVec4 accent = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Header, accent);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, accent);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text));
|
|
||||||
colors_pushed = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// taller frame padding so headers match the height of the category rows below
|
|
||||||
const ImVec2 frame_padding = ImGui::GetStyle().FramePadding;
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding,
|
|
||||||
ImVec2(frame_padding.x, frame_padding.y + overlay::apply_scaling(4)));
|
|
||||||
|
|
||||||
ImGui::CollapsingHeader(label, flags);
|
|
||||||
|
|
||||||
ImGui::PopStyleVar();
|
|
||||||
|
|
||||||
if (colors_pushed) {
|
|
||||||
ImGui::PopStyleColor(colors_pushed);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::IsItemClicked()) {
|
|
||||||
this->options_group_selected = label;
|
this->options_group_selected = label;
|
||||||
this->options_category_selected.clear();
|
this->options_category_selected.clear();
|
||||||
this->options_scroll_top = true;
|
this->options_scroll_top = true;
|
||||||
@@ -493,6 +510,146 @@ namespace overlay::windows {
|
|||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Config::build_controller_tab(float page_offset, ControllerPage *page_selected_new) {
|
||||||
|
const float content_height = ImGui::GetWindowContentRegionMax().y - page_offset;
|
||||||
|
const float nav_width = overlay::apply_scaling(100);
|
||||||
|
|
||||||
|
// hide sub-pages that expose no controls for the selected game
|
||||||
|
auto analogs = games::get_analogs(this->games_selected_name);
|
||||||
|
const bool has_analogs = analogs && !analogs->empty();
|
||||||
|
auto lights = games::get_lights(this->games_selected_name);
|
||||||
|
const bool has_lights = lights && !lights->empty();
|
||||||
|
auto page_hidden = [has_analogs, has_lights](ControllerPage page) {
|
||||||
|
switch (page) {
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_ANALOGS:
|
||||||
|
return !has_analogs;
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_LIGHTS:
|
||||||
|
return !has_lights;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// default to the first page on first display
|
||||||
|
if (this->controller_page_label.empty()) {
|
||||||
|
this->controller_page_label = CONTROLLER_PAGE_GROUPS.front().first;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the selected page is no longer available, fall back to the first one
|
||||||
|
for (const auto &group : CONTROLLER_PAGE_GROUPS) {
|
||||||
|
if (this->controller_page_label == group.first && page_hidden(group.second)) {
|
||||||
|
this->controller_page_label = CONTROLLER_PAGE_GROUPS.front().first;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// left navigation: one header per sub-page; clicking a header selects that page
|
||||||
|
ImGui::BeginChild("ControllerNav", ImVec2(nav_width, content_height), false);
|
||||||
|
|
||||||
|
// extra vertical padding between nav rows
|
||||||
|
const ImVec2 nav_item_spacing = ImGui::GetStyle().ItemSpacing;
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,
|
||||||
|
ImVec2(nav_item_spacing.x, nav_item_spacing.y + overlay::apply_scaling(2)));
|
||||||
|
|
||||||
|
// arrow-less, non-collapsible nav header; selecting it switches the content pane
|
||||||
|
auto nav_header = [this](const char *label) {
|
||||||
|
if (this->build_nav_header(label, this->controller_page_label == label)) {
|
||||||
|
this->controller_page_label = label;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto &group : CONTROLLER_PAGE_GROUPS) {
|
||||||
|
if (page_hidden(group.second)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
nav_header(group.first);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
|
||||||
|
ImGui::EndChild(); // ControllerNav
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
// content: only the selected sub-page
|
||||||
|
ImGui::BeginChild("ControllerContent", ImVec2(0, content_height), false);
|
||||||
|
|
||||||
|
// breathing room at the top of the content area
|
||||||
|
ImGui::Dummy(ImVec2(0.0f, overlay::apply_scaling(4)));
|
||||||
|
|
||||||
|
for (const auto &group : CONTROLLER_PAGE_GROUPS) {
|
||||||
|
if (this->controller_page_label != group.first || page_hidden(group.second)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reflect the active sub-page so per-page side effects still fire
|
||||||
|
*page_selected_new = group.second;
|
||||||
|
|
||||||
|
switch (group.second) {
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_BUTTONS: {
|
||||||
|
|
||||||
|
// help text for binding buttons, if the game has one
|
||||||
|
const auto help_text = games::get_buttons_help(this->games_selected_name);
|
||||||
|
if (!help_text.empty()) {
|
||||||
|
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Button Bindings");
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::TextWrapped("%s", help_text.c_str());
|
||||||
|
ImGui::TextUnformatted("");
|
||||||
|
}
|
||||||
|
|
||||||
|
// game buttons
|
||||||
|
this->build_buttons("Game", games::get_buttons(this->games_selected_name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_KEYPADS: {
|
||||||
|
|
||||||
|
// keypad buttons
|
||||||
|
this->build_keypad_warning();
|
||||||
|
|
||||||
|
auto keypad_buttons = games::get_buttons_keypads(this->games_selected_name);
|
||||||
|
auto keypad_count = eamuse_get_game_keypads_name();
|
||||||
|
if (keypad_count == 1) {
|
||||||
|
this->build_buttons("Keypad", keypad_buttons,
|
||||||
|
0, games::KeypadButtons::Size - 1);
|
||||||
|
} else if (keypad_count >= 2) {
|
||||||
|
this->build_buttons("Keypad", keypad_buttons);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_ANALOGS: {
|
||||||
|
|
||||||
|
// help text for binding analog, if the game has one
|
||||||
|
const auto help_text = games::get_analogs_help(this->games_selected_name);
|
||||||
|
if (!help_text.empty()) {
|
||||||
|
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Analog Bindings");
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::TextWrapped("%s", help_text.c_str());
|
||||||
|
ImGui::TextUnformatted("");
|
||||||
|
}
|
||||||
|
this->build_analogs("Game", analogs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_OVERLAY: {
|
||||||
|
|
||||||
|
// overlay buttons
|
||||||
|
this->build_buttons("Overlay", games::get_buttons_overlay(this->games_selected_name));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_LIGHTS: {
|
||||||
|
this->build_lights("Game", lights);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ControllerPage::CONTROLLER_PAGE_PRESETS: {
|
||||||
|
this->build_presets();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndChild(); // ControllerContent
|
||||||
|
}
|
||||||
|
|
||||||
void Config::build_content() {
|
void Config::build_content() {
|
||||||
|
|
||||||
// if standalone then fullscreen window
|
// if standalone then fullscreen window
|
||||||
@@ -536,87 +693,15 @@ namespace overlay::windows {
|
|||||||
previous_games_selected, this->games_selected);
|
previous_games_selected, this->games_selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// tab selection
|
// tab + controller sub-page selection
|
||||||
auto tab_selected_new = ConfigTab::CONFIG_TAB_INVALID;
|
auto tab_selected_new = ConfigTab::CONFIG_TAB_INVALID;
|
||||||
|
auto controller_page_new = ControllerPage::CONTROLLER_PAGE_INVALID;
|
||||||
if (ImGui::BeginTabBar("Config Tabs", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
|
if (ImGui::BeginTabBar("Config Tabs", ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)) {
|
||||||
const int page_offset2 = overlay::apply_scaling(cfg::CONFIGURATOR_STANDALONE ? 65 : 87);
|
const int page_offset2 = overlay::apply_scaling(cfg::CONFIGURATOR_STANDALONE ? 65 : 87);
|
||||||
|
|
||||||
if (ImGui::BeginTabItem("Buttons")) {
|
if (ImGui::BeginTabItem("Controller")) {
|
||||||
tab_selected_new = ConfigTab::CONFIG_TAB_BUTTONS;
|
tab_selected_new = ConfigTab::CONFIG_TAB_CONTROLLER;
|
||||||
ImGui::BeginChild("Buttons", ImVec2(
|
this->build_controller_tab(page_offset2, &controller_page_new);
|
||||||
0, ImGui::GetWindowContentRegionMax().y - page_offset2), false);
|
|
||||||
|
|
||||||
// help text for binding buttons, if the game has one
|
|
||||||
const auto help_text = games::get_buttons_help(this->games_selected_name);
|
|
||||||
if (!help_text.empty()) {
|
|
||||||
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Button Bindings");
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::TextWrapped("%s", help_text.c_str());
|
|
||||||
ImGui::TextUnformatted("");
|
|
||||||
}
|
|
||||||
|
|
||||||
// game buttons
|
|
||||||
this->build_buttons("Game", games::get_buttons(this->games_selected_name));
|
|
||||||
|
|
||||||
// keypad buttons
|
|
||||||
ImGui::TextUnformatted("");
|
|
||||||
this->build_keypad_warning();
|
|
||||||
|
|
||||||
auto keypad_buttons = games::get_buttons_keypads(this->games_selected_name);
|
|
||||||
auto keypad_count = eamuse_get_game_keypads_name();
|
|
||||||
if (keypad_count == 1) {
|
|
||||||
this->build_buttons("Keypad", keypad_buttons,
|
|
||||||
0, games::KeypadButtons::Size - 1);
|
|
||||||
} else if (keypad_count >= 2) {
|
|
||||||
this->build_buttons("Keypad", keypad_buttons);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndChild();
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
|
||||||
if (ImGui::BeginTabItem("Analogs")) {
|
|
||||||
tab_selected_new = ConfigTab::CONFIG_TAB_ANALOGS;
|
|
||||||
|
|
||||||
ImGui::BeginChild("Analogs", ImVec2(
|
|
||||||
0, ImGui::GetWindowContentRegionMax().y - page_offset2), false);
|
|
||||||
|
|
||||||
// help text for binding analog, if the game has one
|
|
||||||
const auto help_text = games::get_analogs_help(this->games_selected_name);
|
|
||||||
if (!help_text.empty()) {
|
|
||||||
ImGui::TextColored(ImVec4(1.f, 0.7f, 0, 1), "Analog Bindings");
|
|
||||||
ImGui::Spacing();
|
|
||||||
ImGui::TextWrapped("%s", help_text.c_str());
|
|
||||||
ImGui::TextUnformatted("");
|
|
||||||
}
|
|
||||||
this->build_analogs("Game", games::get_analogs(this->games_selected_name));
|
|
||||||
ImGui::EndChild();
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
|
||||||
if (ImGui::BeginTabItem("Overlay")) {
|
|
||||||
tab_selected_new = ConfigTab::CONFIG_TAB_OVERLAY;
|
|
||||||
ImGui::BeginChild("Overlay", ImVec2(
|
|
||||||
0, ImGui::GetWindowContentRegionMax().y - page_offset2), false);
|
|
||||||
|
|
||||||
// overlay buttons
|
|
||||||
this->build_buttons("Overlay", games::get_buttons_overlay(this->games_selected_name));
|
|
||||||
ImGui::EndChild();
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
|
||||||
if (ImGui::BeginTabItem("Lights")) {
|
|
||||||
tab_selected_new = ConfigTab::CONFIG_TAB_LIGHTS;
|
|
||||||
|
|
||||||
ImGui::BeginChild("Lights", ImVec2(
|
|
||||||
0, ImGui::GetWindowContentRegionMax().y - page_offset2), false);
|
|
||||||
this->build_lights("Game", games::get_lights(this->games_selected_name));
|
|
||||||
ImGui::EndChild();
|
|
||||||
ImGui::EndTabItem();
|
|
||||||
}
|
|
||||||
if (ImGui::BeginTabItem("Presets")) {
|
|
||||||
tab_selected_new = ConfigTab::CONFIG_TAB_PRESETS;
|
|
||||||
ImGui::BeginChild("Presets", ImVec2(
|
|
||||||
0, ImGui::GetWindowContentRegionMax().y - page_offset2), false);
|
|
||||||
this->build_presets();
|
|
||||||
ImGui::EndChild();
|
|
||||||
ImGui::EndTabItem();
|
ImGui::EndTabItem();
|
||||||
}
|
}
|
||||||
if (ImGui::BeginTabItem("Cards")) {
|
if (ImGui::BeginTabItem("Cards")) {
|
||||||
@@ -677,17 +762,21 @@ namespace overlay::windows {
|
|||||||
ImGui::EndTabBar();
|
ImGui::EndTabBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
// did tab selection change?
|
// did tab or controller sub-page selection change?
|
||||||
if (this->tab_selected != tab_selected_new) {
|
if (this->tab_selected != tab_selected_new ||
|
||||||
|
this->controller_page_selected != controller_page_new) {
|
||||||
log_misc(
|
log_misc(
|
||||||
"config",
|
"config",
|
||||||
"tab selection changed from {} to {}",
|
"selection changed from tab {} page {} to tab {} page {}",
|
||||||
static_cast<uint32_t>(this->tab_selected),
|
static_cast<uint32_t>(this->tab_selected),
|
||||||
static_cast<uint32_t>(tab_selected_new));
|
static_cast<uint32_t>(this->controller_page_selected),
|
||||||
|
static_cast<uint32_t>(tab_selected_new),
|
||||||
|
static_cast<uint32_t>(controller_page_new));
|
||||||
|
|
||||||
stop_lights_test();
|
stop_lights_test();
|
||||||
|
|
||||||
this->tab_selected = tab_selected_new;
|
this->tab_selected = tab_selected_new;
|
||||||
|
this->controller_page_selected = controller_page_new;
|
||||||
buttons_many_active = false;
|
buttons_many_active = false;
|
||||||
buttons_many_index = -1;
|
buttons_many_index = -1;
|
||||||
|
|
||||||
@@ -728,7 +817,7 @@ namespace overlay::windows {
|
|||||||
"WARNING: PikaPika Pop-Kun model will ignore keypad number input!");
|
"WARNING: PikaPika Pop-Kun model will ignore keypad number input!");
|
||||||
}
|
}
|
||||||
ImGui::TextWrapped(
|
ImGui::TextWrapped(
|
||||||
"Use Toggle Sub Screen button (Overlay tab) to show the overlay and use your mouse, "
|
"Use Toggle Sub Screen button (Controller -> Overlay) to show the overlay and use your mouse, "
|
||||||
"connect using SpiceCompanion app, or connect a touch screen to enter "
|
"connect using SpiceCompanion app, or connect a touch screen to enter "
|
||||||
"the PIN.");
|
"the PIN.");
|
||||||
ImGui::Unindent(INDENT);
|
ImGui::Unindent(INDENT);
|
||||||
@@ -803,8 +892,8 @@ namespace overlay::windows {
|
|||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
if (ImGui::BeginTable("ButtonsTable", 3, ImGuiTableFlags_Resizable)) {
|
if (ImGui::BeginTable("ButtonsTable", 3, ImGuiTableFlags_Resizable)) {
|
||||||
// longest column is probably "Toggle Virtual Keypad P1" in Overlay tab
|
// longest column is probably "Toggle Virtual Keypad P1" in the Overlay page
|
||||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(220));
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(200));
|
||||||
ImGui::TableSetupColumn("Binding", ImGuiTableColumnFlags_WidthStretch);
|
ImGui::TableSetupColumn("Binding", ImGuiTableColumnFlags_WidthStretch);
|
||||||
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(170));
|
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(170));
|
||||||
|
|
||||||
@@ -812,9 +901,9 @@ namespace overlay::windows {
|
|||||||
if (!buttons || buttons->empty()) {
|
if (!buttons || buttons->empty()) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::Indent(INDENT);
|
ImGui::Indent(ROW_INDENT);
|
||||||
ImGui::TextDisabled("-");
|
ImGui::TextDisabled("-");
|
||||||
ImGui::Unindent(INDENT);
|
ImGui::Unindent(ROW_INDENT);
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextDisabled("-");
|
ImGui::TextDisabled("-");
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
@@ -882,7 +971,7 @@ namespace overlay::windows {
|
|||||||
const bool primary_button_state = GameAPI::Buttons::getState(RI_MGR, primary_button);
|
const bool primary_button_state = GameAPI::Buttons::getState(RI_MGR, primary_button);
|
||||||
const bool button_state = GameAPI::Buttons::getState(RI_MGR, *button, false);
|
const bool button_state = GameAPI::Buttons::getState(RI_MGR, *button, false);
|
||||||
|
|
||||||
ImGui::Indent(INDENT);
|
ImGui::Indent(ROW_INDENT);
|
||||||
if (alt_index == 0) {
|
if (alt_index == 0) {
|
||||||
// primary button
|
// primary button
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
@@ -909,7 +998,7 @@ namespace overlay::windows {
|
|||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::Unindent(INDENT);
|
ImGui::Unindent(ROW_INDENT);
|
||||||
|
|
||||||
// column for key binding display
|
// column for key binding display
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
@@ -1013,8 +1102,8 @@ namespace overlay::windows {
|
|||||||
"You just bound an analog axis to a digital button.\n"
|
"You just bound an analog axis to a digital button.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"If your controller supports analog input (turntable,\n"
|
"If your controller supports analog input (turntable,\n"
|
||||||
"knob, slider) you should instead use the Analog tab and\n"
|
"knob, slider) you should instead use the Analogs page\n"
|
||||||
"bind as an analog axis.");
|
"and bind as an analog axis.");
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
@@ -1678,7 +1767,7 @@ namespace overlay::windows {
|
|||||||
ImGui::TextUnformatted("Press any button for:");
|
ImGui::TextUnformatted("Press any button for:");
|
||||||
ImGui::Text(" %s", button->getName().c_str());
|
ImGui::Text(" %s", button->getName().c_str());
|
||||||
ImGui::TextUnformatted("");
|
ImGui::TextUnformatted("");
|
||||||
const bool escape_cancels_bind = (this->tab_selected != ConfigTab::CONFIG_TAB_OVERLAY);
|
const bool escape_cancels_bind = (this->controller_page_selected != ControllerPage::CONTROLLER_PAGE_OVERLAY);
|
||||||
if (escape_cancels_bind) {
|
if (escape_cancels_bind) {
|
||||||
ImGui::TextColored(ImVec4(1, 0.7f, 0, 1), "Press ESC to cancel!");
|
ImGui::TextColored(ImVec4(1, 0.7f, 0, 1), "Press ESC to cancel!");
|
||||||
ImGui::TextUnformatted("");
|
ImGui::TextUnformatted("");
|
||||||
@@ -4857,8 +4946,7 @@ namespace overlay::windows {
|
|||||||
// option name
|
// option name
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0);
|
ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0);
|
||||||
const float row_indent = overlay::apply_scaling(8);
|
ImGui::Indent(ROW_INDENT);
|
||||||
ImGui::Indent(row_indent);
|
|
||||||
|
|
||||||
if (option.is_active()) {
|
if (option.is_active()) {
|
||||||
// active option
|
// active option
|
||||||
@@ -4900,7 +4988,7 @@ namespace overlay::windows {
|
|||||||
clipboard::copy_text(param.c_str());
|
clipboard::copy_text(param.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::Unindent(row_indent);
|
ImGui::Unindent(ROW_INDENT);
|
||||||
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
|
ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
|
||||||
|
|
||||||
// option widgets
|
// option widgets
|
||||||
@@ -5620,9 +5708,9 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_None, 3.f);
|
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_None, 3.f);
|
||||||
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_None, 1.f);
|
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_None, 1.f);
|
||||||
ImGui::TableSetupColumn("Buttons", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(60.f));
|
ImGui::TableSetupColumn("Buttons", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(50.f));
|
||||||
ImGui::TableSetupColumn("Analogs", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(60.f));
|
ImGui::TableSetupColumn("Analogs", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(50.f));
|
||||||
ImGui::TableSetupColumn("Lights", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(60.f));
|
ImGui::TableSetupColumn("Lights", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(50.f));
|
||||||
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(140.f));
|
ImGui::TableSetupColumn("Actions", ImGuiTableColumnFlags_WidthFixed, overlay::apply_scaling(140.f));
|
||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
@@ -5633,7 +5721,8 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
// name
|
// name
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextUnformatted(t.name.c_str());
|
ImGui::TextTruncated(
|
||||||
|
t.name, ImGui::GetContentRegionAvail().x - overlay::apply_scaling(20));
|
||||||
|
|
||||||
// type
|
// type
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|||||||
@@ -12,16 +12,24 @@
|
|||||||
|
|
||||||
namespace overlay::windows {
|
namespace overlay::windows {
|
||||||
|
|
||||||
|
// top-level tabs in the configuration window
|
||||||
enum class ConfigTab {
|
enum class ConfigTab {
|
||||||
CONFIG_TAB_INVALID,
|
CONFIG_TAB_INVALID,
|
||||||
CONFIG_TAB_BUTTONS,
|
CONFIG_TAB_CONTROLLER,
|
||||||
CONFIG_TAB_ANALOGS,
|
|
||||||
CONFIG_TAB_OVERLAY,
|
|
||||||
CONFIG_TAB_LIGHTS,
|
|
||||||
CONFIG_TAB_CARDS,
|
CONFIG_TAB_CARDS,
|
||||||
CONFIG_TAB_PATCHES,
|
CONFIG_TAB_PATCHES,
|
||||||
CONFIG_TAB_OPTIONS,
|
CONFIG_TAB_OPTIONS,
|
||||||
CONFIG_TAB_PRESETS,
|
};
|
||||||
|
|
||||||
|
// sub-pages shown in the Controller tab's left navigation
|
||||||
|
enum class ControllerPage {
|
||||||
|
CONTROLLER_PAGE_INVALID,
|
||||||
|
CONTROLLER_PAGE_BUTTONS,
|
||||||
|
CONTROLLER_PAGE_KEYPADS,
|
||||||
|
CONTROLLER_PAGE_ANALOGS,
|
||||||
|
CONTROLLER_PAGE_OVERLAY,
|
||||||
|
CONTROLLER_PAGE_LIGHTS,
|
||||||
|
CONTROLLER_PAGE_PRESETS,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MatchEntry {
|
struct MatchEntry {
|
||||||
@@ -41,8 +49,9 @@ namespace overlay::windows {
|
|||||||
std::vector<Game> games_list;
|
std::vector<Game> games_list;
|
||||||
std::vector<const char *> games_names;
|
std::vector<const char *> games_names;
|
||||||
|
|
||||||
// tabs ui
|
// currently selected top-level tab and Controller sub-page
|
||||||
ConfigTab tab_selected = ConfigTab::CONFIG_TAB_INVALID;
|
ConfigTab tab_selected = ConfigTab::CONFIG_TAB_INVALID;
|
||||||
|
ControllerPage controller_page_selected = ControllerPage::CONTROLLER_PAGE_INVALID;
|
||||||
|
|
||||||
// buttons tab
|
// buttons tab
|
||||||
bool buttons_keyboard_state[0xFF];
|
bool buttons_keyboard_state[0xFF];
|
||||||
@@ -136,6 +145,9 @@ namespace overlay::windows {
|
|||||||
bool options_scroll_pending = false;
|
bool options_scroll_pending = false;
|
||||||
bool options_scroll_top = false;
|
bool options_scroll_top = false;
|
||||||
|
|
||||||
|
// Controller tab left-nav: selected sub-page
|
||||||
|
std::string controller_page_label = "";
|
||||||
|
|
||||||
std::filesystem::path file_picker_path;
|
std::filesystem::path file_picker_path;
|
||||||
std::thread *file_picker_thread = nullptr;
|
std::thread *file_picker_thread = nullptr;
|
||||||
bool file_picker_done = false;
|
bool file_picker_done = false;
|
||||||
@@ -195,6 +207,8 @@ namespace overlay::windows {
|
|||||||
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr,
|
std::vector<Option> *options, const std::string &category, const std::string *filter=nullptr,
|
||||||
bool quick_only=false);
|
bool quick_only=false);
|
||||||
void build_options_tab(float page_offset);
|
void build_options_tab(float page_offset);
|
||||||
|
void build_controller_tab(float page_offset, ControllerPage *page_selected_new);
|
||||||
|
bool build_nav_header(const char *label, bool active);
|
||||||
void build_about();
|
void build_about();
|
||||||
void build_launcher();
|
void build_launcher();
|
||||||
void build_keypad_warning();
|
void build_keypad_warning();
|
||||||
|
|||||||
Reference in New Issue
Block a user