From 51d3c8e6f2d22bcabd2c2c6eb05283fcb3e5fa5e Mon Sep 17 00:00:00 2001 From: Zy Date: Sat, 28 Sep 2024 03:15:49 +0200 Subject: [PATCH] console utils --- .vscode/settings.json | 13 ++++++ source/main.cpp | 48 ++++++++++++++++++----- source/utilsconsole.cpp | 87 +++++++++++++++++++++++++++++++++++++++++ source/utilsconsole.hpp | 46 ++++++++++++++++++++++ 4 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 source/utilsconsole.cpp create mode 100644 source/utilsconsole.hpp diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3db08b8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,13 @@ +{ + "files.associations": { + "ostream": "cpp", + "system_error": "cpp", + "array": "cpp", + "functional": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "random": "cpp", + "limits": "cpp" + } +} \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index e33c832..577a539 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,21 +1,49 @@ #include <3ds.h> #include +#include "utilsconsole.hpp" using namespace std; int main(void) {; gfxInitDefault(); - consoleInit(GFX_TOP, NULL); - bool value = false; - while (aptMainLoop()) { - hidScanInput(); - if (hidKeysDown() & KEY_A) - value = !value; + consoleInit(GFX_BOTTOM, NULL); - gspWaitForVBlank(); - GSPGPU_SetLedForceOff(value); - gfxFlushBuffers(); - gfxSwapBuffers(); + int a = 0; + int b = 2; + int c = -10; + while (aptMainLoop()) { + static const s_uc_menu_element menu[] = { + {"a", true, &a, 0, 10}, + {"b", true, &b, 0, 2}, + {"c", true, &c, -10, 10}, + {"Show", false, NULL, 0, 0}, + {"Test quick menu", false, NULL, 0, 0}, + }; + static auto menuVec = vector(menu, menu + 5); + int ans = uc_menu(menuVec); + if (ans == 3) { + cout << "a: " << a << ", b: " << b << ", c: " << c << endl; + uc_pause(); + } + else if (ans == 4) { + while (aptMainLoop()) { + ans = uc_menu_quick("hello", "hola", "bonjour", "Go back"); + switch (ans) { + case 0: + cout << "bye" << endl; + break; + case 1: + cout << "adios" << endl; + break; + case 2: + cout << "au revoir" << endl; + break; + } + if (ans == 3) + break; + uc_pause(); + } + } } gfxExit(); } \ No newline at end of file diff --git a/source/utilsconsole.cpp b/source/utilsconsole.cpp new file mode 100644 index 0000000..198f592 --- /dev/null +++ b/source/utilsconsole.cpp @@ -0,0 +1,87 @@ +#include <3ds.h> +#include +#include +#include "utilsconsole.hpp" + +int uc_menu(vector &elements) { + static void *lastElements = NULL; + static size_t selected = 0; + + bool confirmed = false; + + if (&elements != lastElements) { + // init if new menu + consoleClear(); + lastElements = &elements; + selected = 0; + } + else { + // read inputs + hidScanInput(); + if (hidKeysDown() & KEY_UP) { + if (selected-- == 0) + selected += elements.size(); + } + else if (hidKeysDown() & KEY_DOWN) { + if (++selected >= elements.size()) + selected -= elements.size(); + } + else if (!elements[selected].is_number_prompt) { + if (hidKeysDown() & KEY_A) { + confirmed = true; + lastElements = NULL; + } + } + else { + if (hidKeysDown() & KEY_LEFT) + if (*elements[selected].value > elements[selected].min) + (*elements[selected].value)--; + if (hidKeysDown() & KEY_RIGHT) + if (*elements[selected].value < elements[selected].max) + (*elements[selected].value)++; + } + } + + // display + cout << "\e[H\e[0m"; + for (size_t i = 0; i < elements.size(); i++) { + cout << (i == selected && !confirmed ? "\e[7m" : "") + << elements[i].name << "\e[0m"; + if (elements[i].is_number_prompt) + cout + << ((*(elements[i].value) == elements[i].min) ? " " : " <") + << *(elements[i].value) + << ((*(elements[i].value) == elements[i].max) ? " " : ">"); + cout << "\e[0K" << endl; + } + if (!confirmed) + cout << "\e[2m" << "[Up/Down] Move / " + << (elements[selected].is_number_prompt ? + "[Left/Right] Modify" : "(A) Confirm") << "\e[0K" << endl; + else + cout << "\e[2mOK.\e[0K\e[0m" << endl; + + return confirmed ? selected : -1; +} + +int uc_menu_quick(const char *str, ...) { + va_list arguments; + auto elements = vector(); + for (va_start(arguments, str); str; str = va_arg(arguments, const char *)) + elements.push_back({str, false, NULL, 0, 0}); + + int r = -1; + while (r < 0 && aptMainLoop()) + r = uc_menu(elements); + return r; +} + +void uc_pause(void) { + cout << "\e[0;2mPress (A) to continue...\e[0m" << endl; + while (aptMainLoop()) { + hidScanInput(); + if (hidKeysDown() & KEY_A) + break; + gfxFlushBuffers(); + } +} \ No newline at end of file diff --git a/source/utilsconsole.hpp b/source/utilsconsole.hpp new file mode 100644 index 0000000..ae42a4d --- /dev/null +++ b/source/utilsconsole.hpp @@ -0,0 +1,46 @@ +/** + * utilsconsole.hpp (uc_*) + * Utility functions for the console. + */ + +#pragma once +#include +#include + +using namespace std; + +/// @brief To use with uc_menu(): Represent an element of the menu. +typedef struct { + /// @brief Displayed name. + string name; + /// @brief true if this button can be used to change the value of a number. + bool is_number_prompt; + /// @brief Only if is_number_prompt is true: the number to change. + int *value; + /// @brief Only if is_number_prompt is true: the minimum value possible for + /// value. + int min; + /// @brief Only if is_number_prompt is true: the maximum value possible for + /// value. + int max; +} s_uc_menu_element; + +/// @brief Display a menu with several items in the console. +/// @details +/// Non-blocking function, must be called in loop. +/// Only one menu can work at the same time. 'elements' must not change in +/// address. +/// @param elements A pointer to a vector of all the elements of the menu. +/// @return The index of the confirmed element. If none, return -1. +int uc_menu(vector &elements); + +/// @brief Display a menu quickly using only confirm buttons. +/// @details +/// Blocking function. Will return -1 if aptMainLoop() becomes false. +/// @param str Text representing each element. The last parameter must be NULL. +/// @return The index of the confirmed element. +int uc_menu_quick(const char *str, ...); + +/// @brief Blocks the program until the user presses A. +/// @details Will also return if aptMainLoop() becomes false. +void uc_pause(void); \ No newline at end of file