Merge pull request #4 from Juk3n/3-selecting-game-to-run-from-a-console-menuUnverified
3 selecting game to run from a console menu
modified
CMakeLists.txt +37 -3 | @@ -1,9 +1,43 @@ | ||
| 1 | -cmake_minimum_required(VERSION 3.10) | |
| 2 | -project(fluffy) | |
| 1 | +cmake_minimum_required(VERSION 3.14) | |
| 2 | + | |
| 3 | +include(FetchContent) | |
| 4 | + | |
| 5 | +set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE) | |
| 6 | +FetchContent_Declare(ftxui | |
| 7 | + GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui | |
| 8 | + GIT_TAG v5.0.0 | |
| 9 | +) | |
| 10 | +FetchContent_MakeAvailable(ftxui) | |
| 11 | +if(NOT ftxui_POPULATED) | |
| 12 | + FetchContent_Populate(ftxui) | |
| 13 | + add_subdirectory(${ftxui_SOURCE_DIR} ${ftxui_BINARY_DIR} EXCLUDE_FROM_ALL) | |
| 14 | +endif() | |
| 15 | + | |
| 16 | +project(fluffy LANGUAGES CXX VERSION 1.0.0) | |
| 3 | 17 | |
| 4 | 18 | set(CMAKE_CXX_STANDARD 20) |
| 5 | 19 | set(CMAKE_CXX_STANDARD_REQUIRED True) |
| 6 | 20 | |
| 21 | + | |
| 22 | +find_package(SQLite3 REQUIRED) | |
| 23 | + | |
| 7 | 24 | include_directories(${CMAKE_SOURCE_DIR}/include) |
| 8 | 25 | |
| 9 | -add_executable(fluffy src/main.cpp src/sqlite3.c) | |
| \ No newline at end of file | ||
| 26 | +add_executable(fluffy src/main.cpp) | |
| 27 | + | |
| 28 | +target_link_libraries(fluffy | |
| 29 | + PRIVATE ftxui::screen | |
| 30 | + PRIVATE ftxui::dom | |
| 31 | + PRIVATE ftxui::component | |
| 32 | + PRIVATE SQLite::SQLite3 | |
| 33 | +) | |
| 34 | + | |
| 35 | +if (EMSCRIPTEN) | |
| 36 | + string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS") | |
| 37 | + string(APPEND CMAKE_EXE_LINKER_FLAGS " -s ASYNCIFY") | |
| 38 | + string(APPEND CMAKE_EXE_LINKER_FLAGS " -s PROXY_TO_PTHREAD") | |
| 39 | + | |
| 40 | + foreach(file "index.html" "run_webassembly.py") | |
| 41 | + configure_file("src/${file}" ${file}) | |
| 42 | + endforeach(file) | |
| 43 | +endif() | |
| \ No newline at end of file | ||
| @@ -1,9 +1,43 @@ | |||
| 1 | -cmake_minimum_required(VERSION 3.10) | 1 | +cmake_minimum_required(VERSION 3.14) |
| 2 | -project(fluffy) | 2 | + |
| 3 | +include(FetchContent) | ||
| 4 | + | ||
| 5 | +set(FETCHCONTENT_UPDATES_DISCONNECTED TRUE) | ||
| 6 | +FetchContent_Declare(ftxui | ||
| 7 | + GIT_REPOSITORY https://github.com/ArthurSonzogni/ftxui | ||
| 8 | + GIT_TAG v5.0.0 | ||
| 9 | +) | ||
| 10 | +FetchContent_MakeAvailable(ftxui) | ||
| 11 | +if(NOT ftxui_POPULATED) | ||
| 12 | + FetchContent_Populate(ftxui) | ||
| 13 | + add_subdirectory(${ftxui_SOURCE_DIR} ${ftxui_BINARY_DIR} EXCLUDE_FROM_ALL) | ||
| 14 | +endif() | ||
| 15 | + | ||
| 16 | +project(fluffy LANGUAGES CXX VERSION 1.0.0) | ||
| 3 | 17 | ||
| 4 | set(CMAKE_CXX_STANDARD 20) | 18 | set(CMAKE_CXX_STANDARD 20) |
| 5 | set(CMAKE_CXX_STANDARD_REQUIRED True) | 19 | set(CMAKE_CXX_STANDARD_REQUIRED True) |
| 6 | 20 | ||
| 21 | + | ||
| 22 | +find_package(SQLite3 REQUIRED) | ||
| 23 | + | ||
| 7 | include_directories(${CMAKE_SOURCE_DIR}/include) | 24 | include_directories(${CMAKE_SOURCE_DIR}/include) |
| 8 | 25 | ||
| 9 | -add_executable(fluffy src/main.cpp src/sqlite3.c) | ||
| \ No newline at end of file | \ No newline at end of file | ||
| 26 | +add_executable(fluffy src/main.cpp) | ||
| 27 | + | ||
| 28 | +target_link_libraries(fluffy | ||
| 29 | + PRIVATE ftxui::screen | ||
| 30 | + PRIVATE ftxui::dom | ||
| 31 | + PRIVATE ftxui::component | ||
| 32 | + PRIVATE SQLite::SQLite3 | ||
| 33 | +) | ||
| 34 | + | ||
| 35 | +if (EMSCRIPTEN) | ||
| 36 | + string(APPEND CMAKE_CXX_FLAGS " -s USE_PTHREADS") | ||
| 37 | + string(APPEND CMAKE_EXE_LINKER_FLAGS " -s ASYNCIFY") | ||
| 38 | + string(APPEND CMAKE_EXE_LINKER_FLAGS " -s PROXY_TO_PTHREAD") | ||
| 39 | + | ||
| 40 | + foreach(file "index.html" "run_webassembly.py") | ||
| 41 | + configure_file("src/${file}" ${file}) | ||
| 42 | + endforeach(file) | ||
| 43 | +endif() | ||
| \ No newline at end of file | \ No newline at end of file | ||
modified
src/main.cpp +78 -18 | @@ -1,18 +1,27 @@ | ||
| 1 | +#include "ftxui/dom/elements.hpp" | |
| 2 | +#include "ftxui/screen/screen.hpp" | |
| 3 | +#include "ftxui/screen/string.hpp" | |
| 4 | +#include "ftxui/component/component.hpp" | |
| 5 | +#include "ftxui/component/component_options.hpp" | |
| 6 | +#include "ftxui/component/screen_interactive.hpp" | |
| 7 | + | |
| 1 | 8 | #include <iostream> |
| 2 | 9 | #include <string> |
| 3 | 10 | #include <cstdlib> |
| 4 | 11 | #include <filesystem> |
| 5 | -#include <../include/sqlite3.h> | |
| 12 | +#include <sqlite3.h> | |
| 13 | +#include <map> | |
| 14 | + | |
| 6 | 15 | |
| 7 | -std::string gamePath; | |
| 16 | +using namespace ftxui; | |
| 17 | + | |
| 18 | +std::map<std::string, std::string> games; | |
| 8 | 19 | |
| 9 | 20 | std::string database_initialization_command = "CREATE TABLE GAME(" |
| 10 | 21 | "GAME_ID INT PRIMARY KEY NOT NULL, " |
| 11 | 22 | "GAME_NAME TEXT NOT NULL, " |
| 12 | 23 | "GAME_PATH TEXT NOT NULL);"; |
| 13 | 24 | |
| 14 | -std::string insert_example_game_command = "INSERT INTO GAME (GAME_ID, GAME_NAME, GAME_PATH) VALUES (1, 'Devastating Fog', \"\");"; | |
| 15 | - | |
| 16 | 25 | const char* select_all_games_command = "SELECT * FROM GAME;"; |
| 17 | 26 | |
| 18 | 27 | bool debugRun = true; |
| @@ -26,28 +35,37 @@ void printMessage(std::string message) { | ||
| 26 | 35 | void execute_sql_command(sqlite3* database, std::string command) { |
| 27 | 36 | int exit = 0; |
| 28 | 37 | char* messageError; |
| 29 | - exit = sqlite3_exec(database, database_initialization_command.c_str(), NULL, 0, &messageError); | |
| 38 | + exit = sqlite3_exec(database, command.c_str(), NULL, 0, &messageError); | |
| 30 | 39 | |
| 31 | 40 | if (exit != SQLITE_OK) { |
| 32 | - printMessage("Error with command: " + command); | |
| 41 | + printMessage("Error with command: " + command + " " + messageError); | |
| 33 | 42 | sqlite3_free(messageError); |
| 34 | 43 | } |
| 35 | 44 | } |
| 36 | 45 | |
| 46 | +void addGame(sqlite3* database, std::string name, std::string path) { | |
| 47 | + static int val = 1; | |
| 48 | + std::string command = "INSERT INTO GAME (GAME_ID, GAME_NAME, GAME_PATH) VALUES ("; | |
| 49 | + command += std::to_string(val) + ", '" + name + "', \"" + path + "\");"; | |
| 50 | + val++; | |
| 51 | + execute_sql_command(database, command); | |
| 52 | +} | |
| 53 | + | |
| 37 | 54 | void initialize_database(sqlite3* database) { |
| 38 | - execute_sql_command(database, database_initialization_command.c_str()); | |
| 39 | - execute_sql_command(database, insert_example_game_command.c_str()); | |
| 55 | + execute_sql_command(database, database_initialization_command); | |
| 56 | + addGame(database, "Devastating Fog", ""); | |
| 57 | + addGame(database, "No Pirates Here!", ""); | |
| 40 | 58 | printMessage("Database Initialized"); |
| 41 | 59 | } |
| 42 | 60 | |
| 43 | 61 | int main() { |
| 44 | - bool newCreation = not std::filesystem::exists("example_database"); | |
| 62 | + bool newCreation = not std::filesystem::exists("data.db"); | |
| 45 | 63 | |
| 46 | 64 | char* messageError; |
| 47 | 65 | sqlite3* database; |
| 48 | 66 | sqlite3_stmt* stmt; |
| 49 | 67 | int exit = 0; |
| 50 | - exit = sqlite3_open("example_database", &database); | |
| 68 | + exit = sqlite3_open("data.db", &database); | |
| 51 | 69 | |
| 52 | 70 | if (exit) { |
| 53 | 71 | std::cerr << "Error opening database" << sqlite3_errmsg(database) << std::endl; |
| @@ -55,8 +73,6 @@ int main() { | ||
| 55 | 73 | } |
| 56 | 74 | |
| 57 | 75 | std::cout << "Opened database successfully!" << std::endl; |
| 58 | - | |
| 59 | - | |
| 60 | 76 | |
| 61 | 77 | if (newCreation) { |
| 62 | 78 | initialize_database(database); |
| @@ -72,15 +88,59 @@ int main() { | ||
| 72 | 88 | |
| 73 | 89 | while (sqlite3_step(stmt) == SQLITE_ROW) { |
| 74 | 90 | int id = sqlite3_column_int(stmt, 0); |
| 75 | - const unsigned char* game_name = sqlite3_column_text(stmt, 1); | |
| 76 | - const unsigned char* path = sqlite3_column_text(stmt, 2); | |
| 91 | + const unsigned char* gameName = sqlite3_column_text(stmt, 1); | |
| 92 | + const unsigned char* gamePath = sqlite3_column_text(stmt, 2); | |
| 77 | 93 | |
| 78 | - std::cout << game_name << ": " << path << std::endl; | |
| 79 | - gamePath.append(reinterpret_cast<const char*>(path)); | |
| 94 | + std::cout << gameName << ": " << gamePath << std::endl; | |
| 95 | + std::string name{reinterpret_cast<const char*>(gameName)}; | |
| 96 | + std::string path{reinterpret_cast<const char*>(gamePath)}; | |
| 97 | + games[name] = path; | |
| 80 | 98 | } |
| 81 | 99 | sqlite3_finalize(stmt); |
| 82 | 100 | |
| 101 | + int exit_id = games.size(); | |
| 102 | + int choice = 0; | |
| 103 | + do { | |
| 104 | + system("clear"); | |
| 105 | + auto document = vbox({ | |
| 106 | + center(text(L" Fluffy v0.1 ")), | |
| 107 | + }); | |
| 108 | + | |
| 109 | + document = document | size(WIDTH, LESS_THAN, 120); | |
| 110 | + | |
| 111 | + auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); | |
| 112 | + Render(screen, document); | |
| 113 | + | |
| 114 | + std::cout << screen.ToString() << '\0' << std::endl; | |
| 115 | + | |
| 116 | + | |
| 117 | + auto menu_screen = ScreenInteractive::TerminalOutput(); | |
| 118 | + | |
| 119 | + std::vector<std::string> localGames = {}; | |
| 120 | + for (const auto& [name, path] : games) { | |
| 121 | + localGames.push_back(name); | |
| 122 | + } | |
| 123 | + localGames.push_back("Exit"); | |
| 124 | + | |
| 125 | + MenuOption option; | |
| 126 | + option.on_enter = menu_screen.ExitLoopClosure(); | |
| 127 | + auto menu = Menu(&localGames, &choice, option); | |
| 128 | + menu_screen.Loop(menu); | |
| 129 | + | |
| 130 | + if (choice != exit_id) { | |
| 131 | + int i{ 0 }; | |
| 132 | + std::string pathToRun = ""; | |
| 133 | + for (const auto& [name, path] : games) { | |
| 134 | + | |
| 135 | + if (i == choice) { | |
| 136 | + pathToRun = path; | |
| 137 | + | |
| 138 | + } | |
| 139 | + i++; | |
| 140 | + } | |
| 141 | + system(pathToRun.c_str()); | |
| 142 | + } | |
| 143 | + } while (choice != exit_id); | |
| 83 | 144 | sqlite3_close(database); |
| 84 | - system(gamePath.c_str()); | |
| 85 | - return 0; | |
| 145 | + return EXIT_SUCCESS; | |
| 86 | 146 | } |
| \ No newline at end of file | ||
| @@ -1,18 +1,27 @@ | |||
| 1 | +#include "ftxui/dom/elements.hpp" | ||
| 2 | +#include "ftxui/screen/screen.hpp" | ||
| 3 | +#include "ftxui/screen/string.hpp" | ||
| 4 | +#include "ftxui/component/component.hpp" | ||
| 5 | +#include "ftxui/component/component_options.hpp" | ||
| 6 | +#include "ftxui/component/screen_interactive.hpp" | ||
| 7 | + | ||
| 1 | #include <iostream> | 8 | #include <iostream> |
| 2 | #include <string> | 9 | #include <string> |
| 3 | #include <cstdlib> | 10 | #include <cstdlib> |
| 4 | #include <filesystem> | 11 | #include <filesystem> |
| 5 | -#include <../include/sqlite3.h> | 12 | +#include <sqlite3.h> |
| 13 | +#include <map> | ||
| 14 | + | ||
| 6 | 15 | ||
| 7 | -std::string gamePath; | 16 | +using namespace ftxui; |
| 17 | + | ||
| 18 | +std::map<std::string, std::string> games; | ||
| 8 | 19 | ||
| 9 | std::string database_initialization_command = "CREATE TABLE GAME(" | 20 | std::string database_initialization_command = "CREATE TABLE GAME(" |
| 10 | "GAME_ID INT PRIMARY KEY NOT NULL, " | 21 | "GAME_ID INT PRIMARY KEY NOT NULL, " |
| 11 | "GAME_NAME TEXT NOT NULL, " | 22 | "GAME_NAME TEXT NOT NULL, " |
| 12 | "GAME_PATH TEXT NOT NULL);"; | 23 | "GAME_PATH TEXT NOT NULL);"; |
| 13 | 24 | ||
| 14 | -std::string insert_example_game_command = "INSERT INTO GAME (GAME_ID, GAME_NAME, GAME_PATH) VALUES (1, 'Devastating Fog', \"\");"; | ||
| 15 | - | ||
| 16 | const char* select_all_games_command = "SELECT * FROM GAME;"; | 25 | const char* select_all_games_command = "SELECT * FROM GAME;"; |
| 17 | 26 | ||
| 18 | bool debugRun = true; | 27 | bool debugRun = true; |
| @@ -26,28 +35,37 @@ void printMessage(std::string message) { | |||
| 26 | void execute_sql_command(sqlite3* database, std::string command) { | 35 | void execute_sql_command(sqlite3* database, std::string command) { |
| 27 | int exit = 0; | 36 | int exit = 0; |
| 28 | char* messageError; | 37 | char* messageError; |
| 29 | - exit = sqlite3_exec(database, database_initialization_command.c_str(), NULL, 0, &messageError); | 38 | + exit = sqlite3_exec(database, command.c_str(), NULL, 0, &messageError); |
| 30 | 39 | ||
| 31 | if (exit != SQLITE_OK) { | 40 | if (exit != SQLITE_OK) { |
| 32 | - printMessage("Error with command: " + command); | 41 | + printMessage("Error with command: " + command + " " + messageError); |
| 33 | sqlite3_free(messageError); | 42 | sqlite3_free(messageError); |
| 34 | } | 43 | } |
| 35 | } | 44 | } |
| 36 | 45 | ||
| 46 | +void addGame(sqlite3* database, std::string name, std::string path) { | ||
| 47 | + static int val = 1; | ||
| 48 | + std::string command = "INSERT INTO GAME (GAME_ID, GAME_NAME, GAME_PATH) VALUES ("; | ||
| 49 | + command += std::to_string(val) + ", '" + name + "', \"" + path + "\");"; | ||
| 50 | + val++; | ||
| 51 | + execute_sql_command(database, command); | ||
| 52 | +} | ||
| 53 | + | ||
| 37 | void initialize_database(sqlite3* database) { | 54 | void initialize_database(sqlite3* database) { |
| 38 | - execute_sql_command(database, database_initialization_command.c_str()); | 55 | + execute_sql_command(database, database_initialization_command); |
| 39 | - execute_sql_command(database, insert_example_game_command.c_str()); | 56 | + addGame(database, "Devastating Fog", ""); |
| 57 | + addGame(database, "No Pirates Here!", ""); | ||
| 40 | printMessage("Database Initialized"); | 58 | printMessage("Database Initialized"); |
| 41 | } | 59 | } |
| 42 | 60 | ||
| 43 | int main() { | 61 | int main() { |
| 44 | - bool newCreation = not std::filesystem::exists("example_database"); | 62 | + bool newCreation = not std::filesystem::exists("data.db"); |
| 45 | 63 | ||
| 46 | char* messageError; | 64 | char* messageError; |
| 47 | sqlite3* database; | 65 | sqlite3* database; |
| 48 | sqlite3_stmt* stmt; | 66 | sqlite3_stmt* stmt; |
| 49 | int exit = 0; | 67 | int exit = 0; |
| 50 | - exit = sqlite3_open("example_database", &database); | 68 | + exit = sqlite3_open("data.db", &database); |
| 51 | 69 | ||
| 52 | if (exit) { | 70 | if (exit) { |
| 53 | std::cerr << "Error opening database" << sqlite3_errmsg(database) << std::endl; | 71 | std::cerr << "Error opening database" << sqlite3_errmsg(database) << std::endl; |
| @@ -55,8 +73,6 @@ int main() { | |||
| 55 | } | 73 | } |
| 56 | 74 | ||
| 57 | std::cout << "Opened database successfully!" << std::endl; | 75 | std::cout << "Opened database successfully!" << std::endl; |
| 58 | - | ||
| 59 | - | ||
| 60 | 76 | ||
| 61 | if (newCreation) { | 77 | if (newCreation) { |
| 62 | initialize_database(database); | 78 | initialize_database(database); |
| @@ -72,15 +88,59 @@ int main() { | |||
| 72 | 88 | ||
| 73 | while (sqlite3_step(stmt) == SQLITE_ROW) { | 89 | while (sqlite3_step(stmt) == SQLITE_ROW) { |
| 74 | int id = sqlite3_column_int(stmt, 0); | 90 | int id = sqlite3_column_int(stmt, 0); |
| 75 | - const unsigned char* game_name = sqlite3_column_text(stmt, 1); | 91 | + const unsigned char* gameName = sqlite3_column_text(stmt, 1); |
| 76 | - const unsigned char* path = sqlite3_column_text(stmt, 2); | 92 | + const unsigned char* gamePath = sqlite3_column_text(stmt, 2); |
| 77 | 93 | ||
| 78 | - std::cout << game_name << ": " << path << std::endl; | 94 | + std::cout << gameName << ": " << gamePath << std::endl; |
| 79 | - gamePath.append(reinterpret_cast<const char*>(path)); | 95 | + std::string name{reinterpret_cast<const char*>(gameName)}; |
| 96 | + std::string path{reinterpret_cast<const char*>(gamePath)}; | ||
| 97 | + games[name] = path; | ||
| 80 | } | 98 | } |
| 81 | sqlite3_finalize(stmt); | 99 | sqlite3_finalize(stmt); |
| 82 | 100 | ||
| 101 | + int exit_id = games.size(); | ||
| 102 | + int choice = 0; | ||
| 103 | + do { | ||
| 104 | + system("clear"); | ||
| 105 | + auto document = vbox({ | ||
| 106 | + center(text(L" Fluffy v0.1 ")), | ||
| 107 | + }); | ||
| 108 | + | ||
| 109 | + document = document | size(WIDTH, LESS_THAN, 120); | ||
| 110 | + | ||
| 111 | + auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); | ||
| 112 | + Render(screen, document); | ||
| 113 | + | ||
| 114 | + std::cout << screen.ToString() << '\0' << std::endl; | ||
| 115 | + | ||
| 116 | + | ||
| 117 | + auto menu_screen = ScreenInteractive::TerminalOutput(); | ||
| 118 | + | ||
| 119 | + std::vector<std::string> localGames = {}; | ||
| 120 | + for (const auto& [name, path] : games) { | ||
| 121 | + localGames.push_back(name); | ||
| 122 | + } | ||
| 123 | + localGames.push_back("Exit"); | ||
| 124 | + | ||
| 125 | + MenuOption option; | ||
| 126 | + option.on_enter = menu_screen.ExitLoopClosure(); | ||
| 127 | + auto menu = Menu(&localGames, &choice, option); | ||
| 128 | + menu_screen.Loop(menu); | ||
| 129 | + | ||
| 130 | + if (choice != exit_id) { | ||
| 131 | + int i{ 0 }; | ||
| 132 | + std::string pathToRun = ""; | ||
| 133 | + for (const auto& [name, path] : games) { | ||
| 134 | + | ||
| 135 | + if (i == choice) { | ||
| 136 | + pathToRun = path; | ||
| 137 | + | ||
| 138 | + } | ||
| 139 | + i++; | ||
| 140 | + } | ||
| 141 | + system(pathToRun.c_str()); | ||
| 142 | + } | ||
| 143 | + } while (choice != exit_id); | ||
| 83 | sqlite3_close(database); | 144 | sqlite3_close(database); |
| 84 | - system(gamePath.c_str()); | 145 | + return EXIT_SUCCESS; |
| 85 | - return 0; | ||
| 86 | } | 146 | } |
| \ No newline at end of file | \ No newline at end of file | ||