mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
overlay: update UI for card manager (#294)
## Link to GitHub Issue, if one exists
n/a
## Description of change
Change the usage pattern for Card Manager UI.
### Previous behavior
Previously, it was a list of cards that you select, and click a button
to insert as P1 or P2.
This is fine, but users got confused when they pressed `Insert Card`
overlay key and got a different card inserted, or when auto-insert
didn't work as expected.
Additionally, if you play a game without continue (IIDX/DDR for
example), then it's cumbersome to bring up the overlay and click on
insert card every time.
### New behavior
Insert Card overlay now lets you pick a card and *slot* it into P1 or P2
side.
From that point on, the slotted card number is used as the override,
replacing what was previously passed to `-card0` or `-card1`. This means
that `Insert Card` button and auto-insert will pick up the new card and
use that instead.
## Compiling
👍
## Testing
Tested 1p-only game (popn) and 2p games (DDR, IIDX).
This commit is contained in:
@@ -124,6 +124,8 @@ std::string LOG_FILE_PATH = "";
|
|||||||
int LAUNCHER_ARGC = 0;
|
int LAUNCHER_ARGC = 0;
|
||||||
char **LAUNCHER_ARGV = nullptr;
|
char **LAUNCHER_ARGV = nullptr;
|
||||||
std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
std::unique_ptr<std::vector<Option>> LAUNCHER_OPTIONS;
|
||||||
|
|
||||||
|
std::mutex CARD_OVERRIDES_LOCK;
|
||||||
std::string CARD_OVERRIDES[2];
|
std::string CARD_OVERRIDES[2];
|
||||||
|
|
||||||
// sub-systems
|
// sub-systems
|
||||||
@@ -744,9 +746,11 @@ int main_implementation(int argc, char *argv[]) {
|
|||||||
SetDllDirectoryW(MODULE_PATH.c_str());
|
SetDllDirectoryW(MODULE_PATH.c_str());
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::Player1Card].is_active()) {
|
if (options[launcher::Options::Player1Card].is_active()) {
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
CARD_OVERRIDES[0] = options[launcher::Options::Player1Card].value_text();
|
CARD_OVERRIDES[0] = options[launcher::Options::Player1Card].value_text();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::Player2Card].is_active()) {
|
if (options[launcher::Options::Player2Card].is_active()) {
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
CARD_OVERRIDES[1] = options[launcher::Options::Player2Card].value_text();
|
CARD_OVERRIDES[1] = options[launcher::Options::Player2Card].value_text();
|
||||||
}
|
}
|
||||||
if (options[launcher::Options::Player1PinMacro].is_active()) {
|
if (options[launcher::Options::Player1PinMacro].is_active()) {
|
||||||
|
|||||||
+16
-12
@@ -66,7 +66,7 @@ bool eamuse_get_card(int active_count, int unit_id, uint8_t *card) {
|
|||||||
if (CARD_INSERT_UID_ENABLE[index]) {
|
if (CARD_INSERT_UID_ENABLE[index]) {
|
||||||
CARD_INSERT_UID_ENABLE[index] = false;
|
CARD_INSERT_UID_ENABLE[index] = false;
|
||||||
memcpy(card, CARD_INSERT_UID[index], 8);
|
memcpy(card, CARD_INSERT_UID[index], 8);
|
||||||
log_info("eamuse", "Inserted card from reader {}: {}", index, bin2hex(card, 8));
|
log_info("eamuse", "[P{}] Inserted card from reader: {}", index+1, bin2hex(card, 8));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,35 +83,40 @@ bool eamuse_get_card(int active_count, int unit_id, uint8_t *card) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool eamuse_get_card(const std::filesystem::path &path, uint8_t *card, int index) {
|
bool eamuse_get_card(const std::filesystem::path &path, uint8_t *card, int index) {
|
||||||
|
// do a quick copy under lock
|
||||||
|
std::unique_lock<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
|
const auto card_override = CARD_OVERRIDES[index];
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
// Check if card overrides are present
|
// Check if card overrides are present
|
||||||
if (!CARD_OVERRIDES[index].empty()) {
|
if (!card_override.empty()) {
|
||||||
|
|
||||||
// Override is present
|
// Override is present
|
||||||
for (int n = 0; n < 16; n++) {
|
for (int n = 0; n < 16; n++) {
|
||||||
char c = CARD_OVERRIDES[index].c_str()[n];
|
char c = card_override.c_str()[n];
|
||||||
bool digit = c >= '0' && c <= '9';
|
bool digit = c >= '0' && c <= '9';
|
||||||
bool character_big = c >= 'A' && c <= 'F';
|
bool character_big = c >= 'A' && c <= 'F';
|
||||||
bool character_small = c >= 'a' && c <= 'f';
|
bool character_small = c >= 'a' && c <= 'f';
|
||||||
if (!digit && !character_big && !character_small) {
|
if (!digit && !character_big && !character_small) {
|
||||||
log_warning("eamuse",
|
log_warning("eamuse",
|
||||||
"{} card override contains an invalid character sequence at byte {} (16 characters, 0-9/A-F only)",
|
"{} card override contains an invalid character sequence at byte {} (16 characters, 0-9/A-F only)",
|
||||||
CARD_OVERRIDES[index], n);
|
card_override, n);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Log info
|
// Log info
|
||||||
log_info("eamuse", "Inserted card override: {}", CARD_OVERRIDES[index]);
|
log_info("eamuse", "[P{}] Inserted card override: {}", index+1, card_override);
|
||||||
|
|
||||||
// Card is valid, convert and set it.
|
// Card is valid, convert and set it.
|
||||||
hex2bin(CARD_OVERRIDES[index].c_str(), card);
|
hex2bin(card_override.c_str(), card);
|
||||||
|
|
||||||
// cache it for auto-insert
|
// cache it for auto-insert
|
||||||
if (AUTO_INSERT_CARD[index] && !AUTO_INSERT_CARD_CACHED[index]) {
|
// always overwrite from overrides since override may have changed by user in card manager
|
||||||
|
if (AUTO_INSERT_CARD[index]) {
|
||||||
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
||||||
AUTO_INSERT_CARD_CACHED[index] = true;
|
AUTO_INSERT_CARD_CACHED[index] = true;
|
||||||
log_info("eamuse", "Auto card insert - caching this card in memory: {}", CARD_OVERRIDES[index]);
|
log_info("eamuse", "[P{}] Auto card insert - caching this card override in memory: {}", index+1, card_override);
|
||||||
}
|
}
|
||||||
|
|
||||||
// success
|
// success
|
||||||
@@ -162,7 +167,7 @@ bool eamuse_get_card_from_file(const std::filesystem::path &path, uint8_t *card,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// info
|
// info
|
||||||
log_info("eamuse", "Inserted {}: {}", path.string(), buffer);
|
log_info("eamuse", "[P{}] Inserted {}: {}", index+1, path.string(), buffer);
|
||||||
|
|
||||||
// convert hex to bytes
|
// convert hex to bytes
|
||||||
hex2bin(buffer, card);
|
hex2bin(buffer, card);
|
||||||
@@ -171,7 +176,7 @@ bool eamuse_get_card_from_file(const std::filesystem::path &path, uint8_t *card,
|
|||||||
if (AUTO_INSERT_CARD[index] && !AUTO_INSERT_CARD_CACHED[index]) {
|
if (AUTO_INSERT_CARD[index] && !AUTO_INSERT_CARD_CACHED[index]) {
|
||||||
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
memcpy(AUTO_INSERT_CARD_CACHED_DATA[index], card, 8);
|
||||||
AUTO_INSERT_CARD_CACHED[index] = true;
|
AUTO_INSERT_CARD_CACHED[index] = true;
|
||||||
log_info("eamuse", "Auto card insert - caching this card in memory: {}", buffer);
|
log_info("eamuse", "[P{}] Auto card insert - caching this card from file in memory: {}", index+1, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// success
|
// success
|
||||||
@@ -211,7 +216,6 @@ bool eamuse_card_insert_consume(int active_count, int unit_id) {
|
|||||||
if (!CARD_INSERT[index]) {
|
if (!CARD_INSERT[index]) {
|
||||||
eamuse_card_insert(index);
|
eamuse_card_insert(index);
|
||||||
// not logging anything here to prevent spam
|
// not logging anything here to prevent spam
|
||||||
// log_info("eamuse", "Automatic card insert on {}/{} (-autocard)", unit_id + 1, active_count);
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@@ -223,7 +227,7 @@ bool eamuse_card_insert_consume(int active_count, int unit_id) {
|
|||||||
auto offset = unit_id * games::KeypadButtons::Size;
|
auto offset = unit_id * games::KeypadButtons::Size;
|
||||||
if ((CARD_INSERT[index] && fabs(get_performance_seconds() - CARD_INSERT_TIME[index]) < CARD_INSERT_TIMEOUT)
|
if ((CARD_INSERT[index] && fabs(get_performance_seconds() - CARD_INSERT_TIME[index]) < CARD_INSERT_TIMEOUT)
|
||||||
|| GameAPI::Buttons::getState(RI_MGR, keypad_buttons->at(games::KeypadButtons::InsertCard + offset))) {
|
|| GameAPI::Buttons::getState(RI_MGR, keypad_buttons->at(games::KeypadButtons::InsertCard + offset))) {
|
||||||
log_info("eamuse", "Card insert on {}/{}", unit_id + 1, active_count);
|
log_info("eamuse", "[P{}] Card insert on reader (total active count: {})", unit_id+1, active_count);
|
||||||
CARD_INSERT[index] = false;
|
CARD_INSERT[index] = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "external/scard/scard.h"
|
#include "external/scard/scard.h"
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ enum eam_io_keypad_scan_code {
|
|||||||
EAM_IO_INSERT = 13, /* SpiceTools Extension */
|
EAM_IO_INSERT = 13, /* SpiceTools Extension */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern std::mutex CARD_OVERRIDES_LOCK;
|
||||||
extern std::string CARD_OVERRIDES[2];
|
extern std::string CARD_OVERRIDES[2];
|
||||||
extern bool AUTO_INSERT_CARD[2];
|
extern bool AUTO_INSERT_CARD[2];
|
||||||
extern float AUTO_INSERT_CARD_COOLDOWN;
|
extern float AUTO_INSERT_CARD_COOLDOWN;
|
||||||
|
|||||||
@@ -5,9 +5,11 @@
|
|||||||
#include "external/rapidjson/document.h"
|
#include "external/rapidjson/document.h"
|
||||||
#include "external/rapidjson/prettywriter.h"
|
#include "external/rapidjson/prettywriter.h"
|
||||||
#include "misc/eamuse.h"
|
#include "misc/eamuse.h"
|
||||||
|
#include "misc/clipboard.h"
|
||||||
#include "util/utils.h"
|
#include "util/utils.h"
|
||||||
#include "util/fileutils.h"
|
#include "util/fileutils.h"
|
||||||
#include "cfg/configurator.h"
|
#include "cfg/configurator.h"
|
||||||
|
#include "overlay/imgui/extensions.h"
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
|
|
||||||
@@ -31,15 +33,69 @@ namespace overlay::windows {
|
|||||||
if (fileutils::file_exists(this->config_path)) {
|
if (fileutils::file_exists(this->config_path)) {
|
||||||
this->config_load();
|
this->config_load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load -card0 / -card1
|
||||||
|
// -card0 / -card1 override
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
|
if (!CARD_OVERRIDES[0].empty()) {
|
||||||
|
const CardEntry card0 = {
|
||||||
|
.name = "P1 Default (-card0)",
|
||||||
|
.id = CARD_OVERRIDES[0],
|
||||||
|
.search_string = "p1 default (-card0)",
|
||||||
|
.read_only = true,
|
||||||
|
.color = {0.9f, 0.9f, 0.9f}
|
||||||
|
};
|
||||||
|
card_cmd_overrides[0].emplace(card0);
|
||||||
|
this->loaded_card[0] = card0;
|
||||||
|
}
|
||||||
|
if (eamuse_get_game_keypads() > 1 && !CARD_OVERRIDES[1].empty()) {
|
||||||
|
const CardEntry card1 = {
|
||||||
|
.name = "P2 Default (-card1)",
|
||||||
|
.id = CARD_OVERRIDES[1],
|
||||||
|
.search_string = "p2 default (-card1)",
|
||||||
|
.read_only = true,
|
||||||
|
.color = {0.9f, 0.9f, 0.9f}
|
||||||
|
};
|
||||||
|
card_cmd_overrides[1].emplace(card1);
|
||||||
|
this->loaded_card[1] = card1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CardManager::~CardManager() {
|
CardManager::~CardManager() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::build_content() {
|
void CardManager::build_content() {
|
||||||
ImGui::SeparatorText("Selected card");
|
ImGui::TextColored(ImVec4(1, 0.7f, 0, 1), "Active card overrides");
|
||||||
build_card();
|
ImGui::SameLine();
|
||||||
ImGui::SeparatorText("Available cards");
|
ImGui::HelpMarker(
|
||||||
|
"Click to insert card now, or press Insert Card key. Auto Card Insert will also use these cards.\n\n"
|
||||||
|
"If no override is set, pressing Insert Card will read from card0.txt / card1.txt.");
|
||||||
|
if (ImGui::BeginTable("CardSetTable", eamuse_get_game_keypads() > 1 ? 2 : 1, ImGuiTableFlags_SizingFixedFit)) {
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted("Player 1");
|
||||||
|
if (eamuse_get_game_keypads() > 1) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
ImGui::TextUnformatted("Player 2");
|
||||||
|
}
|
||||||
|
ImGui::TableNextRow();
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
if (eamuse_get_game_keypads() > (int)i) {
|
||||||
|
ImGui::TableNextColumn();
|
||||||
|
if (build_card(i) && this->loaded_card[i].has_value()) {
|
||||||
|
insert_card_over_api(i, this->loaded_card[i].value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Spacing();
|
||||||
|
ImGui::Spacing();
|
||||||
|
|
||||||
|
ImGui::TextColored(ImVec4(1, 0.7f, 0, 1), "Available cards");
|
||||||
build_card_list();
|
build_card_list();
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
@@ -48,44 +104,13 @@ namespace overlay::windows {
|
|||||||
build_card_editor();
|
build_card_editor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::build_card() {
|
bool CardManager::build_card(int reader) {
|
||||||
ImGui::BeginDisabled(this->current_card == nullptr);
|
ImGui::PushID(reader);
|
||||||
// insert P1 button
|
bool clicked = false;
|
||||||
if (ImGui::Button("Insert P1")) {
|
if (this->loaded_card[reader].has_value()) {
|
||||||
const auto card = this->current_card;
|
const auto &card = this->loaded_card[reader].value();
|
||||||
uint8_t card_bin[8];
|
const ImVec4 color(card.color[0], card.color[1], card.color[2], 1.f);
|
||||||
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
|
float bg_luminance = (0.299f * card.color[0] + 0.587 * card.color[1] + 0.114 * card.color[2]);
|
||||||
eamuse_card_insert(0, card_bin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert P2 button
|
|
||||||
if (eamuse_get_game_keypads() > 1) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Insert P2")) {
|
|
||||||
const auto card = this->current_card;
|
|
||||||
uint8_t card_bin[8];
|
|
||||||
if (card && card->id.length() == 16 && hex2bin(card->id.c_str(), card_bin)) {
|
|
||||||
eamuse_card_insert(1, card_bin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// edit selected card
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Edit Card")) {
|
|
||||||
open_card_editor();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
|
||||||
|
|
||||||
ImGui::Spacing();
|
|
||||||
|
|
||||||
// card ui
|
|
||||||
if (this->current_card) {
|
|
||||||
const auto card = this->current_card;
|
|
||||||
const ImVec4 color(card->color[0], card->color[1], card->color[2], 1.f);
|
|
||||||
float bg_luminance = (0.299f * card->color[0] + 0.587 * card->color[1] + 0.114 * card->color[2]);
|
|
||||||
|
|
||||||
// text color
|
// text color
|
||||||
ImVec4 text_color;
|
ImVec4 text_color;
|
||||||
@@ -101,21 +126,25 @@ namespace overlay::windows {
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Text, text_color);
|
ImGui::PushStyleColor(ImGuiCol_Text, text_color);
|
||||||
if (ImGui::Button(fmt::format(
|
if (ImGui::Button(fmt::format(
|
||||||
" {} \n {} {} {} {} ",
|
" {} \n {} {} {} {} ",
|
||||||
card->name.empty() ? "<blank>" : card->name.substr(0, 19),
|
card.name.empty() ? "<blank>" : card.name.substr(0, 19),
|
||||||
card->id.substr(0, 4).c_str(),
|
card.id.substr(0, 4).c_str(),
|
||||||
card->id.substr(4, 4).c_str(),
|
card.id.substr(4, 4).c_str(),
|
||||||
card->id.substr(8, 4).c_str(),
|
card.id.substr(8, 4).c_str(),
|
||||||
card->id.substr(12, 4).c_str()
|
card.id.substr(12, 4).c_str()
|
||||||
).c_str())) {
|
).c_str())) {
|
||||||
|
|
||||||
open_card_editor();
|
clicked = true;
|
||||||
}
|
}
|
||||||
ImGui::PopStyleColor(4);
|
ImGui::PopStyleColor(4);
|
||||||
} else {
|
} else {
|
||||||
ImGui::BeginDisabled();
|
ImGui::BeginDisabled();
|
||||||
ImGui::Button(" <No card> \n xxxx xxxx xxxx xxxx ");
|
ImGui::Button(" (No override set) \n"
|
||||||
|
" xxxx xxxx xxxx xxxx ");
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
return clicked;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardManager::open_card_editor() {
|
void CardManager::open_card_editor() {
|
||||||
@@ -139,13 +168,18 @@ namespace overlay::windows {
|
|||||||
this->card_buffer,
|
this->card_buffer,
|
||||||
std::size(this->card_buffer),
|
std::size(this->card_buffer),
|
||||||
ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
|
ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
|
||||||
|
ImGui::EndDisabled();
|
||||||
if (this->current_card == nullptr) {
|
if (this->current_card == nullptr) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Generate")) {
|
if (ImGui::Button("Generate")) {
|
||||||
generate_ea_card(this->card_buffer);
|
generate_ea_card(this->card_buffer);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (ImGui::Button("Copy")) {
|
||||||
|
clipboard::copy_text(this->current_card->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
|
||||||
|
|
||||||
// name field
|
// name field
|
||||||
ImGui::InputTextWithHint("Card Name", "Main Card",
|
ImGui::InputTextWithHint("Card Name", "Main Card",
|
||||||
@@ -170,6 +204,18 @@ namespace overlay::windows {
|
|||||||
this->current_card->color[1] = this->color_buffer[1];
|
this->current_card->color[1] = this->color_buffer[1];
|
||||||
this->current_card->color[2] = this->color_buffer[2];
|
this->current_card->color[2] = this->color_buffer[2];
|
||||||
generate_search_string(this->current_card);
|
generate_search_string(this->current_card);
|
||||||
|
|
||||||
|
// ensure loaded cards are kept up to date
|
||||||
|
// note: does not handle cases where multiple cards have the same ID
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
if (this->loaded_card[i].has_value() &&
|
||||||
|
!this->loaded_card[i].value().read_only &&
|
||||||
|
this->loaded_card[i].value().id == this->current_card->id) {
|
||||||
|
this->loaded_card[i] = *this->current_card;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// create a new card
|
// create a new card
|
||||||
CardEntry card {
|
CardEntry card {
|
||||||
@@ -210,14 +256,54 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardManager::build_card_selectable(CardEntry &card) {
|
||||||
|
// generate card name
|
||||||
|
std::string card_name = "";
|
||||||
|
if (card.id.length() == 16) {
|
||||||
|
card_name += card.id.substr(0, 4);
|
||||||
|
card_name += " ";
|
||||||
|
card_name += card.id.substr(4, 4);
|
||||||
|
card_name += " ";
|
||||||
|
card_name += card.id.substr(8, 4);
|
||||||
|
card_name += " ";
|
||||||
|
card_name += card.id.substr(12, 4);
|
||||||
|
} else {
|
||||||
|
card_name += card.id;
|
||||||
|
}
|
||||||
|
if (!card.name.empty()) {
|
||||||
|
card_name += " - ";
|
||||||
|
card_name += card.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PushID(&card);
|
||||||
|
|
||||||
|
// color button
|
||||||
|
ImVec4 color(card.color[0], card.color[1], card.color[2], 1.f);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color);
|
||||||
|
ImGui::SmallButton(" ");
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
// selectable item
|
||||||
|
if (ImGui::Selectable(card_name.c_str(), this->current_card == &card)) {
|
||||||
|
this->current_card = &card;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
void CardManager::build_card_list() {
|
void CardManager::build_card_list() {
|
||||||
|
|
||||||
// search for card
|
// search for card
|
||||||
//
|
//
|
||||||
// setting ImGuiInputTextFlags_CallbackCharFilter and pressing escape doesn't cause below
|
// setting ImGuiInputTextFlags_CallbackCharFilter and pressing escape doesn't cause below
|
||||||
// to return true, making it necessary to provide a callback...
|
// to return true, making it necessary to provide a callback...
|
||||||
ImGui::SetNextItemWidth(220);
|
ImGui::SetNextItemWidth(240);
|
||||||
if (ImGui::InputTextWithHint("", "Type here to search..", &this->search_filter)) {
|
if (ImGui::InputTextWithHint("", "Type here to search..", &this->search_filter)) {
|
||||||
|
this->current_card = nullptr;
|
||||||
this->search_filter_in_lower_case = strtolower(this->search_filter);
|
this->search_filter_in_lower_case = strtolower(this->search_filter);
|
||||||
}
|
}
|
||||||
if (!this->search_filter.empty()) {
|
if (!this->search_filter.empty()) {
|
||||||
@@ -226,11 +312,49 @@ namespace overlay::windows {
|
|||||||
this->search_filter.clear();
|
this->search_filter.clear();
|
||||||
this->search_filter_in_lower_case.clear();
|
this->search_filter_in_lower_case.clear();
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
// toolbar
|
||||||
|
|
||||||
|
// set card as p1/p2
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
if (eamuse_get_game_keypads() > (int)i) {
|
||||||
|
if (i != 0) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
}
|
||||||
|
ImGui::PushID(i);
|
||||||
|
ImGui::BeginDisabled(this->current_card == nullptr);
|
||||||
|
if (ImGui::Button(i == 0 ? "Load P1" : "Load P2") && this->current_card) {
|
||||||
|
this->loaded_card[i] = *this->current_card;
|
||||||
|
log_info(
|
||||||
|
"cardmanager",
|
||||||
|
"[P{}] update override and insert card: {} ({})",
|
||||||
|
i+1,
|
||||||
|
this->current_card->id,
|
||||||
|
this->current_card->name
|
||||||
|
);
|
||||||
|
|
||||||
|
// update override
|
||||||
|
std::lock_guard<std::mutex> lock(CARD_OVERRIDES_LOCK);
|
||||||
|
CARD_OVERRIDES[i] = this->current_card->id;
|
||||||
|
|
||||||
|
// insert card over api
|
||||||
|
insert_card_over_api(i, this->loaded_card[i].value());
|
||||||
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// edit selected card
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::BeginDisabled(this->current_card == nullptr || this->current_card->read_only);
|
||||||
|
if (ImGui::Button("Edit")) {
|
||||||
|
open_card_editor();
|
||||||
|
}
|
||||||
|
|
||||||
// move selected up/down the list
|
// move selected up/down the list
|
||||||
ImGui::BeginDisabled(this->current_card == nullptr);
|
if (this->search_filter.empty()) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button("Move Up")) {
|
if (ImGui::Button("Move Up")) {
|
||||||
for (auto it = this->cards.begin(); it != this->cards.end(); ++it) {
|
for (auto it = this->cards.begin(); it != this->cards.end(); ++it) {
|
||||||
@@ -253,36 +377,27 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
|
||||||
}
|
}
|
||||||
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
ImGui::Spacing();
|
ImGui::Spacing();
|
||||||
|
|
||||||
// cards list
|
// cards list
|
||||||
// use all available vertical space, minus height of buttons, minus separator
|
// use all available vertical space, minus height footer (a row of buttons and separator)
|
||||||
if (ImGui::BeginChild(
|
if (ImGui::BeginChild(
|
||||||
"cards",
|
"cards",
|
||||||
ImVec2(0, ImGui::GetContentRegionAvail().y - ImGui::GetFrameHeightWithSpacing() - 8.f))) {
|
ImVec2(0, ImGui::GetContentRegionAvail().y - ImGui::GetFrameHeightWithSpacing() - 8.f))) {
|
||||||
for (auto &card : this->cards) {
|
|
||||||
|
|
||||||
// get card name
|
// -card0 / -card1 override
|
||||||
std::string card_name = "";
|
for (size_t i = 0; i < 2; i++) {
|
||||||
if (card.id.length() == 16) {
|
if (card_cmd_overrides[i].has_value()) {
|
||||||
card_name += card.id.substr(0, 4);
|
build_card_selectable(card_cmd_overrides[i].value());
|
||||||
card_name += " ";
|
|
||||||
card_name += card.id.substr(4, 4);
|
|
||||||
card_name += " ";
|
|
||||||
card_name += card.id.substr(8, 4);
|
|
||||||
card_name += " ";
|
|
||||||
card_name += card.id.substr(12, 4);
|
|
||||||
} else {
|
|
||||||
card_name += card.id;
|
|
||||||
}
|
}
|
||||||
if (!card.name.empty()) {
|
|
||||||
card_name += " - ";
|
|
||||||
card_name += card.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// cards from card manager JSON
|
||||||
|
for (auto &card : this->cards) {
|
||||||
|
|
||||||
if (!this->search_filter_in_lower_case.empty() && !card.search_string.empty()) {
|
if (!this->search_filter_in_lower_case.empty() && !card.search_string.empty()) {
|
||||||
const bool matched =
|
const bool matched =
|
||||||
card.search_string.find(this->search_filter_in_lower_case) != std::string::npos;
|
card.search_string.find(this->search_filter_in_lower_case) != std::string::npos;
|
||||||
@@ -292,21 +407,7 @@ namespace overlay::windows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw entry
|
build_card_selectable(card);
|
||||||
ImGui::PushID(&card);
|
|
||||||
|
|
||||||
ImVec4 color(card.color[0], card.color[1], card.color[2], 1.f);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, color);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, color);
|
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, color);
|
|
||||||
ImGui::SmallButton(" ");
|
|
||||||
ImGui::PopStyleColor(3);
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Selectable(card_name.c_str(), this->current_card == &card)) {
|
|
||||||
this->current_card = &card;
|
|
||||||
}
|
|
||||||
ImGui::PopID();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
@@ -503,4 +604,11 @@ namespace overlay::windows {
|
|||||||
this->color_buffer[1] = g / 255.f;
|
this->color_buffer[1] = g / 255.f;
|
||||||
this->color_buffer[2] = b / 255.f;
|
this->color_buffer[2] = b / 255.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardManager::insert_card_over_api(int reader, CardEntry &card) {
|
||||||
|
uint8_t card_bin[8];
|
||||||
|
if (card.id.length() == 16 && hex2bin(card.id.c_str(), card_bin)) {
|
||||||
|
eamuse_card_insert(reader, card_bin);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "overlay/window.h"
|
#include "overlay/window.h"
|
||||||
|
|
||||||
@@ -10,6 +11,7 @@ namespace overlay::windows {
|
|||||||
std::string name = "unnamed";
|
std::string name = "unnamed";
|
||||||
std::string id = "E004010000000000";
|
std::string id = "E004010000000000";
|
||||||
std::string search_string = "";
|
std::string search_string = "";
|
||||||
|
bool read_only = false;
|
||||||
float color[3] {};
|
float color[3] {};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,6 +32,9 @@ namespace overlay::windows {
|
|||||||
char card_buffer[17] {};
|
char card_buffer[17] {};
|
||||||
float color_buffer[3] {};
|
float color_buffer[3] {};
|
||||||
|
|
||||||
|
std::optional<CardEntry> card_cmd_overrides[2];
|
||||||
|
|
||||||
|
std::optional<CardEntry> loaded_card[2];
|
||||||
CardEntry *current_card = nullptr;
|
CardEntry *current_card = nullptr;
|
||||||
|
|
||||||
std::string search_filter = "";
|
std::string search_filter = "";
|
||||||
@@ -41,10 +46,13 @@ namespace overlay::windows {
|
|||||||
void generate_search_string(CardEntry *card);
|
void generate_search_string(CardEntry *card);
|
||||||
void generate_random_color();
|
void generate_random_color();
|
||||||
|
|
||||||
void build_card();
|
bool build_card(int reader);
|
||||||
void open_card_editor();
|
void open_card_editor();
|
||||||
void build_card_editor();
|
void build_card_editor();
|
||||||
void build_card_list();
|
void build_card_list();
|
||||||
|
void build_card_selectable(CardEntry &card);
|
||||||
void build_footer();
|
void build_footer();
|
||||||
|
|
||||||
|
void insert_card_over_api(int reader, CardEntry &card);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user