From e8c0c460d93d75307b41a73f037200339d435e39 Mon Sep 17 00:00:00 2001 From: lejulien Date: Sat, 10 Jan 2026 21:40:24 +0100 Subject: [PATCH 01/11] Disable selection when patern menu is selected --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 7c1a398..345222f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -172,7 +172,7 @@ int main(int ac, char **av) { mousePos.y / config_json["cell_size"].get()); } // Selection behaviour - if (!edit_ctrl && !play_ctrl) { + if (!edit_ctrl && !play_ctrl && !paterns_ctrl) { if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { sel_pos = snapToGrid(mousePos, cell_size_ctrl); selecting = true; -- 2.49.1 From 24729d11f337ec9b3e3fa839e60a5077ddadbc49 Mon Sep 17 00:00:00 2001 From: lejulien Date: Sat, 10 Jan 2026 21:50:17 +0100 Subject: [PATCH 02/11] Update file headers --- includes/render.hpp | 18 +++++++----------- includes/rules.hpp | 18 +++++++----------- includes/types.hpp | 8 ++++++++ includes/world.hpp | 8 ++++++++ src/main.cpp | 8 ++++++++ src/render.cpp | 18 +++++++----------- src/rules.cpp | 18 +++++++----------- src/world.cpp | 18 +++++++----------- 8 files changed, 59 insertions(+), 55 deletions(-) diff --git a/includes/render.hpp b/includes/render.hpp index 3332b33..60651ab 100644 --- a/includes/render.hpp +++ b/includes/render.hpp @@ -1,14 +1,10 @@ -/* ************************************************************************** */ -/* */ -/* / ) */ -/* render.hpp (\__/) ( ( */ -/* ) ( ) ) */ -/* By: lejulien ={ }= / / */ -/* ) `-------/ / */ -/* Created: 2023/01/09 12:44:54 by lejulien ( / */ -/* Updated: 2023/01/14 16:51:15 by lejulien \ | */ -/* */ -/* ************************************************************************** */ +/* +* File name: render.hpp +* Author: lejulien +* Date created: 10-01-2026 21:54:12 +// Date modified: 10-01-2026 22:00:37 +* ------ +*/ #include "world.hpp" diff --git a/includes/rules.hpp b/includes/rules.hpp index 5ae7bef..cae4c57 100644 --- a/includes/rules.hpp +++ b/includes/rules.hpp @@ -1,14 +1,10 @@ -/* ************************************************************************** */ -/* */ -/* / ) */ -/* rules.hpp (\__/) ( ( */ -/* ) ( ) ) */ -/* By: lejulien ={ }= / / */ -/* ) `-------/ / */ -/* Created: 2023/01/09 12:16:47 by lejulien ( / */ -/* Updated: 2023/01/14 16:47:04 by lejulien \ | */ -/* */ -/* ************************************************************************** */ +/* +* File name: rules.hpp +* Author: lejulien +* Date created: 09-01-2026 23:59:55 +* Date modified: 10-01-2026 21:49:44 +* ------ +*/ #include "world.hpp" diff --git a/includes/types.hpp b/includes/types.hpp index eec79a2..1e4f043 100644 --- a/includes/types.hpp +++ b/includes/types.hpp @@ -1,3 +1,11 @@ +/* +* File name: types.hpp +* Author: lejulien +* Date created: 09-01-2026 23:59:55 +* Date modified: 10-01-2026 21:49:36 +* ------ +*/ + #pragma once enum class MenuState { diff --git a/includes/world.hpp b/includes/world.hpp index ec97798..a84b404 100644 --- a/includes/world.hpp +++ b/includes/world.hpp @@ -1,3 +1,11 @@ +/* +* File name: world.hpp +* Author: lejulien +* Date created: 09-01-2026 23:59:55 +* Date modified: 10-01-2026 21:49:31 +* ------ +*/ + #include #include #include diff --git a/src/main.cpp b/src/main.cpp index 345222f..24a8526 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,3 +1,11 @@ +/* +* File name: main.cpp +* Author: lejulien +* Date created: 10-01-2026 21:59:32 +// Date modified: 10-01-2026 21:59:38 +* ------ +*/ + #include #include #include diff --git a/src/render.cpp b/src/render.cpp index f74fa19..6f2a9fa 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -1,14 +1,10 @@ -/* ************************************************************************** */ -/* */ -/* / ) */ -/* render.cpp (\__/) ( ( */ -/* ) ( ) ) */ -/* By: lejulien ={ }= / / */ -/* ) `-------/ / */ -/* Created: 2023/01/09 12:44:30 by lejulien ( / */ -/* Updated: 2023/01/14 17:02:00 by lejulien \ | */ -/* */ -/* ************************************************************************** */ +/* +* File name: render.cpp +* Author: lejulien +* Date created: 10-01-2026 21:49:04 +// Date modified: 10-01-2026 21:59:56 +* ------ +*/ #include "../includes/render.hpp" diff --git a/src/rules.cpp b/src/rules.cpp index e9c0298..55beb2f 100644 --- a/src/rules.cpp +++ b/src/rules.cpp @@ -1,14 +1,10 @@ -/* ************************************************************************** */ -/* */ -/* / ) */ -/* rules.cpp (\__/) ( ( */ -/* ) ( ) ) */ -/* By: lejulien ={ }= / / */ -/* ) `-------/ / */ -/* Created: 2023/01/09 12:18:36 by lejulien ( / */ -/* Updated: 2023/01/14 16:47:01 by lejulien \ | */ -/* */ -/* ************************************************************************** */ +/* +* File name: rules.cpp +* Author: lejulien +* Date created: 10-01-2026 21:49:14 +// Date modified: 10-01-2026 22:00:16 +* ------ +*/ #include "../includes/rules.hpp" #include "../includes/world.hpp" diff --git a/src/world.cpp b/src/world.cpp index 3752280..f737eec 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,14 +1,10 @@ -/* ************************************************************************** */ -/* */ -/* / ) */ -/* world.cpp (\__/) ( ( */ -/* ) ( ) ) */ -/* By: lejulien ={ }= / / */ -/* ) `-------/ / */ -/* Created: 2023/01/09 12:25:55 by lejulien ( / */ -/* Updated: 2023/01/14 17:06:54 by lejulien \ | */ -/* */ -/* ************************************************************************** */ +/* +* File name: world.cpp +* Author: lejulien +* Date created: 09-01-2026 23:59:55 +// Date modified: 10-01-2026 22:00:23 +* ------ +*/ #include "../includes/world.hpp" -- 2.49.1 From 8aee4cdc535c19568cfc37193e1c68ce238b1ffa Mon Sep 17 00:00:00 2001 From: lejulien Date: Sat, 10 Jan 2026 22:40:17 +0100 Subject: [PATCH 03/11] Adding new context with world & config_json --- includes/context.hpp | 24 ++++++++ includes/control_menu.hpp | 39 ++++++++++++ src/control_menu.cpp | 17 +++++ src/main.cpp | 126 +++++++++++++++++++------------------- 4 files changed, 144 insertions(+), 62 deletions(-) create mode 100644 includes/context.hpp create mode 100644 includes/control_menu.hpp create mode 100644 src/control_menu.cpp diff --git a/includes/context.hpp b/includes/context.hpp new file mode 100644 index 0000000..f2d915c --- /dev/null +++ b/includes/context.hpp @@ -0,0 +1,24 @@ +/* +* File name: context.hpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 10-01-2026 22:24:41 +* ------ +*/ + +#pragma once + +#include + +#include + +#include + +namespace gol { + +typedef struct ctx { + std::shared_ptr world = nullptr; + nlohmann::json config_json; +} ctx; + +} // namespace gol diff --git a/includes/control_menu.hpp b/includes/control_menu.hpp new file mode 100644 index 0000000..f673c6a --- /dev/null +++ b/includes/control_menu.hpp @@ -0,0 +1,39 @@ +/* +* File name: control_menu.hpp +* Author: lejulien +* Date created: 10-01-2026 22:00:33 +// Date modified: 10-01-2026 22:18:25 +* ------ +*/ + +#pragma once + +#include + +namespace gol { + +class ControlMenu { +public: + ControlMenu(ctx context); + ~ControlMenu() = default; + void update(); + void display(); +private: + ctx context_; + int fps_ctrl_ = false; + int cell_size_ctrl_ = false; + bool play_ctrl_ = true; + bool step_ctrl_ = false; + bool step_back_ctrl_ = false; + bool rand_ctrl_ = false; + bool edit_ctrl_ = false; + bool clear_ctrl_ = false; + bool settings_window_ = false; + bool paterns_ctrl_ = false; + int width_ctrl_ = false; + int height_ctrl_ = false; + bool dark_theme_ctrl_ = false; + bool apply_ctrl_ = false; +}; + +} // namespace gol diff --git a/src/control_menu.cpp b/src/control_menu.cpp new file mode 100644 index 0000000..e09bd0b --- /dev/null +++ b/src/control_menu.cpp @@ -0,0 +1,17 @@ +/* +* File name: control_menu.cpp +* Author: lejulien +* Date created: 10-01-2026 22:12:44 +// Date modified: 10-01-2026 22:21:20 +* ------ +*/ + +#include + +namespace gol { + +ControlMenu::ControlMenu(ctx context):context_(context) { + // TODO: load content from json +} + +} // namespace gol diff --git a/src/main.cpp b/src/main.cpp index 24a8526..afff289 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ * File name: main.cpp * Author: lejulien * Date created: 10-01-2026 21:59:32 -// Date modified: 10-01-2026 21:59:38 +// Date modified: 10-01-2026 22:39:36 * ------ */ @@ -12,14 +12,15 @@ #include #include -#include "../includes/render.hpp" -#include "../includes/rules.hpp" -#include "../includes/world.hpp" -#include "../includes/types.hpp" -#include "imgui.h" -#include "raylib.h" -#include "rlImGui.h" +#include +#include +#include +#include +#include +#include +#include +#include Vector2 snapToGrid(Vector2 screen, int cell_size) { return {static_cast(round(screen.x / cell_size) * cell_size), @@ -32,9 +33,9 @@ Vector2i screenToGrid(Vector2 screen, int cell_size) { } int main(int ac, char **av) { + gol::ctx context; // Load or default config const std::string config_file_name = "config.json"; - nlohmann::json config_json; MenuState menu_state = MenuState::NONE; std::fstream config_file(config_file_name, std::ios::in | std::ios::out); @@ -55,7 +56,7 @@ int main(int ac, char **av) { // Try reading the configuration try { config_file.seekg(0); - config_file >> config_json; + config_file >> context.config_json; } catch (const nlohmann::json::parse_error &e) { std::cerr << "An error occured while loading config : " << e.what() << std::endl; @@ -66,49 +67,50 @@ int main(int ac, char **av) { config_file.close(); // Check config values or populate them - if (!config_json.contains("cell_size") || - (config_json["cell_size"] < 4 || config_json["cell_size"] > 100)) { - config_json["cell_size"] = 10; + if (!context.config_json.contains("cell_size") || + (context.config_json["cell_size"] < 4 || context.config_json["cell_size"] > 100)) { + context.config_json["cell_size"] = 10; } - if (!config_json.contains("screen_width") || - (config_json["screen_width"] < 800 || - config_json["screen_width"] > 1920)) { - config_json["screen_width"] = 800; + if (!context.config_json.contains("screen_width") || + (context.config_json["screen_width"] < 800 || + context.config_json["screen_width"] > 1920)) { + context.config_json["screen_width"] = 800; } - if (!config_json.contains("screen_height") || - (config_json["screen_height"] < 600 || - config_json["screen_height"] > 1200)) { - config_json["screen_height"] = 600; + if (!context.config_json.contains("screen_height") || + (context.config_json["screen_height"] < 600 || + context.config_json["screen_height"] > 1200)) { + context.config_json["screen_height"] = 600; } - if (!config_json.contains("dark_theme")) { - config_json["dark_theme"] = true; + if (!context.config_json.contains("dark_theme")) { + context.config_json["dark_theme"] = true; } - if (!config_json.contains("fps") || - (config_json["fps"] < 0 || config_json["fps"] > 30)) { - config_json["fps"] = 800; + if (!context.config_json.contains("fps") || + (context.config_json["fps"] < 0 || context.config_json["fps"] > 30)) { + context.config_json["fps"] = 800; } - InitWindow(config_json["screen_width"], config_json["screen_height"], + InitWindow(context.config_json["screen_width"], context.config_json["screen_height"], &av[0][2]); SetTargetFPS(60); - rlImGuiSetup(config_json["dark_theme"]); + rlImGuiSetup(context.config_json["dark_theme"]); // Selection window RenderTexture2D selectionTexture = LoadRenderTexture(200, 200); // Initialize objects - World world(config_json["screen_width"].get() / - config_json["cell_size"].get(), - config_json["screen_height"].get() / - config_json["cell_size"].get()); + context.world = std::make_shared( + context.config_json["screen_width"].get() / + context.config_json["cell_size"].get(), + context.config_json["screen_height"].get() / + context.config_json["cell_size"].get()); Rules rules = Rules(); - Render render(config_json["cell_size"]); + Render render(context.config_json["cell_size"]); // Imgui control menu - int fps_ctrl = config_json["fps"].get(); - int cell_size_ctrl = config_json["cell_size"].get(); + int fps_ctrl = context.config_json["fps"].get(); + int cell_size_ctrl = context.config_json["cell_size"].get(); bool play_ctrl = true; bool step_ctrl = false; bool step_back_ctrl = false; @@ -117,9 +119,9 @@ int main(int ac, char **av) { bool clear_ctrl = false; bool settings_window = false; bool paterns_ctrl = false; - int width_ctrl = config_json["screen_width"].get(); - int height_ctrl = config_json["screen_height"].get(); - bool dark_theme_ctrl = config_json["dark_theme"].get(); + int width_ctrl = context.config_json["screen_width"].get(); + int height_ctrl = context.config_json["screen_height"].get(); + bool dark_theme_ctrl = context.config_json["dark_theme"].get(); bool apply_ctrl = false; // Speed handling values @@ -137,7 +139,7 @@ int main(int ac, char **av) { std::string sel_txt_input_hint("patern name"); // Setups - rules.setup(&world); + rules.setup(&(*context.world)); // Diplay generations while (!WindowShouldClose()) { if (menu_state == MenuState::PLAY || menu_state == MenuState::EDIT) { @@ -153,11 +155,11 @@ int main(int ac, char **av) { auto gesture = GetGestureDetected(); auto mousePos = GetMousePosition(); if (rand_ctrl) { - world.randomize(); + context.world->randomize(); rand_ctrl = false; } if (clear_ctrl) { - world.clear(); + context.world->clear(); clear_ctrl = false; } if (edit_ctrl && play_ctrl) { @@ -176,8 +178,8 @@ int main(int ac, char **av) { if (edit_ctrl && IsMouseButtonPressed(0) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { menu_state = MenuState::EDIT; - world.setCell(mousePos.x / config_json["cell_size"].get(), - mousePos.y / config_json["cell_size"].get()); + context.world->setCell(mousePos.x / context.config_json["cell_size"].get(), + mousePos.y / context.config_json["cell_size"].get()); } // Selection behaviour if (!edit_ctrl && !play_ctrl && !paterns_ctrl) { @@ -201,7 +203,7 @@ int main(int ac, char **av) { }; // Ensure there is at least one cell selected if (!(sel_size.x == 0 || sel_size.y == 0)) { - sel_data = std::move(world.getSelection(orig, sel_size)); + sel_data = std::move(context.world->getSelection(orig, sel_size)); sel_ctrl = true; } } @@ -210,39 +212,39 @@ int main(int ac, char **av) { patern_name[0] = '\0'; } if (step_ctrl) { - world.saveCompressed(); + context.world->saveCompressed(); rules.update(); step_ctrl = false; } if (step_back_ctrl) { - world.stepBack(); + context.world->stepBack(); step_back_ctrl = false; } if (apply_ctrl) { bool resize_needed = false; - config_json["fps"] = fps_ctrl; - if (config_json["screen_width"].get() != width_ctrl || - config_json["screen_height"].get() != height_ctrl) { - config_json["screen_width"] = width_ctrl; - config_json["screen_height"] = height_ctrl; + context.config_json["fps"] = fps_ctrl; + if (context.config_json["screen_width"].get() != width_ctrl || + context.config_json["screen_height"].get() != height_ctrl) { + context.config_json["screen_width"] = width_ctrl; + context.config_json["screen_height"] = height_ctrl; rlImGuiShutdown(); SetWindowSize(width_ctrl, height_ctrl); rlImGuiSetup(dark_theme_ctrl); resize_needed = true; } - if (cell_size_ctrl != config_json["cell_size"].get() || + if (cell_size_ctrl != context.config_json["cell_size"].get() || resize_needed) { - world.resize(config_json["screen_width"].get() / cell_size_ctrl, - config_json["screen_height"].get() / cell_size_ctrl); + context.world->resize(context.config_json["screen_width"].get() / cell_size_ctrl, + context.config_json["screen_height"].get() / cell_size_ctrl); render.updateCellSize(cell_size_ctrl); - rules.newWorld(&world); - config_json["cell_size"] = cell_size_ctrl; + rules.newWorld(&(*context.world)); + context.config_json["cell_size"] = cell_size_ctrl; } - if (dark_theme_ctrl != config_json["dark_theme"]) { + if (dark_theme_ctrl != context.config_json["dark_theme"]) { rlImGuiShutdown(); rlImGuiSetup(dark_theme_ctrl); - config_json["dark_theme"] = dark_theme_ctrl; + context.config_json["dark_theme"] = dark_theme_ctrl; } apply_ctrl = false; settings_window = false; @@ -255,13 +257,13 @@ int main(int ac, char **av) { // Reset accumulator deltaTimeAccumulator -= timePerUpdate; if (menu_state == MenuState::PLAY) { - world.saveCompressed(); + context.world->saveCompressed(); rules.update(); } } BeginDrawing(); ClearBackground(BLACK); - render.display(&world); + render.display(&(*context.world)); if (selecting) { auto grid_mouse = snapToGrid(mousePos, cell_size_ctrl); bool sel_x_less = (sel_pos.x < grid_mouse.x); @@ -296,7 +298,7 @@ int main(int ac, char **av) { if (ImGui::Button((settings_window) ? "Hide settings" : "Show settings")) { settings_window = !settings_window; } - ImGui::Text("Generation: %zu", world.getCycle()); + ImGui::Text("Generation: %zu", context.world->getCycle()); ImGui::End(); if (paterns_ctrl) { ImGuiWindowFlags paterns_flags = @@ -389,7 +391,7 @@ int main(int ac, char **av) { EndDrawing(); } config_file.open(config_file_name, std::ios::out | std::ios::trunc); - config_file << config_json.dump(2); + config_file << context.config_json.dump(2); config_file.close(); // Cleanup Selection texture UnloadRenderTexture(selectionTexture); -- 2.49.1 From 95a7d6ea9a863a0022e55b853b3b9f72565a6d9d Mon Sep 17 00:00:00 2001 From: lejulien Date: Sat, 10 Jan 2026 22:55:53 +0100 Subject: [PATCH 04/11] Adding controls to control_menu --- CMakeLists.txt | 1 + includes/control_menu.hpp | 3 +- src/control_menu.cpp | 19 +++++- src/main.cpp | 138 +++++++++++++++++--------------------- 4 files changed, 82 insertions(+), 79 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5f8e6c9..333ee3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ set(SRC_CXX_FILES "./src/main.cpp" "./src/rules.cpp" "./src/world.cpp" "./src/render.cpp" + "./src/control_menu.cpp" "${rlImGui_SOURCE_DIR}/rlImGui.cpp" "${imgui_SOURCE_DIR}/imgui.cpp" "${imgui_SOURCE_DIR}/imgui_draw.cpp" diff --git a/includes/control_menu.hpp b/includes/control_menu.hpp index f673c6a..1660da7 100644 --- a/includes/control_menu.hpp +++ b/includes/control_menu.hpp @@ -2,7 +2,7 @@ * File name: control_menu.hpp * Author: lejulien * Date created: 10-01-2026 22:00:33 -// Date modified: 10-01-2026 22:18:25 +// Date modified: 10-01-2026 22:45:10 * ------ */ @@ -20,6 +20,7 @@ public: void display(); private: ctx context_; +public: // Keep those public for easy access int fps_ctrl_ = false; int cell_size_ctrl_ = false; bool play_ctrl_ = true; diff --git a/src/control_menu.cpp b/src/control_menu.cpp index e09bd0b..0f10f0d 100644 --- a/src/control_menu.cpp +++ b/src/control_menu.cpp @@ -2,7 +2,7 @@ * File name: control_menu.cpp * Author: lejulien * Date created: 10-01-2026 22:12:44 -// Date modified: 10-01-2026 22:21:20 +// Date modified: 10-01-2026 22:43:36 * ------ */ @@ -11,7 +11,20 @@ namespace gol { ControlMenu::ControlMenu(ctx context):context_(context) { - // TODO: load content from json -} + fps_ctrl_ = context.config_json["fps"].get(); + cell_size_ctrl_ = context.config_json["cell_size"].get(); + play_ctrl_ = true; + step_ctrl_ = false; + step_back_ctrl_ = false; + rand_ctrl_ = false; + edit_ctrl_ = false; + clear_ctrl_ = false; + settings_window_ = false; + paterns_ctrl_ = false; + width_ctrl_ = context.config_json["screen_width"].get(); + height_ctrl_ = context.config_json["screen_height"].get(); + dark_theme_ctrl_ = context.config_json["dark_theme"].get(); + apply_ctrl_ = false; +} } // namespace gol diff --git a/src/main.cpp b/src/main.cpp index afff289..6c7fd67 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ * File name: main.cpp * Author: lejulien * Date created: 10-01-2026 21:59:32 -// Date modified: 10-01-2026 22:39:36 +// Date modified: 10-01-2026 22:55:11 * ------ */ @@ -21,6 +21,7 @@ #include #include #include +#include Vector2 snapToGrid(Vector2 screen, int cell_size) { return {static_cast(round(screen.x / cell_size) * cell_size), @@ -109,20 +110,7 @@ int main(int ac, char **av) { Render render(context.config_json["cell_size"]); // Imgui control menu - int fps_ctrl = context.config_json["fps"].get(); - int cell_size_ctrl = context.config_json["cell_size"].get(); - bool play_ctrl = true; - bool step_ctrl = false; - bool step_back_ctrl = false; - bool rand_ctrl = false; - bool edit_ctrl = false; - bool clear_ctrl = false; - bool settings_window = false; - bool paterns_ctrl = false; - int width_ctrl = context.config_json["screen_width"].get(); - int height_ctrl = context.config_json["screen_height"].get(); - bool dark_theme_ctrl = context.config_json["dark_theme"].get(); - bool apply_ctrl = false; + gol::ControlMenu control_menu(context); // Speed handling values float sim_speed = 1.0f; @@ -143,54 +131,54 @@ int main(int ac, char **av) { // Diplay generations while (!WindowShouldClose()) { if (menu_state == MenuState::PLAY || menu_state == MenuState::EDIT) { - if (!play_ctrl && !edit_ctrl) { + if (!control_menu.play_ctrl_ && !control_menu.edit_ctrl_) { menu_state = MenuState::NONE; } } // Frames shinenigans float deltaTime = GetFrameTime(); - sim_speed = fps_ctrl / 10.0f; + sim_speed = control_menu.fps_ctrl_ / 10.0f; timePerUpdate = (1.0f / 10.0f) / sim_speed; auto gesture = GetGestureDetected(); auto mousePos = GetMousePosition(); - if (rand_ctrl) { + if (control_menu.rand_ctrl_) { context.world->randomize(); - rand_ctrl = false; + control_menu.rand_ctrl_ = false; } - if (clear_ctrl) { + if (control_menu.clear_ctrl_) { context.world->clear(); - clear_ctrl = false; + control_menu.clear_ctrl_ = false; } - if (edit_ctrl && play_ctrl) { + if (control_menu.edit_ctrl_ && control_menu.play_ctrl_) { if (menu_state == MenuState::PLAY) { menu_state = MenuState::EDIT; - play_ctrl = false; + control_menu.play_ctrl_ = false; } else if (menu_state == MenuState::EDIT) { menu_state = MenuState::PLAY; - edit_ctrl = false; + control_menu.edit_ctrl_ = false; } - } else if (play_ctrl) { + } else if (control_menu.play_ctrl_) { menu_state = MenuState::PLAY; - } else if (edit_ctrl) { + } else if (control_menu.edit_ctrl_) { menu_state = MenuState::EDIT; } - if (edit_ctrl && IsMouseButtonPressed(0) && + if (control_menu.edit_ctrl_ && IsMouseButtonPressed(0) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { menu_state = MenuState::EDIT; context.world->setCell(mousePos.x / context.config_json["cell_size"].get(), mousePos.y / context.config_json["cell_size"].get()); } // Selection behaviour - if (!edit_ctrl && !play_ctrl && !paterns_ctrl) { + if (!control_menu.edit_ctrl_ && !control_menu.play_ctrl_ && !control_menu.paterns_ctrl_ && !control_menu.settings_window_) { if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - sel_pos = snapToGrid(mousePos, cell_size_ctrl); + sel_pos = snapToGrid(mousePos, control_menu.cell_size_ctrl_); selecting = true; } - if (ImGui::IsMouseReleased(0) && selecting == true && mousePos.x >=0 && mousePos.x < width_ctrl && mousePos.y >=0 && mousePos.y < height_ctrl ) { + if (ImGui::IsMouseReleased(0) && selecting == true && mousePos.x >=0 && mousePos.x < control_menu.width_ctrl_ && mousePos.y >=0 && mousePos.y < control_menu.height_ctrl_ ) { selecting = false; - Vector2i p1 = screenToGrid(sel_pos, cell_size_ctrl); - Vector2i p2 = screenToGrid(mousePos, cell_size_ctrl); + Vector2i p1 = screenToGrid(sel_pos, control_menu.cell_size_ctrl_); + Vector2i p2 = screenToGrid(mousePos, control_menu.cell_size_ctrl_); // Get origin Vector2i orig = { (p1.x < p2.x)?p1.x:p2.x, @@ -211,43 +199,43 @@ int main(int ac, char **av) { if (!sel_ctrl) { patern_name[0] = '\0'; } - if (step_ctrl) { + if (control_menu.step_ctrl_) { context.world->saveCompressed(); rules.update(); - step_ctrl = false; + control_menu.step_ctrl_ = false; } - if (step_back_ctrl) { + if (control_menu.step_back_ctrl_) { context.world->stepBack(); - step_back_ctrl = false; + control_menu.step_back_ctrl_ = false; } - if (apply_ctrl) { + if (control_menu.apply_ctrl_) { bool resize_needed = false; - context.config_json["fps"] = fps_ctrl; - if (context.config_json["screen_width"].get() != width_ctrl || - context.config_json["screen_height"].get() != height_ctrl) { - context.config_json["screen_width"] = width_ctrl; - context.config_json["screen_height"] = height_ctrl; + context.config_json["fps"] = control_menu.fps_ctrl_; + if (context.config_json["screen_width"].get() != control_menu.width_ctrl_ || + context.config_json["screen_height"].get() != control_menu.height_ctrl_) { + context.config_json["screen_width"] = control_menu.width_ctrl_; + context.config_json["screen_height"] = control_menu.height_ctrl_; rlImGuiShutdown(); - SetWindowSize(width_ctrl, height_ctrl); - rlImGuiSetup(dark_theme_ctrl); + SetWindowSize(control_menu.width_ctrl_, control_menu.height_ctrl_); + rlImGuiSetup(control_menu.dark_theme_ctrl_); resize_needed = true; } - if (cell_size_ctrl != context.config_json["cell_size"].get() || + if (control_menu.cell_size_ctrl_ != context.config_json["cell_size"].get() || resize_needed) { - context.world->resize(context.config_json["screen_width"].get() / cell_size_ctrl, - context.config_json["screen_height"].get() / cell_size_ctrl); - render.updateCellSize(cell_size_ctrl); + context.world->resize(context.config_json["screen_width"].get() / control_menu.cell_size_ctrl_, + context.config_json["screen_height"].get() / control_menu.cell_size_ctrl_); + render.updateCellSize(control_menu.cell_size_ctrl_); rules.newWorld(&(*context.world)); - context.config_json["cell_size"] = cell_size_ctrl; + context.config_json["cell_size"] = control_menu.cell_size_ctrl_; } - if (dark_theme_ctrl != context.config_json["dark_theme"]) { + if (control_menu.dark_theme_ctrl_ != context.config_json["dark_theme"]) { rlImGuiShutdown(); - rlImGuiSetup(dark_theme_ctrl); - context.config_json["dark_theme"] = dark_theme_ctrl; + rlImGuiSetup(control_menu.dark_theme_ctrl_); + context.config_json["dark_theme"] = control_menu.dark_theme_ctrl_; } - apply_ctrl = false; - settings_window = false; + control_menu.apply_ctrl_ = false; + control_menu.settings_window_ = false; } // Accumulate time and update simulation at the adjusted speed @@ -265,7 +253,7 @@ int main(int ac, char **av) { ClearBackground(BLACK); render.display(&(*context.world)); if (selecting) { - auto grid_mouse = snapToGrid(mousePos, cell_size_ctrl); + auto grid_mouse = snapToGrid(mousePos, control_menu.cell_size_ctrl_); bool sel_x_less = (sel_pos.x < grid_mouse.x); bool sel_y_less = (sel_pos.y < grid_mouse.y); DrawRectangleLines(((sel_x_less)? sel_pos.x: grid_mouse.x), ((sel_y_less)? sel_pos.y: grid_mouse.y), @@ -282,43 +270,43 @@ int main(int ac, char **av) { ImVec2 menu_pos(3, 3); ImGui::SetNextWindowPos(menu_pos, ImGuiCond_Always); ImGui::Begin("Control Panel", &control_panel_open, control_panel_flags); - ImGui::Checkbox("Play", &play_ctrl); + ImGui::Checkbox("Play", &control_menu.play_ctrl_); if (ImGui::Button("Step")) { - step_ctrl = true; + control_menu.step_ctrl_ = true; } if (ImGui::Button("Step Back")) { - step_back_ctrl = true; + control_menu.step_back_ctrl_ = true; } - ImGui::Checkbox("Edit", &edit_ctrl); - ImGui::Checkbox("Clear", &clear_ctrl); - ImGui::Checkbox("Randomize", &rand_ctrl); - if (ImGui::Button((paterns_ctrl) ? "Hide paterns" : "Show paterns")) { - paterns_ctrl = !paterns_ctrl; + ImGui::Checkbox("Edit", &control_menu.edit_ctrl_); + ImGui::Checkbox("Clear", &control_menu.clear_ctrl_); + ImGui::Checkbox("Randomize", &control_menu.rand_ctrl_); + if (ImGui::Button((control_menu.paterns_ctrl_) ? "Hide paterns" : "Show paterns")) { + control_menu.paterns_ctrl_ = !control_menu.paterns_ctrl_; } - if (ImGui::Button((settings_window) ? "Hide settings" : "Show settings")) { - settings_window = !settings_window; + if (ImGui::Button((control_menu.settings_window_) ? "Hide settings" : "Show settings")) { + control_menu.settings_window_ = !control_menu.settings_window_; } ImGui::Text("Generation: %zu", context.world->getCycle()); ImGui::End(); - if (paterns_ctrl) { + if (control_menu.paterns_ctrl_) { ImGuiWindowFlags paterns_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; ImGui::SetNextWindowSize(ImVec2(150, 200), ImGuiCond_Always); - ImGui::Begin("paterns", &paterns_ctrl, paterns_flags); + ImGui::Begin("paterns", &control_menu.paterns_ctrl_, paterns_flags); ImGui::Button("refresh"); ImGui::End(); } - if (settings_window) { + if (control_menu.settings_window_) { ImGuiWindowFlags settings_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; - ImGui::Begin("Settings", &settings_window, settings_flags); - ImGui::SliderInt("Window Width", &width_ctrl, 800, 1920); - ImGui::SliderInt("Window Height", &height_ctrl, 600, 1200); - ImGui::SliderInt("FPS", &fps_ctrl, 0, 30); - ImGui::SliderInt("Cell Size", &cell_size_ctrl, 4, 100); - ImGui::Checkbox("Dark Theme", &dark_theme_ctrl); + ImGui::Begin("Settings", &control_menu.settings_window_, settings_flags); + ImGui::SliderInt("Window Width", &control_menu.width_ctrl_, 800, 1920); + ImGui::SliderInt("Window Height", &control_menu.height_ctrl_, 600, 1200); + ImGui::SliderInt("FPS", &control_menu.fps_ctrl_, 0, 30); + ImGui::SliderInt("Cell Size", &control_menu.cell_size_ctrl_, 4, 100); + ImGui::Checkbox("Dark Theme", &control_menu.dark_theme_ctrl_); if (ImGui::Button("Save & Apply")) { - apply_ctrl = true; + control_menu.apply_ctrl_ = true; } ImGui::End(); } -- 2.49.1 From c00c43038229a5745a26b4c04721f8e015193cbe Mon Sep 17 00:00:00 2001 From: lejulien Date: Mon, 12 Jan 2026 15:44:04 +0100 Subject: [PATCH 05/11] world: Use context at contruction to simplify it's call --- includes/context.hpp | 2 +- includes/world.hpp | 5 +++-- src/main.cpp | 6 +----- src/world.cpp | 8 ++++++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/includes/context.hpp b/includes/context.hpp index f2d915c..3075bb2 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -12,7 +12,7 @@ #include -#include +class World; namespace gol { diff --git a/includes/world.hpp b/includes/world.hpp index a84b404..668609d 100644 --- a/includes/world.hpp +++ b/includes/world.hpp @@ -13,7 +13,8 @@ #include #include -#include "../includes/types.hpp" +#include +#include #pragma once @@ -22,7 +23,7 @@ class World { public: - World(int width, int height); + World(gol::ctx &ctx); ~World(); std::vector *getWorldData(); diff --git a/src/main.cpp b/src/main.cpp index 6c7fd67..45f8a3f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -101,11 +101,7 @@ int main(int ac, char **av) { RenderTexture2D selectionTexture = LoadRenderTexture(200, 200); // Initialize objects - context.world = std::make_shared( - context.config_json["screen_width"].get() / - context.config_json["cell_size"].get(), - context.config_json["screen_height"].get() / - context.config_json["cell_size"].get()); + context.world = std::make_shared(context); Rules rules = Rules(); Render render(context.config_json["cell_size"]); diff --git a/src/world.cpp b/src/world.cpp index f737eec..3e371e0 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -12,9 +12,13 @@ // Constructor and destructor -World::World(int width, int height) : _width(width), _height(height) { +World::World(gol::ctx &context) { + _width = context.config_json["screen_width"].get() / + context.config_json["cell_size"].get(); + _height = context.config_json["screen_height"].get() / + context.config_json["cell_size"].get(); // create world data - this->_data = new std::vector(width * height, false); + this->_data = new std::vector(_width * _height, false); } World::~World() { delete this->_data; } -- 2.49.1 From 9e2e7b562dc171844d1423b874a7897bbae1bf67 Mon Sep 17 00:00:00 2001 From: lejulien Date: Mon, 12 Jan 2026 16:29:12 +0100 Subject: [PATCH 06/11] control_menu: Move processing and display code into it's correspondind methods --- includes/control_menu.hpp | 2 ++ src/control_menu.cpp | 60 +++++++++++++++++++++++++++++++++++++++ src/main.cpp | 60 ++++----------------------------------- 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/includes/control_menu.hpp b/includes/control_menu.hpp index 1660da7..2aa0c2e 100644 --- a/includes/control_menu.hpp +++ b/includes/control_menu.hpp @@ -9,6 +9,7 @@ #pragma once #include +#include namespace gol { @@ -21,6 +22,7 @@ public: private: ctx context_; public: // Keep those public for easy access + MenuState menu_state_ = MenuState::NONE; int fps_ctrl_ = false; int cell_size_ctrl_ = false; bool play_ctrl_ = true; diff --git a/src/control_menu.cpp b/src/control_menu.cpp index 0f10f0d..dfb3fc5 100644 --- a/src/control_menu.cpp +++ b/src/control_menu.cpp @@ -6,7 +6,12 @@ * ------ */ +#include +#include +#include + #include +#include namespace gol { @@ -27,4 +32,59 @@ ControlMenu::ControlMenu(ctx context):context_(context) { apply_ctrl_ = false; } +void ControlMenu::update() { + if (menu_state_ == MenuState::PLAY || menu_state_ == MenuState::EDIT) { + if (!play_ctrl_ && !edit_ctrl_) { + menu_state_ = MenuState::NONE; + } + } + if (rand_ctrl_) { + context_.world->randomize(); + rand_ctrl_ = false; + } + if (clear_ctrl_) { + context_.world->clear(); + clear_ctrl_ = false; + } + if (edit_ctrl_ && play_ctrl_) { + if (menu_state_ == MenuState::PLAY) { + menu_state_ = MenuState::EDIT; + play_ctrl_ = false; + } else if (menu_state_ == MenuState::EDIT) { + menu_state_ = MenuState::PLAY; + edit_ctrl_ = false; + } + } else if (play_ctrl_) { + menu_state_ = MenuState::PLAY; + } else if (edit_ctrl_) { + menu_state_ = MenuState::EDIT; + } +} + +void ControlMenu::display() { + bool control_panel_open = true; + ImGuiWindowFlags control_panel_flags = ImGuiWindowFlags_AlwaysAutoResize | + ImGuiWindowFlags_NoResize; + ImVec2 menu_pos(3, 3); + ImGui::SetNextWindowPos(menu_pos, ImGuiCond_Always); + ImGui::Begin("Control Panel", &control_panel_open, control_panel_flags); + ImGui::Checkbox("Play", &play_ctrl_); + if (ImGui::Button("Step")) { + step_ctrl_ = true; + } + if (ImGui::Button("Step Back")) { + step_back_ctrl_ = true; + } + ImGui::Checkbox("Edit", &edit_ctrl_); + ImGui::Checkbox("Clear", &clear_ctrl_); + ImGui::Checkbox("Randomize", &rand_ctrl_); + if (ImGui::Button((paterns_ctrl_) ? "Hide paterns" : "Show paterns")) { + paterns_ctrl_ = !paterns_ctrl_; + } + if (ImGui::Button((settings_window_) ? "Hide settings" : "Show settings")) { + settings_window_ = !settings_window_; + } + ImGui::Text("Generation: %zu", context_.world->getCycle()); + ImGui::End();} + } // namespace gol diff --git a/src/main.cpp b/src/main.cpp index 45f8a3f..cbbaa43 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -37,7 +37,6 @@ int main(int ac, char **av) { gol::ctx context; // Load or default config const std::string config_file_name = "config.json"; - MenuState menu_state = MenuState::NONE; std::fstream config_file(config_file_name, std::ios::in | std::ios::out); @@ -126,45 +125,22 @@ int main(int ac, char **av) { rules.setup(&(*context.world)); // Diplay generations while (!WindowShouldClose()) { - if (menu_state == MenuState::PLAY || menu_state == MenuState::EDIT) { - if (!control_menu.play_ctrl_ && !control_menu.edit_ctrl_) { - menu_state = MenuState::NONE; - } - } // Frames shinenigans float deltaTime = GetFrameTime(); sim_speed = control_menu.fps_ctrl_ / 10.0f; timePerUpdate = (1.0f / 10.0f) / sim_speed; + control_menu.update(); + auto gesture = GetGestureDetected(); auto mousePos = GetMousePosition(); - if (control_menu.rand_ctrl_) { - context.world->randomize(); - control_menu.rand_ctrl_ = false; - } - if (control_menu.clear_ctrl_) { - context.world->clear(); - control_menu.clear_ctrl_ = false; - } - if (control_menu.edit_ctrl_ && control_menu.play_ctrl_) { - if (menu_state == MenuState::PLAY) { - menu_state = MenuState::EDIT; - control_menu.play_ctrl_ = false; - } else if (menu_state == MenuState::EDIT) { - menu_state = MenuState::PLAY; - control_menu.edit_ctrl_ = false; - } - } else if (control_menu.play_ctrl_) { - menu_state = MenuState::PLAY; - } else if (control_menu.edit_ctrl_) { - menu_state = MenuState::EDIT; - } if (control_menu.edit_ctrl_ && IsMouseButtonPressed(0) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - menu_state = MenuState::EDIT; + control_menu.menu_state_ = MenuState::EDIT; context.world->setCell(mousePos.x / context.config_json["cell_size"].get(), mousePos.y / context.config_json["cell_size"].get()); } + // Selection behaviour if (!control_menu.edit_ctrl_ && !control_menu.play_ctrl_ && !control_menu.paterns_ctrl_ && !control_menu.settings_window_) { if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { @@ -240,7 +216,7 @@ int main(int ac, char **av) { if (deltaTimeAccumulator >= timePerUpdate) { // Reset accumulator deltaTimeAccumulator -= timePerUpdate; - if (menu_state == MenuState::PLAY) { + if (control_menu.menu_state_ == MenuState::PLAY) { context.world->saveCompressed(); rules.update(); } @@ -259,31 +235,7 @@ int main(int ac, char **av) { } // Start ImGui frame rlImGuiBegin(); - - bool control_panel_open = true; - ImGuiWindowFlags control_panel_flags = ImGuiWindowFlags_AlwaysAutoResize | - ImGuiWindowFlags_NoResize; - ImVec2 menu_pos(3, 3); - ImGui::SetNextWindowPos(menu_pos, ImGuiCond_Always); - ImGui::Begin("Control Panel", &control_panel_open, control_panel_flags); - ImGui::Checkbox("Play", &control_menu.play_ctrl_); - if (ImGui::Button("Step")) { - control_menu.step_ctrl_ = true; - } - if (ImGui::Button("Step Back")) { - control_menu.step_back_ctrl_ = true; - } - ImGui::Checkbox("Edit", &control_menu.edit_ctrl_); - ImGui::Checkbox("Clear", &control_menu.clear_ctrl_); - ImGui::Checkbox("Randomize", &control_menu.rand_ctrl_); - if (ImGui::Button((control_menu.paterns_ctrl_) ? "Hide paterns" : "Show paterns")) { - control_menu.paterns_ctrl_ = !control_menu.paterns_ctrl_; - } - if (ImGui::Button((control_menu.settings_window_) ? "Hide settings" : "Show settings")) { - control_menu.settings_window_ = !control_menu.settings_window_; - } - ImGui::Text("Generation: %zu", context.world->getCycle()); - ImGui::End(); + control_menu.display(); if (control_menu.paterns_ctrl_) { ImGuiWindowFlags paterns_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; -- 2.49.1 From 24d8a092e482f47dccf4871d8e3d369591c8f081 Mon Sep 17 00:00:00 2001 From: lejulien Date: Mon, 12 Jan 2026 20:43:50 +0100 Subject: [PATCH 07/11] control_menu: Add rules related updates --- includes/context.hpp | 4 +++- src/control_menu.cpp | 12 +++++++++++- src/main.cpp | 19 +++++-------------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/includes/context.hpp b/includes/context.hpp index 3075bb2..c03587c 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -2,7 +2,7 @@ * File name: context.hpp * Author: lejulien * Date created: 01-01-1970 00:59:59 -// Date modified: 10-01-2026 22:24:41 +// Date modified: 12-01-2026 20:31:50 * ------ */ @@ -13,11 +13,13 @@ #include class World; +class Rules; namespace gol { typedef struct ctx { std::shared_ptr world = nullptr; + std::shared_ptr rules = nullptr; nlohmann::json config_json; } ctx; diff --git a/src/control_menu.cpp b/src/control_menu.cpp index dfb3fc5..f9aa76b 100644 --- a/src/control_menu.cpp +++ b/src/control_menu.cpp @@ -2,7 +2,7 @@ * File name: control_menu.cpp * Author: lejulien * Date created: 10-01-2026 22:12:44 -// Date modified: 10-01-2026 22:43:36 +// Date modified: 12-01-2026 20:36:39 * ------ */ @@ -12,6 +12,7 @@ #include #include +#include namespace gol { @@ -59,6 +60,15 @@ void ControlMenu::update() { } else if (edit_ctrl_) { menu_state_ = MenuState::EDIT; } + if (step_ctrl_) { + context_.world->saveCompressed(); + context_.rules->update(); + step_ctrl_ = false; + } + if (step_back_ctrl_) { + context_.world->stepBack(); + step_back_ctrl_ = false; + } } void ControlMenu::display() { diff --git a/src/main.cpp b/src/main.cpp index cbbaa43..cb95fde 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ * File name: main.cpp * Author: lejulien * Date created: 10-01-2026 21:59:32 -// Date modified: 10-01-2026 22:55:11 +// Date modified: 12-01-2026 20:34:37 * ------ */ @@ -101,7 +101,7 @@ int main(int ac, char **av) { // Initialize objects context.world = std::make_shared(context); - Rules rules = Rules(); + context.rules = std::make_shared(); Render render(context.config_json["cell_size"]); // Imgui control menu @@ -122,7 +122,7 @@ int main(int ac, char **av) { std::string sel_txt_input_hint("patern name"); // Setups - rules.setup(&(*context.world)); + context.rules->setup(&(*context.world)); // Diplay generations while (!WindowShouldClose()) { // Frames shinenigans @@ -171,15 +171,6 @@ int main(int ac, char **av) { if (!sel_ctrl) { patern_name[0] = '\0'; } - if (control_menu.step_ctrl_) { - context.world->saveCompressed(); - rules.update(); - control_menu.step_ctrl_ = false; - } - if (control_menu.step_back_ctrl_) { - context.world->stepBack(); - control_menu.step_back_ctrl_ = false; - } if (control_menu.apply_ctrl_) { bool resize_needed = false; @@ -198,7 +189,7 @@ int main(int ac, char **av) { context.world->resize(context.config_json["screen_width"].get() / control_menu.cell_size_ctrl_, context.config_json["screen_height"].get() / control_menu.cell_size_ctrl_); render.updateCellSize(control_menu.cell_size_ctrl_); - rules.newWorld(&(*context.world)); + context.rules->newWorld(&(*context.world)); context.config_json["cell_size"] = control_menu.cell_size_ctrl_; } if (control_menu.dark_theme_ctrl_ != context.config_json["dark_theme"]) { @@ -218,7 +209,7 @@ int main(int ac, char **av) { deltaTimeAccumulator -= timePerUpdate; if (control_menu.menu_state_ == MenuState::PLAY) { context.world->saveCompressed(); - rules.update(); + context.rules->update(); } } BeginDrawing(); -- 2.49.1 From 416d3a2be9af71b63aa585743f4f5f74b150e321 Mon Sep 17 00:00:00 2001 From: lejulien Date: Mon, 12 Jan 2026 21:34:41 +0100 Subject: [PATCH 08/11] settings_menu: Create a dedicated class for the settings --- CMakeLists.txt | 63 ++++++++++--------- includes/context.hpp | 6 +- includes/control_menu.hpp | 15 ++--- includes/render.hpp | 6 +- includes/rules.hpp | 8 +-- includes/settings_menu.hpp | 46 ++++++++++++++ includes/world.hpp | 6 +- src/control_menu.cpp | 28 ++++----- src/main.cpp | 125 +++++++++++++------------------------ src/render.cpp | 4 +- src/rules.cpp | 6 +- src/settings_menu.cpp | 122 ++++++++++++++++++++++++++++++++++++ src/world.cpp | 12 ++-- 13 files changed, 286 insertions(+), 161 deletions(-) create mode 100644 includes/settings_menu.hpp create mode 100644 src/settings_menu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 333ee3b..77d5bf7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,11 +8,11 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(WIN32) - set(IMGUI_BACKEND "imgui_impl_dx11.cpp") # DirectX 11 for Windows + set(IMGUI_BACKEND "imgui_impl_dx11.cpp") # DirectX 11 for Windows elseif(APPLE) - set(IMGUI_BACKEND "imgui_impl_metal.mm") # Metal for macOS + set(IMGUI_BACKEND "imgui_impl_metal.mm") # Metal for macOS elseif(UNIX) - set(IMGUI_BACKEND "imgui_impl_opengl3.cpp") # OpenGL for Linux + set(IMGUI_BACKEND "imgui_impl_opengl3.cpp") # OpenGL for Linux endif() # includes @@ -21,25 +21,25 @@ include_directories(./includes) # raylib include(FetchContent) FetchContent_Declare( - raylib - GIT_REPOSITORY https://github.com/raysan5/raylib.git - GIT_TAG 5.5 - GIT_SHALLOW 1 + raylib + GIT_REPOSITORY https://github.com/raysan5/raylib.git + GIT_TAG 5.5 + GIT_SHALLOW 1 ) FetchContent_GetProperties(raylib) if (NOT raylib_POPULATED) - set(FETCHCONTENT_QUIET NO) - FetchContent_Populate(raylib) - set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) - set(BUILD_GAMES OFF CACHE BOOL "" FORCE) - add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) + set(FETCHCONTENT_QUIET NO) + FetchContent_Populate(raylib) + set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) + set(BUILD_GAMES OFF CACHE BOOL "" FORCE) + add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) endif() # imgui FetchContent_Declare( - imgui - GIT_REPOSITORY https://github.com/ocornut/imgui.git - GIT_TAG docking + imgui + GIT_REPOSITORY https://github.com/ocornut/imgui.git + GIT_TAG docking ) FetchContent_MakeAvailable(imgui) @@ -48,9 +48,9 @@ set(imgui_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/imgui-src) # rlimgui FetchContent_Declare( - rlImGui - GIT_REPOSITORY https://github.com/raylib-extras/rlImGui.git - GIT_TAG main + rlImGui + GIT_REPOSITORY https://github.com/raylib-extras/rlImGui.git + GIT_TAG main ) FetchContent_MakeAvailable(rlImGui) set(rlImGui_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/rlimgui-src) @@ -58,25 +58,26 @@ set(rlImGui_SOURCE_DIR ${CMAKE_BINARY_DIR}/_deps/rlimgui-src) # nlohmann::json FetchContent_Declare( - json - GIT_REPOSITORY https://github.com/nlohmann/json.git - GIT_TAG v3.11.3 + json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 ) FetchContent_MakeAvailable(json) include_directories(${imgui_SOURCE_DIR} ${rlImGui_SOURCE_DIR}) -set(SRC_CXX_FILES "./src/main.cpp" - "./src/rules.cpp" - "./src/world.cpp" - "./src/render.cpp" +set(SRC_CXX_FILES "./src/main.cpp" + "./src/rules.cpp" + "./src/world.cpp" + "./src/render.cpp" "./src/control_menu.cpp" - "${rlImGui_SOURCE_DIR}/rlImGui.cpp" - "${imgui_SOURCE_DIR}/imgui.cpp" - "${imgui_SOURCE_DIR}/imgui_draw.cpp" - "${imgui_SOURCE_DIR}/imgui_widgets.cpp" - "${imgui_SOURCE_DIR}/imgui_tables.cpp" - "${imgui_SOURCE_DIR}/backends/${IMGUI_BACKEND}" + "./src/settings_menu.cpp" + "${rlImGui_SOURCE_DIR}/rlImGui.cpp" + "${imgui_SOURCE_DIR}/imgui.cpp" + "${imgui_SOURCE_DIR}/imgui_draw.cpp" + "${imgui_SOURCE_DIR}/imgui_widgets.cpp" + "${imgui_SOURCE_DIR}/imgui_tables.cpp" + "${imgui_SOURCE_DIR}/backends/${IMGUI_BACKEND}" ) # Setup the example diff --git a/includes/context.hpp b/includes/context.hpp index c03587c..21fa3db 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -2,7 +2,7 @@ * File name: context.hpp * Author: lejulien * Date created: 01-01-1970 00:59:59 -// Date modified: 12-01-2026 20:31:50 +// Date modified: 12-01-2026 21:30:10 * ------ */ @@ -14,12 +14,16 @@ class World; class Rules; +class Render; namespace gol { +class SettingsMenu; typedef struct ctx { std::shared_ptr world = nullptr; std::shared_ptr rules = nullptr; + std::shared_ptr render = nullptr; + std::shared_ptr settings_menu = nullptr; nlohmann::json config_json; } ctx; diff --git a/includes/control_menu.hpp b/includes/control_menu.hpp index 2aa0c2e..7c20a7d 100644 --- a/includes/control_menu.hpp +++ b/includes/control_menu.hpp @@ -2,12 +2,14 @@ * File name: control_menu.hpp * Author: lejulien * Date created: 10-01-2026 22:00:33 -// Date modified: 10-01-2026 22:45:10 +// Date modified: 12-01-2026 22:18:26 * ------ */ #pragma once +#include + #include #include @@ -15,28 +17,21 @@ namespace gol { class ControlMenu { public: - ControlMenu(ctx context); + ControlMenu(std::shared_ptr context); ~ControlMenu() = default; void update(); void display(); private: - ctx context_; + std::shared_ptr context_; public: // Keep those public for easy access MenuState menu_state_ = MenuState::NONE; - int fps_ctrl_ = false; - int cell_size_ctrl_ = false; bool play_ctrl_ = true; bool step_ctrl_ = false; bool step_back_ctrl_ = false; bool rand_ctrl_ = false; bool edit_ctrl_ = false; bool clear_ctrl_ = false; - bool settings_window_ = false; bool paterns_ctrl_ = false; - int width_ctrl_ = false; - int height_ctrl_ = false; - bool dark_theme_ctrl_ = false; - bool apply_ctrl_ = false; }; } // namespace gol diff --git a/includes/render.hpp b/includes/render.hpp index 60651ab..0714998 100644 --- a/includes/render.hpp +++ b/includes/render.hpp @@ -2,10 +2,12 @@ * File name: render.hpp * Author: lejulien * Date created: 10-01-2026 21:54:12 -// Date modified: 10-01-2026 22:00:37 +// Date modified: 12-01-2026 21:56:03 * ------ */ +#include + #include "world.hpp" #pragma once @@ -16,7 +18,7 @@ public: Render(int cell_size); // Member function - void display(World *world); + void display(std::shared_ptr world); void updateCellSize(int new_size); private: diff --git a/includes/rules.hpp b/includes/rules.hpp index cae4c57..32b120e 100644 --- a/includes/rules.hpp +++ b/includes/rules.hpp @@ -2,7 +2,7 @@ * File name: rules.hpp * Author: lejulien * Date created: 09-01-2026 23:59:55 -* Date modified: 10-01-2026 21:49:44 +// Date modified: 12-01-2026 21:58:17 * ------ */ @@ -19,12 +19,12 @@ private: public: Rules(); - void setup(World *world); - void newWorld(World *world); + void setup(std::shared_ptr world); + void newWorld(std::shared_ptr world); void update(); private: - World *_world; + std::shared_ptr _world; std::vector _buffer; int _width; int _height; diff --git a/includes/settings_menu.hpp b/includes/settings_menu.hpp new file mode 100644 index 0000000..965fade --- /dev/null +++ b/includes/settings_menu.hpp @@ -0,0 +1,46 @@ +/* +* File name: settings_menu.hpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 22:16:29 +* ------ +*/ + +#pragma once + +#include + +#include + +namespace gol { + +class SettingsMenu { +public: + SettingsMenu(std::shared_ptr context); + ~SettingsMenu() = default; + void update(); + void display(); + bool isOpen(); + void Toogle(); + // Getter/Setters + int getFPS(); + void setFPS(int); + int getCellSize(); + void setCellSize(int); + int getWidth(); + void setWidth(int); + int getHeight(); + void setHeight(int); +private: + std::shared_ptr context_ = nullptr; + int fps_ctrl_ = false; + int cell_size_ctrl_ = false; + bool settings_window_ = false; + int width_ctrl_ = false; + int height_ctrl_ = false; + bool dark_theme_ctrl_ = false; + bool apply_ctrl_ = false; +}; + + +} // namespace gol diff --git a/includes/world.hpp b/includes/world.hpp index 668609d..c61e373 100644 --- a/includes/world.hpp +++ b/includes/world.hpp @@ -2,14 +2,14 @@ * File name: world.hpp * Author: lejulien * Date created: 09-01-2026 23:59:55 -* Date modified: 10-01-2026 21:49:31 +// Date modified: 12-01-2026 22:20:26 * ------ */ #include #include #include -#include +#include #include #include @@ -23,7 +23,7 @@ class World { public: - World(gol::ctx &ctx); + World(std::shared_ptr ctx); ~World(); std::vector *getWorldData(); diff --git a/src/control_menu.cpp b/src/control_menu.cpp index f9aa76b..d91d3ff 100644 --- a/src/control_menu.cpp +++ b/src/control_menu.cpp @@ -2,7 +2,7 @@ * File name: control_menu.cpp * Author: lejulien * Date created: 10-01-2026 22:12:44 -// Date modified: 12-01-2026 20:36:39 +// Date modified: 12-01-2026 22:18:58 * ------ */ @@ -11,26 +11,20 @@ #include #include +#include #include #include namespace gol { -ControlMenu::ControlMenu(ctx context):context_(context) { - fps_ctrl_ = context.config_json["fps"].get(); - cell_size_ctrl_ = context.config_json["cell_size"].get(); +ControlMenu::ControlMenu(std::shared_ptr context):context_(context) { play_ctrl_ = true; step_ctrl_ = false; step_back_ctrl_ = false; rand_ctrl_ = false; edit_ctrl_ = false; clear_ctrl_ = false; - settings_window_ = false; paterns_ctrl_ = false; - width_ctrl_ = context.config_json["screen_width"].get(); - height_ctrl_ = context.config_json["screen_height"].get(); - dark_theme_ctrl_ = context.config_json["dark_theme"].get(); - apply_ctrl_ = false; } void ControlMenu::update() { @@ -40,11 +34,11 @@ void ControlMenu::update() { } } if (rand_ctrl_) { - context_.world->randomize(); + context_->world->randomize(); rand_ctrl_ = false; } if (clear_ctrl_) { - context_.world->clear(); + context_->world->clear(); clear_ctrl_ = false; } if (edit_ctrl_ && play_ctrl_) { @@ -61,12 +55,12 @@ void ControlMenu::update() { menu_state_ = MenuState::EDIT; } if (step_ctrl_) { - context_.world->saveCompressed(); - context_.rules->update(); + context_->world->saveCompressed(); + context_->rules->update(); step_ctrl_ = false; } if (step_back_ctrl_) { - context_.world->stepBack(); + context_->world->stepBack(); step_back_ctrl_ = false; } } @@ -91,10 +85,10 @@ void ControlMenu::display() { if (ImGui::Button((paterns_ctrl_) ? "Hide paterns" : "Show paterns")) { paterns_ctrl_ = !paterns_ctrl_; } - if (ImGui::Button((settings_window_) ? "Hide settings" : "Show settings")) { - settings_window_ = !settings_window_; + if (ImGui::Button((context_->settings_menu->isOpen()) ? "Hide settings" : "Show settings")) { + context_->settings_menu->Toogle(); } - ImGui::Text("Generation: %zu", context_.world->getCycle()); + ImGui::Text("Generation: %zu", context_->world->getCycle()); ImGui::End();} } // namespace gol diff --git a/src/main.cpp b/src/main.cpp index cb95fde..bf07e5b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,7 +2,7 @@ * File name: main.cpp * Author: lejulien * Date created: 10-01-2026 21:59:32 -// Date modified: 12-01-2026 20:34:37 +// Date modified: 12-01-2026 22:17:54 * ------ */ @@ -22,6 +22,7 @@ #include #include #include +#include Vector2 snapToGrid(Vector2 screen, int cell_size) { return {static_cast(round(screen.x / cell_size) * cell_size), @@ -34,7 +35,7 @@ Vector2i screenToGrid(Vector2 screen, int cell_size) { } int main(int ac, char **av) { - gol::ctx context; + std::shared_ptr context = std::make_shared(); // Load or default config const std::string config_file_name = "config.json"; @@ -56,7 +57,7 @@ int main(int ac, char **av) { // Try reading the configuration try { config_file.seekg(0); - config_file >> context.config_json; + config_file >> context->config_json; } catch (const nlohmann::json::parse_error &e) { std::cerr << "An error occured while loading config : " << e.what() << std::endl; @@ -67,42 +68,43 @@ int main(int ac, char **av) { config_file.close(); // Check config values or populate them - if (!context.config_json.contains("cell_size") || - (context.config_json["cell_size"] < 4 || context.config_json["cell_size"] > 100)) { - context.config_json["cell_size"] = 10; + if (!context->config_json.contains("cell_size") || + (context->config_json["cell_size"] < 4 || context->config_json["cell_size"] > 100)) { + context->config_json["cell_size"] = 10; } - if (!context.config_json.contains("screen_width") || - (context.config_json["screen_width"] < 800 || - context.config_json["screen_width"] > 1920)) { - context.config_json["screen_width"] = 800; + if (!context->config_json.contains("screen_width") || + (context->config_json["screen_width"] < 800 || + context->config_json["screen_width"] > 1920)) { + context->config_json["screen_width"] = 800; } - if (!context.config_json.contains("screen_height") || - (context.config_json["screen_height"] < 600 || - context.config_json["screen_height"] > 1200)) { - context.config_json["screen_height"] = 600; + if (!context->config_json.contains("screen_height") || + (context->config_json["screen_height"] < 600 || + context->config_json["screen_height"] > 1200)) { + context->config_json["screen_height"] = 600; } - if (!context.config_json.contains("dark_theme")) { - context.config_json["dark_theme"] = true; + if (!context->config_json.contains("dark_theme")) { + context->config_json["dark_theme"] = true; } - if (!context.config_json.contains("fps") || - (context.config_json["fps"] < 0 || context.config_json["fps"] > 30)) { - context.config_json["fps"] = 800; + if (!context->config_json.contains("fps") || + (context->config_json["fps"] < 0 || context->config_json["fps"] > 30)) { + context->config_json["fps"] = 800; } - InitWindow(context.config_json["screen_width"], context.config_json["screen_height"], + InitWindow(context->config_json["screen_width"], context->config_json["screen_height"], &av[0][2]); SetTargetFPS(60); - rlImGuiSetup(context.config_json["dark_theme"]); + rlImGuiSetup(context->config_json["dark_theme"]); // Selection window RenderTexture2D selectionTexture = LoadRenderTexture(200, 200); // Initialize objects - context.world = std::make_shared(context); - context.rules = std::make_shared(); - Render render(context.config_json["cell_size"]); + context->world = std::make_shared(context); + context->rules = std::make_shared(); + context->settings_menu = std::make_shared(context); + context->render = std::make_shared(context->settings_menu->getCellSize()); // Imgui control menu gol::ControlMenu control_menu(context); @@ -122,12 +124,12 @@ int main(int ac, char **av) { std::string sel_txt_input_hint("patern name"); // Setups - context.rules->setup(&(*context.world)); + context->rules->setup(context->world); // Diplay generations while (!WindowShouldClose()) { // Frames shinenigans float deltaTime = GetFrameTime(); - sim_speed = control_menu.fps_ctrl_ / 10.0f; + sim_speed = context->settings_menu->getFPS() / 10.0f; timePerUpdate = (1.0f / 10.0f) / sim_speed; control_menu.update(); @@ -137,20 +139,20 @@ int main(int ac, char **av) { if (control_menu.edit_ctrl_ && IsMouseButtonPressed(0) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { control_menu.menu_state_ = MenuState::EDIT; - context.world->setCell(mousePos.x / context.config_json["cell_size"].get(), - mousePos.y / context.config_json["cell_size"].get()); + context->world->setCell(mousePos.x / context->config_json["cell_size"].get(), + mousePos.y / context->config_json["cell_size"].get()); } // Selection behaviour - if (!control_menu.edit_ctrl_ && !control_menu.play_ctrl_ && !control_menu.paterns_ctrl_ && !control_menu.settings_window_) { + if (!control_menu.edit_ctrl_ && !control_menu.play_ctrl_ && !control_menu.paterns_ctrl_ && !context->settings_menu->isOpen()) { if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - sel_pos = snapToGrid(mousePos, control_menu.cell_size_ctrl_); + sel_pos = snapToGrid(mousePos, context->settings_menu->getCellSize()); selecting = true; } - if (ImGui::IsMouseReleased(0) && selecting == true && mousePos.x >=0 && mousePos.x < control_menu.width_ctrl_ && mousePos.y >=0 && mousePos.y < control_menu.height_ctrl_ ) { + if (ImGui::IsMouseReleased(0) && selecting == true && mousePos.x >=0 && mousePos.x < context->settings_menu->getWidth() && mousePos.y >=0 && mousePos.y < context->settings_menu->getHeight() ) { selecting = false; - Vector2i p1 = screenToGrid(sel_pos, control_menu.cell_size_ctrl_); - Vector2i p2 = screenToGrid(mousePos, control_menu.cell_size_ctrl_); + Vector2i p1 = screenToGrid(sel_pos, context->settings_menu->getCellSize()); + Vector2i p2 = screenToGrid(mousePos, context->settings_menu->getCellSize()); // Get origin Vector2i orig = { (p1.x < p2.x)?p1.x:p2.x, @@ -163,7 +165,7 @@ int main(int ac, char **av) { }; // Ensure there is at least one cell selected if (!(sel_size.x == 0 || sel_size.y == 0)) { - sel_data = std::move(context.world->getSelection(orig, sel_size)); + sel_data = std::move(context->world->getSelection(orig, sel_size)); sel_ctrl = true; } } @@ -171,35 +173,7 @@ int main(int ac, char **av) { if (!sel_ctrl) { patern_name[0] = '\0'; } - - if (control_menu.apply_ctrl_) { - bool resize_needed = false; - context.config_json["fps"] = control_menu.fps_ctrl_; - if (context.config_json["screen_width"].get() != control_menu.width_ctrl_ || - context.config_json["screen_height"].get() != control_menu.height_ctrl_) { - context.config_json["screen_width"] = control_menu.width_ctrl_; - context.config_json["screen_height"] = control_menu.height_ctrl_; - rlImGuiShutdown(); - SetWindowSize(control_menu.width_ctrl_, control_menu.height_ctrl_); - rlImGuiSetup(control_menu.dark_theme_ctrl_); - resize_needed = true; - } - if (control_menu.cell_size_ctrl_ != context.config_json["cell_size"].get() || - resize_needed) { - context.world->resize(context.config_json["screen_width"].get() / control_menu.cell_size_ctrl_, - context.config_json["screen_height"].get() / control_menu.cell_size_ctrl_); - render.updateCellSize(control_menu.cell_size_ctrl_); - context.rules->newWorld(&(*context.world)); - context.config_json["cell_size"] = control_menu.cell_size_ctrl_; - } - if (control_menu.dark_theme_ctrl_ != context.config_json["dark_theme"]) { - rlImGuiShutdown(); - rlImGuiSetup(control_menu.dark_theme_ctrl_); - context.config_json["dark_theme"] = control_menu.dark_theme_ctrl_; - } - control_menu.apply_ctrl_ = false; - control_menu.settings_window_ = false; - } + context->settings_menu->update(); // Accumulate time and update simulation at the adjusted speed deltaTimeAccumulator += deltaTime; @@ -208,15 +182,15 @@ int main(int ac, char **av) { // Reset accumulator deltaTimeAccumulator -= timePerUpdate; if (control_menu.menu_state_ == MenuState::PLAY) { - context.world->saveCompressed(); - context.rules->update(); + context->world->saveCompressed(); + context->rules->update(); } } BeginDrawing(); ClearBackground(BLACK); - render.display(&(*context.world)); + context->render->display(context->world); if (selecting) { - auto grid_mouse = snapToGrid(mousePos, control_menu.cell_size_ctrl_); + auto grid_mouse = snapToGrid(mousePos, context->settings_menu->getCellSize()); bool sel_x_less = (sel_pos.x < grid_mouse.x); bool sel_y_less = (sel_pos.y < grid_mouse.y); DrawRectangleLines(((sel_x_less)? sel_pos.x: grid_mouse.x), ((sel_y_less)? sel_pos.y: grid_mouse.y), @@ -235,20 +209,7 @@ int main(int ac, char **av) { ImGui::Button("refresh"); ImGui::End(); } - if (control_menu.settings_window_) { - ImGuiWindowFlags settings_flags = - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; - ImGui::Begin("Settings", &control_menu.settings_window_, settings_flags); - ImGui::SliderInt("Window Width", &control_menu.width_ctrl_, 800, 1920); - ImGui::SliderInt("Window Height", &control_menu.height_ctrl_, 600, 1200); - ImGui::SliderInt("FPS", &control_menu.fps_ctrl_, 0, 30); - ImGui::SliderInt("Cell Size", &control_menu.cell_size_ctrl_, 4, 100); - ImGui::Checkbox("Dark Theme", &control_menu.dark_theme_ctrl_); - if (ImGui::Button("Save & Apply")) { - control_menu.apply_ctrl_ = true; - } - ImGui::End(); - } + context->settings_menu->display(); if (sel_ctrl) { BeginTextureMode(selectionTexture); ClearBackground(BLACK); @@ -318,7 +279,7 @@ int main(int ac, char **av) { EndDrawing(); } config_file.open(config_file_name, std::ios::out | std::ios::trunc); - config_file << context.config_json.dump(2); + config_file << context->config_json.dump(2); config_file.close(); // Cleanup Selection texture UnloadRenderTexture(selectionTexture); diff --git a/src/render.cpp b/src/render.cpp index 6f2a9fa..f4c995e 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -2,7 +2,7 @@ * File name: render.cpp * Author: lejulien * Date created: 10-01-2026 21:49:04 -// Date modified: 10-01-2026 21:59:56 +// Date modified: 12-01-2026 21:54:56 * ------ */ @@ -71,7 +71,7 @@ void Render::display_world(std::vector *data, int width, int height) { // Render loop -void Render::display(World *world) { +void Render::display(std::shared_ptr world) { display_world(world->getWorldData(), world->getWidth(), world->getHeight()); } diff --git a/src/rules.cpp b/src/rules.cpp index 55beb2f..5094c00 100644 --- a/src/rules.cpp +++ b/src/rules.cpp @@ -2,7 +2,7 @@ * File name: rules.cpp * Author: lejulien * Date created: 10-01-2026 21:49:14 -// Date modified: 10-01-2026 22:00:16 +// Date modified: 12-01-2026 21:59:00 * ------ */ @@ -67,13 +67,13 @@ void Rules::diag_neighbors(int &neighbors, int i, int j) { // Member function -void Rules::setup(World *world) { +void Rules::setup(std::shared_ptr world) { _world = world; _width = world->getWidth(); _height = world->getHeight(); } -void Rules::newWorld(World *world) { +void Rules::newWorld(std::shared_ptr world) { _world = world; _width = world->getWidth(); _height = world->getHeight(); diff --git a/src/settings_menu.cpp b/src/settings_menu.cpp new file mode 100644 index 0000000..0ce1e54 --- /dev/null +++ b/src/settings_menu.cpp @@ -0,0 +1,122 @@ +/* +* File name: settings_menu.cpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 22:21:49 +* ------ +*/ + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace gol { + +SettingsMenu::SettingsMenu(std::shared_ptr context): context_(context) { + fps_ctrl_ = context->config_json["fps"].get(); + cell_size_ctrl_ = context->config_json["cell_size"].get(); + settings_window_ = false; + width_ctrl_ = context->config_json["screen_width"].get(); + height_ctrl_ = context->config_json["screen_height"].get(); + dark_theme_ctrl_ = context->config_json["dark_theme"].get(); + apply_ctrl_ = false; +} + +void SettingsMenu::update() { + if (apply_ctrl_) { + bool resize_needed = false; + context_->config_json["fps"] = fps_ctrl_; + if (context_->config_json["screen_width"].get() != width_ctrl_ || + context_->config_json["screen_height"].get() != height_ctrl_) { + context_->config_json["screen_width"] = width_ctrl_; + context_->config_json["screen_height"] = height_ctrl_; + rlImGuiShutdown(); + SetWindowSize(width_ctrl_, height_ctrl_); + rlImGuiSetup(dark_theme_ctrl_); + resize_needed = true; + } + if (cell_size_ctrl_ != context_->config_json["cell_size"].get() || + resize_needed) { + context_->world->resize(context_->config_json["screen_width"].get() / cell_size_ctrl_, + context_->config_json["screen_height"].get() / cell_size_ctrl_); + context_->render->updateCellSize(cell_size_ctrl_); + context_->rules->newWorld(context_->world); + context_->config_json["cell_size"] = cell_size_ctrl_; + } + if (dark_theme_ctrl_ != context_->config_json["dark_theme"]) { + rlImGuiShutdown(); + rlImGuiSetup(dark_theme_ctrl_); + context_->config_json["dark_theme"] = dark_theme_ctrl_; + } + apply_ctrl_ = false; + settings_window_ = false; + } +} + +void SettingsMenu::display() { + if (settings_window_) { + ImGuiWindowFlags settings_flags = + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; + ImGui::Begin("Settings", &settings_window_, settings_flags); + ImGui::SliderInt("Window Width", &width_ctrl_, 800, 1920); + ImGui::SliderInt("Window Height", &height_ctrl_, 600, 1200); + ImGui::SliderInt("FPS", &fps_ctrl_, 0, 30); + ImGui::SliderInt("Cell Size", &cell_size_ctrl_, 4, 100); + ImGui::Checkbox("Dark Theme", &dark_theme_ctrl_); + if (ImGui::Button("Save & Apply")) { + apply_ctrl_ = true; + } + ImGui::End(); + } +} + +bool SettingsMenu::isOpen() { + return settings_window_; +} + +void SettingsMenu::Toogle() { + settings_window_ = !settings_window_; +} + +// Getters/Setters +int SettingsMenu::getFPS() { + return fps_ctrl_; +} + +void SettingsMenu::setFPS(int new_fps) { + fps_ctrl_ = new_fps; +} + +int SettingsMenu::getCellSize() { + return cell_size_ctrl_; +} + +void SettingsMenu::setCellSize(int new_cell_size) { + cell_size_ctrl_ = new_cell_size; +} + +int SettingsMenu::getWidth() { + return width_ctrl_; +} + +void SettingsMenu::setWidth(int new_width) { + width_ctrl_ = new_width; +} + +int SettingsMenu::getHeight() { + return height_ctrl_; +} + +void SettingsMenu::setHeight(int new_height) { + height_ctrl_ = new_height; +} + +} // namespace gol diff --git a/src/world.cpp b/src/world.cpp index 3e371e0..ae653ba 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -2,7 +2,7 @@ * File name: world.cpp * Author: lejulien * Date created: 09-01-2026 23:59:55 -// Date modified: 10-01-2026 22:00:23 +// Date modified: 12-01-2026 22:14:46 * ------ */ @@ -12,11 +12,11 @@ // Constructor and destructor -World::World(gol::ctx &context) { - _width = context.config_json["screen_width"].get() / - context.config_json["cell_size"].get(); - _height = context.config_json["screen_height"].get() / - context.config_json["cell_size"].get(); +World::World(std::shared_ptr context) { + _width = context->config_json["screen_width"].get() / + context->config_json["cell_size"].get(); + _height = context->config_json["screen_height"].get() / + context->config_json["cell_size"].get(); // create world data this->_data = new std::vector(_width * _height, false); } -- 2.49.1 From f45c83dd7748725f0d5483766462284180571d5c Mon Sep 17 00:00:00 2001 From: lejulien Date: Tue, 13 Jan 2026 13:03:36 +0100 Subject: [PATCH 09/11] selection_menu: Move it to it's dedicated class --- CMakeLists.txt | 1 + includes/context.hpp | 2 + includes/selection_menu.hpp | 38 +++++++++++++ src/main.cpp | 86 ++-------------------------- src/selection_menu.cpp | 109 ++++++++++++++++++++++++++++++++++++ 5 files changed, 156 insertions(+), 80 deletions(-) create mode 100644 includes/selection_menu.hpp create mode 100644 src/selection_menu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 77d5bf7..6cb9cc0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -72,6 +72,7 @@ set(SRC_CXX_FILES "./src/main.cpp" "./src/render.cpp" "./src/control_menu.cpp" "./src/settings_menu.cpp" + "./src/selection_menu.cpp" "${rlImGui_SOURCE_DIR}/rlImGui.cpp" "${imgui_SOURCE_DIR}/imgui.cpp" "${imgui_SOURCE_DIR}/imgui_draw.cpp" diff --git a/includes/context.hpp b/includes/context.hpp index 21fa3db..f025d49 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -18,12 +18,14 @@ class Render; namespace gol { class SettingsMenu; +class SelectionMenu; typedef struct ctx { std::shared_ptr world = nullptr; std::shared_ptr rules = nullptr; std::shared_ptr render = nullptr; std::shared_ptr settings_menu = nullptr; + std::shared_ptr selection_menu = nullptr; nlohmann::json config_json; } ctx; diff --git a/includes/selection_menu.hpp b/includes/selection_menu.hpp new file mode 100644 index 0000000..ccc9124 --- /dev/null +++ b/includes/selection_menu.hpp @@ -0,0 +1,38 @@ +/* +* File name: selection_menu.hpp +* Author: lejulien +* Date created: 13-01-2026 22:12:44 +// Date modified: 13-01-2026 22:18:58 +* ------ +*/ + +#pragma once + +#include +#include + +#include +#include +#include + +#include + +namespace gol { + +class SelectionMenu { +public: + SelectionMenu(std::shared_ptr context); + ~SelectionMenu(); + void update(); + void display(); + void setSelection(std::vector selection); + void open(); +private: + std::shared_ptr context_; + RenderTexture2D selectionTexture_; + std::vector sel_data_ = {}; + bool sel_ctrl_ = false; + char patern_name_[255]; +}; + +} // namespace gol diff --git a/src/main.cpp b/src/main.cpp index bf07e5b..4c68eed 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -23,6 +22,7 @@ #include #include #include +#include Vector2 snapToGrid(Vector2 screen, int cell_size) { return {static_cast(round(screen.x / cell_size) * cell_size), @@ -96,15 +96,13 @@ int main(int ac, char **av) { SetTargetFPS(60); rlImGuiSetup(context->config_json["dark_theme"]); - // Selection window - - RenderTexture2D selectionTexture = LoadRenderTexture(200, 200); // Initialize objects context->world = std::make_shared(context); context->rules = std::make_shared(); context->settings_menu = std::make_shared(context); context->render = std::make_shared(context->settings_menu->getCellSize()); + context->selection_menu = std::make_shared(context); // Imgui control menu gol::ControlMenu control_menu(context); @@ -117,11 +115,6 @@ int main(int ac, char **av) { // Selection window Vector2 sel_pos = {0., 0.}; bool selecting = false; - std::vector sel_data = {}; - bool sel_ctrl = false; - char patern_name[255]; - patern_name[0] = '\0'; - std::string sel_txt_input_hint("patern name"); // Setups context->rules->setup(context->world); @@ -165,14 +158,12 @@ int main(int ac, char **av) { }; // Ensure there is at least one cell selected if (!(sel_size.x == 0 || sel_size.y == 0)) { - sel_data = std::move(context->world->getSelection(orig, sel_size)); - sel_ctrl = true; + context->selection_menu->setSelection(context->world->getSelection(orig, sel_size)); + context->selection_menu->open(); } } } - if (!sel_ctrl) { - patern_name[0] = '\0'; - } + context->selection_menu->update(); context->settings_menu->update(); // Accumulate time and update simulation at the adjusted speed @@ -210,70 +201,7 @@ int main(int ac, char **av) { ImGui::End(); } context->settings_menu->display(); - if (sel_ctrl) { - BeginTextureMode(selectionTexture); - ClearBackground(BLACK); - auto max_size = (sel_data[0] > sel_data[1]) ? sel_data[0] : sel_data[1]; - int fitted_width = 200 / max_size; - auto sel_it = sel_data.begin(); - sel_it += 2; // skip dimensions - for (int j = 0; j < sel_data[1]; j++) { - for (int i = 0; i < sel_data[0]; i++) { - if (*sel_it == 1) { - DrawRectangle(i * fitted_width, (sel_data[1] -j-1) * fitted_width, fitted_width, fitted_width, WHITE); - } - sel_it++; - } - } - EndTextureMode(); - ImGuiWindowFlags settings_flags = - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; - ImGui::Begin("Selection", &sel_ctrl, settings_flags); - rlImGuiImageSize(&selectionTexture.texture, 200, 200); - ImGui::InputText(sel_txt_input_hint.c_str(), patern_name, 255); - if (ImGui::Button("Save")) { - char path_buf[1024]; - ssize_t len = readlink("/proc/self/exe", path_buf, sizeof(path_buf)-1); - if (len != -1) { - // Create paterns dir if not present - std::filesystem::path paterns_dir = std::filesystem::path(path_buf).parent_path() / "paterns"; - if (!std::filesystem::exists(paterns_dir) && !std::filesystem::create_directory(paterns_dir)) { - std::cerr << "Failed to create paterns directory" << std::endl; - } else { // Could be optimized by early returning in a function - std::ofstream patern_file; - paterns_dir += '/'; - paterns_dir += patern_name; - patern_file.open(paterns_dir); - if (!patern_file) { - std::cerr << "Failed to create the patern file" << std::endl; - } else { - auto sel_it = sel_data.begin(); - sel_it += 2; // skip dimensions - patern_file << sel_data[0]; - patern_file << "|"; // Separator needed to split as ascii values - patern_file << sel_data[1]; - patern_file << "|"; // Separator needed to split as ascii values - for (int j = 0; j < sel_data[1]; j++) { - for (int i = 0; i < sel_data[0]; i++) { - patern_file << std::to_string(*sel_it); - if (*sel_it == 1) { - } - sel_it++; - } - } - patern_file << std::flush; - patern_file.close(); - } - } - sel_ctrl = false; - } - } - ImGui::SameLine(); - if (ImGui::Button("Discard")) { - sel_ctrl = false; - } - ImGui::End(); - } + context->selection_menu->display(); // End ImGui frame rlImGuiEnd(); EndDrawing(); @@ -281,8 +209,6 @@ int main(int ac, char **av) { config_file.open(config_file_name, std::ios::out | std::ios::trunc); config_file << context->config_json.dump(2); config_file.close(); - // Cleanup Selection texture - UnloadRenderTexture(selectionTexture); rlImGuiShutdown(); CloseWindow(); return 0; diff --git a/src/selection_menu.cpp b/src/selection_menu.cpp new file mode 100644 index 0000000..de9f56d --- /dev/null +++ b/src/selection_menu.cpp @@ -0,0 +1,109 @@ +/* +* File name: selection_menu.cpp +* Author: lejulien +* Date created: 13-01-2026 22:12:44 +// Date modified: 13-01-2026 22:18:58 +* ------ +*/ + +#include +#include +#include +#include + +#include + +namespace gol { + +SelectionMenu::SelectionMenu(std::shared_ptr context): context_(context) { + selectionTexture_ = LoadRenderTexture(200, 200); + patern_name_[0] = '\0'; + +} + +SelectionMenu::~SelectionMenu() { + UnloadRenderTexture(selectionTexture_); +} + +void SelectionMenu::update() { + if (!sel_ctrl_) { + patern_name_[0] = '\0'; + } +} + +void SelectionMenu::open() { + sel_ctrl_ = true; +} + +void SelectionMenu::setSelection(std::vector selection) { + sel_data_ = selection; +} + +void SelectionMenu::display() { + if (sel_ctrl_) { + BeginTextureMode(selectionTexture_); + ClearBackground(BLACK); + auto max_size = (sel_data_[0] > sel_data_[1]) ? sel_data_[0] : sel_data_[1]; + int fitted_width = 200 / max_size; + auto sel_it = sel_data_.begin(); + sel_it += 2; // skip dimensions + for (int j = 0; j < sel_data_[1]; j++) { + for (int i = 0; i < sel_data_[0]; i++) { + if (*sel_it == 1) { + DrawRectangle(i * fitted_width, (sel_data_[1] -j-1) * fitted_width, fitted_width, fitted_width, WHITE); + } + sel_it++; + } + } + EndTextureMode(); + ImGuiWindowFlags settings_flags = + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; + ImGui::Begin("Selection", &sel_ctrl_, settings_flags); + rlImGuiImageSize(&selectionTexture_.texture, 200, 200); + ImGui::InputText("patern_name", patern_name_, 255); + if (ImGui::Button("Save")) { + char path_buf[1024]; + ssize_t len = readlink("/proc/self/exe", path_buf, sizeof(path_buf)-1); + if (len != -1) { + // Create paterns dir if not present + std::filesystem::path paterns_dir = std::filesystem::path(path_buf).parent_path() / "paterns"; + if (!std::filesystem::exists(paterns_dir) && !std::filesystem::create_directory(paterns_dir)) { + std::cerr << "Failed to create paterns directory" << std::endl; + } else { // Could be optimized by early returning in a function + std::ofstream patern_file; + paterns_dir += '/'; + paterns_dir += patern_name_; + patern_file.open(paterns_dir); + if (!patern_file) { + std::cerr << "Failed to create the patern file" << std::endl; + } else { + auto sel_it = sel_data_.begin(); + sel_it += 2; // skip dimensions + patern_file << sel_data_[0]; + patern_file << "|"; // Separator needed to split as ascii values + patern_file << sel_data_[1]; + patern_file << "|"; // Separator needed to split as ascii values + for (int j = 0; j < sel_data_[1]; j++) { + for (int i = 0; i < sel_data_[0]; i++) { + patern_file << std::to_string(*sel_it); + if (*sel_it == 1) { + } + sel_it++; + } + } + patern_file << std::flush; + patern_file.close(); + } + } + sel_ctrl_ = false; + } + } + ImGui::SameLine(); + if (ImGui::Button("Discard")) { + sel_ctrl_ = false; + } + ImGui::End(); + } +} + +} // namespace gol -- 2.49.1 From 55341973b325fd63872fbaae5fae1d70b49ea323 Mon Sep 17 00:00:00 2001 From: lejulien Date: Tue, 13 Jan 2026 13:39:02 +0100 Subject: [PATCH 10/11] selection: Create it's dedicated class --- CMakeLists.txt | 1 + includes/context.hpp | 4 +++ includes/selection.hpp | 32 ++++++++++++++++++ includes/snapping.hpp | 24 ++++++++++++++ src/main.cpp | 73 ++++++++---------------------------------- src/selection.cpp | 67 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 141 insertions(+), 60 deletions(-) create mode 100644 includes/selection.hpp create mode 100644 includes/snapping.hpp create mode 100644 src/selection.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6cb9cc0..811c3d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC_CXX_FILES "./src/main.cpp" "./src/control_menu.cpp" "./src/settings_menu.cpp" "./src/selection_menu.cpp" + "./src/selection.cpp" "${rlImGui_SOURCE_DIR}/rlImGui.cpp" "${imgui_SOURCE_DIR}/imgui.cpp" "${imgui_SOURCE_DIR}/imgui_draw.cpp" diff --git a/includes/context.hpp b/includes/context.hpp index f025d49..9ad954e 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -19,6 +19,8 @@ class Render; namespace gol { class SettingsMenu; class SelectionMenu; +class ControlMenu; +class Selection; typedef struct ctx { std::shared_ptr world = nullptr; @@ -26,6 +28,8 @@ typedef struct ctx { std::shared_ptr render = nullptr; std::shared_ptr settings_menu = nullptr; std::shared_ptr selection_menu = nullptr; + std::shared_ptr control_menu = nullptr; + std::shared_ptr selection = nullptr; nlohmann::json config_json; } ctx; diff --git a/includes/selection.hpp b/includes/selection.hpp new file mode 100644 index 0000000..eb1de78 --- /dev/null +++ b/includes/selection.hpp @@ -0,0 +1,32 @@ +/* +* File name: selection.hpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#pragma once + +#include + +#include +#include +#include + +namespace gol { + +class Selection { +public: + Selection(std::shared_ptr); + ~Selection() = default; + void update(); + void display(); +private: + std::shared_ptr context_ = nullptr; + Vector2 sel_pos_ = {0., 0.}; + Vector2 mouse_pos_ = {0., 0.}; + bool selecting_ = false; +}; + +} // namespace gol diff --git a/includes/snapping.hpp b/includes/snapping.hpp new file mode 100644 index 0000000..dfcc0fb --- /dev/null +++ b/includes/snapping.hpp @@ -0,0 +1,24 @@ +/* +* File name: selection.cpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#pragma once + +#include + +#include +#include + +Vector2 snapToGrid(Vector2 screen, int cell_size) { + return {static_cast(round(screen.x / cell_size) * cell_size), + static_cast(round(screen.y / cell_size) * cell_size)}; +} + +Vector2i screenToGrid(Vector2 screen, int cell_size) { + return {static_cast(round(screen.x / cell_size)), + static_cast(round(screen.y / cell_size))}; +} diff --git a/src/main.cpp b/src/main.cpp index 4c68eed..25482dc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,16 +23,7 @@ #include #include #include - -Vector2 snapToGrid(Vector2 screen, int cell_size) { - return {static_cast(round(screen.x / cell_size) * cell_size), - static_cast(round(screen.y / cell_size) * cell_size)}; -} - -Vector2i screenToGrid(Vector2 screen, int cell_size) { - return {static_cast(round(screen.x / cell_size)), - static_cast(round(screen.y / cell_size))}; -} +#include int main(int ac, char **av) { std::shared_ptr context = std::make_shared(); @@ -98,71 +89,41 @@ int main(int ac, char **av) { rlImGuiSetup(context->config_json["dark_theme"]); // Initialize objects + context->control_menu = std::make_shared(context); context->world = std::make_shared(context); context->rules = std::make_shared(); context->settings_menu = std::make_shared(context); context->render = std::make_shared(context->settings_menu->getCellSize()); context->selection_menu = std::make_shared(context); - - // Imgui control menu - gol::ControlMenu control_menu(context); + context->selection = std::make_shared(context); // Speed handling values float sim_speed = 1.0f; float deltaTimeAccumulator = 0.0f; float timePerUpdate = 1.0f / 10.0f; - // Selection window - Vector2 sel_pos = {0., 0.}; - bool selecting = false; - // Setups context->rules->setup(context->world); // Diplay generations while (!WindowShouldClose()) { // Frames shinenigans float deltaTime = GetFrameTime(); - sim_speed = context->settings_menu->getFPS() / 10.0f; + sim_speed = context->settings_menu->getFPS() / 10.0f; timePerUpdate = (1.0f / 10.0f) / sim_speed; - control_menu.update(); + context->control_menu->update(); auto gesture = GetGestureDetected(); auto mousePos = GetMousePosition(); - if (control_menu.edit_ctrl_ && IsMouseButtonPressed(0) && + if (context->control_menu->edit_ctrl_ && IsMouseButtonPressed(0) && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - control_menu.menu_state_ = MenuState::EDIT; + context->control_menu->menu_state_ = MenuState::EDIT; context->world->setCell(mousePos.x / context->config_json["cell_size"].get(), mousePos.y / context->config_json["cell_size"].get()); } // Selection behaviour - if (!control_menu.edit_ctrl_ && !control_menu.play_ctrl_ && !control_menu.paterns_ctrl_ && !context->settings_menu->isOpen()) { - if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { - sel_pos = snapToGrid(mousePos, context->settings_menu->getCellSize()); - selecting = true; - } - if (ImGui::IsMouseReleased(0) && selecting == true && mousePos.x >=0 && mousePos.x < context->settings_menu->getWidth() && mousePos.y >=0 && mousePos.y < context->settings_menu->getHeight() ) { - selecting = false; - Vector2i p1 = screenToGrid(sel_pos, context->settings_menu->getCellSize()); - Vector2i p2 = screenToGrid(mousePos, context->settings_menu->getCellSize()); - // Get origin - Vector2i orig = { - (p1.x < p2.x)?p1.x:p2.x, - (p1.y < p2.y)?p1.y:p2.y, - }; - // Get selection size - Vector2i sel_size = { - (p1.x > p2.x)?p1.x-p2.x:p2.x-p1.x, - (p1.y > p2.y)?p1.y-p2.y:p2.y-p1.y, - }; - // Ensure there is at least one cell selected - if (!(sel_size.x == 0 || sel_size.y == 0)) { - context->selection_menu->setSelection(context->world->getSelection(orig, sel_size)); - context->selection_menu->open(); - } - } - } + context->selection->update(); context->selection_menu->update(); context->settings_menu->update(); @@ -172,7 +133,7 @@ int main(int ac, char **av) { if (deltaTimeAccumulator >= timePerUpdate) { // Reset accumulator deltaTimeAccumulator -= timePerUpdate; - if (control_menu.menu_state_ == MenuState::PLAY) { + if (context->control_menu->menu_state_ == MenuState::PLAY) { context->world->saveCompressed(); context->rules->update(); } @@ -180,23 +141,15 @@ int main(int ac, char **av) { BeginDrawing(); ClearBackground(BLACK); context->render->display(context->world); - if (selecting) { - auto grid_mouse = snapToGrid(mousePos, context->settings_menu->getCellSize()); - bool sel_x_less = (sel_pos.x < grid_mouse.x); - bool sel_y_less = (sel_pos.y < grid_mouse.y); - DrawRectangleLines(((sel_x_less)? sel_pos.x: grid_mouse.x), ((sel_y_less)? sel_pos.y: grid_mouse.y), - ((sel_x_less)? grid_mouse.x - sel_pos.x : sel_pos.x - grid_mouse.x), - ((sel_y_less)? grid_mouse.y - sel_pos.y : sel_pos.y - grid_mouse.y), - RED); - } + context->selection->display(); // Start ImGui frame rlImGuiBegin(); - control_menu.display(); - if (control_menu.paterns_ctrl_) { + context->control_menu->display(); + if (context->control_menu->paterns_ctrl_) { ImGuiWindowFlags paterns_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; ImGui::SetNextWindowSize(ImVec2(150, 200), ImGuiCond_Always); - ImGui::Begin("paterns", &control_menu.paterns_ctrl_, paterns_flags); + ImGui::Begin("paterns", &context->control_menu->paterns_ctrl_, paterns_flags); ImGui::Button("refresh"); ImGui::End(); } diff --git a/src/selection.cpp b/src/selection.cpp new file mode 100644 index 0000000..c36cfd7 --- /dev/null +++ b/src/selection.cpp @@ -0,0 +1,67 @@ +/* +* File name: selection.cpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#include + +#include +#include +#include +#include +#include +#include + +namespace gol { + +Selection::Selection(std::shared_ptr context): context_(context) { + +} + +void Selection::update() { + auto gesture = GetGestureDetected(); + mouse_pos_ = GetMousePosition(); + if (!context_->control_menu->edit_ctrl_ && !context_->control_menu->play_ctrl_ && !context_->control_menu->paterns_ctrl_ && !context_->settings_menu->isOpen()) { + if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { + sel_pos_ = snapToGrid(mouse_pos_, context_->settings_menu->getCellSize()); + selecting_ = true; + } + if (ImGui::IsMouseReleased(0) && selecting_ == true && mouse_pos_.x >=0 && mouse_pos_.x < context_->settings_menu->getWidth() && mouse_pos_.y >=0 && mouse_pos_.y < context_->settings_menu->getHeight() ) { + selecting_ = false; + Vector2i p1 = screenToGrid(sel_pos_, context_->settings_menu->getCellSize()); + Vector2i p2 = screenToGrid(mouse_pos_, context_->settings_menu->getCellSize()); + // Get origin + Vector2i orig = { + (p1.x < p2.x)?p1.x:p2.x, + (p1.y < p2.y)?p1.y:p2.y, + }; + // Get selection size + Vector2i sel_size = { + (p1.x > p2.x)?p1.x-p2.x:p2.x-p1.x, + (p1.y > p2.y)?p1.y-p2.y:p2.y-p1.y, + }; + // Ensure there is at least one cell selected + if (!(sel_size.x == 0 || sel_size.y == 0)) { + context_->selection_menu->setSelection(context_->world->getSelection(orig, sel_size)); + context_->selection_menu->open(); + } + } + } +} + +void Selection::display() { + if (selecting_) { + auto grid_mouse = snapToGrid(mouse_pos_, context_->settings_menu->getCellSize()); + bool sel_x_less = (sel_pos_.x < grid_mouse.x); + bool sel_y_less = (sel_pos_.y < grid_mouse.y); + DrawRectangleLines(((sel_x_less)? sel_pos_.x: grid_mouse.x), ((sel_y_less)? sel_pos_.y: grid_mouse.y), + ((sel_x_less)? grid_mouse.x - sel_pos_.x : sel_pos_.x - grid_mouse.x), + ((sel_y_less)? grid_mouse.y - sel_pos_.y : sel_pos_.y - grid_mouse.y), + RED); + } +} + +} // namespace gol -- 2.49.1 From 81f1bc5e72c46b4165bbe9eb48d6ebf86215132f Mon Sep 17 00:00:00 2001 From: lejulien Date: Tue, 13 Jan 2026 14:49:12 +0100 Subject: [PATCH 11/11] paterns_menu: Move it to it's own class --- CMakeLists.txt | 1 + includes/context.hpp | 2 ++ includes/control_menu.hpp | 1 - includes/paterns_menu.hpp | 24 ++++++++++++++++++++++++ src/control_menu.cpp | 12 +++--------- src/main.cpp | 11 +++-------- src/paterns_menu.cpp | 35 +++++++++++++++++++++++++++++++++++ src/selection.cpp | 3 ++- 8 files changed, 70 insertions(+), 19 deletions(-) create mode 100644 includes/paterns_menu.hpp create mode 100644 src/paterns_menu.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 811c3d8..f03cca0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,7 @@ set(SRC_CXX_FILES "./src/main.cpp" "./src/settings_menu.cpp" "./src/selection_menu.cpp" "./src/selection.cpp" + "./src/paterns_menu.cpp" "${rlImGui_SOURCE_DIR}/rlImGui.cpp" "${imgui_SOURCE_DIR}/imgui.cpp" "${imgui_SOURCE_DIR}/imgui_draw.cpp" diff --git a/includes/context.hpp b/includes/context.hpp index 9ad954e..40f8704 100644 --- a/includes/context.hpp +++ b/includes/context.hpp @@ -21,6 +21,7 @@ class SettingsMenu; class SelectionMenu; class ControlMenu; class Selection; +class PaternsMenu; typedef struct ctx { std::shared_ptr world = nullptr; @@ -30,6 +31,7 @@ typedef struct ctx { std::shared_ptr selection_menu = nullptr; std::shared_ptr control_menu = nullptr; std::shared_ptr selection = nullptr; + std::shared_ptr paterns_menu = nullptr; nlohmann::json config_json; } ctx; diff --git a/includes/control_menu.hpp b/includes/control_menu.hpp index 7c20a7d..c9c71b5 100644 --- a/includes/control_menu.hpp +++ b/includes/control_menu.hpp @@ -31,7 +31,6 @@ public: // Keep those public for easy access bool rand_ctrl_ = false; bool edit_ctrl_ = false; bool clear_ctrl_ = false; - bool paterns_ctrl_ = false; }; } // namespace gol diff --git a/includes/paterns_menu.hpp b/includes/paterns_menu.hpp new file mode 100644 index 0000000..9af513a --- /dev/null +++ b/includes/paterns_menu.hpp @@ -0,0 +1,24 @@ +/* +* File name: paterns_menu.hpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#pragma once + +namespace gol { + +class PaternsMenu { +public: + PaternsMenu() = default; + ~PaternsMenu() = default; + void Toogle(); + bool isOpen(); + void display(); +private: + bool is_open_ = false; +}; + +} // namespace gol diff --git a/src/control_menu.cpp b/src/control_menu.cpp index d91d3ff..2ec86cf 100644 --- a/src/control_menu.cpp +++ b/src/control_menu.cpp @@ -12,19 +12,13 @@ #include #include +#include #include #include namespace gol { ControlMenu::ControlMenu(std::shared_ptr context):context_(context) { - play_ctrl_ = true; - step_ctrl_ = false; - step_back_ctrl_ = false; - rand_ctrl_ = false; - edit_ctrl_ = false; - clear_ctrl_ = false; - paterns_ctrl_ = false; } void ControlMenu::update() { @@ -82,8 +76,8 @@ void ControlMenu::display() { ImGui::Checkbox("Edit", &edit_ctrl_); ImGui::Checkbox("Clear", &clear_ctrl_); ImGui::Checkbox("Randomize", &rand_ctrl_); - if (ImGui::Button((paterns_ctrl_) ? "Hide paterns" : "Show paterns")) { - paterns_ctrl_ = !paterns_ctrl_; + if (ImGui::Button((context_->paterns_menu->isOpen()) ? "Hide paterns" : "Show paterns")) { + context_->paterns_menu->Toogle(); } if (ImGui::Button((context_->settings_menu->isOpen()) ? "Hide settings" : "Show settings")) { context_->settings_menu->Toogle(); diff --git a/src/main.cpp b/src/main.cpp index 25482dc..6f7ebb2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,6 +24,7 @@ #include #include #include +#include int main(int ac, char **av) { std::shared_ptr context = std::make_shared(); @@ -96,6 +97,7 @@ int main(int ac, char **av) { context->render = std::make_shared(context->settings_menu->getCellSize()); context->selection_menu = std::make_shared(context); context->selection = std::make_shared(context); + context->paterns_menu = std::make_shared(); // Speed handling values float sim_speed = 1.0f; @@ -145,14 +147,7 @@ int main(int ac, char **av) { // Start ImGui frame rlImGuiBegin(); context->control_menu->display(); - if (context->control_menu->paterns_ctrl_) { - ImGuiWindowFlags paterns_flags = - ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; - ImGui::SetNextWindowSize(ImVec2(150, 200), ImGuiCond_Always); - ImGui::Begin("paterns", &context->control_menu->paterns_ctrl_, paterns_flags); - ImGui::Button("refresh"); - ImGui::End(); - } + context->paterns_menu->display(); context->settings_menu->display(); context->selection_menu->display(); // End ImGui frame diff --git a/src/paterns_menu.cpp b/src/paterns_menu.cpp new file mode 100644 index 0000000..ad450fa --- /dev/null +++ b/src/paterns_menu.cpp @@ -0,0 +1,35 @@ +/* +* File name: paterns_menu.cpp +* Author: lejulien +* Date created: 01-01-1970 00:59:59 +// Date modified: 12-01-2026 21:30:10 +* ------ +*/ + +#include + +#include +#include +#include + +namespace gol { + +void PaternsMenu::Toogle() { + is_open_ = !is_open_; +} + +bool PaternsMenu::isOpen() { + return is_open_; +} + +void PaternsMenu::display() { + if (is_open_) { + ImGuiWindowFlags paterns_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; + ImGui::SetNextWindowSize(ImVec2(150, 200), ImGuiCond_Always); + ImGui::Begin("paterns", &is_open_, paterns_flags); + ImGui::Button("refresh"); + ImGui::End(); + } +} + +} // namespace gol diff --git a/src/selection.cpp b/src/selection.cpp index c36cfd7..fac32b7 100644 --- a/src/selection.cpp +++ b/src/selection.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -24,7 +25,7 @@ Selection::Selection(std::shared_ptr context): context_(context) { void Selection::update() { auto gesture = GetGestureDetected(); mouse_pos_ = GetMousePosition(); - if (!context_->control_menu->edit_ctrl_ && !context_->control_menu->play_ctrl_ && !context_->control_menu->paterns_ctrl_ && !context_->settings_menu->isOpen()) { + if (!context_->control_menu->edit_ctrl_ && !context_->control_menu->play_ctrl_ && !context_->paterns_menu->isOpen() && !context_->settings_menu->isOpen()) { if (gesture == GESTURE_TAP && !ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow)) { sel_pos_ = snapToGrid(mouse_pos_, context_->settings_menu->getCellSize()); selecting_ = true; -- 2.49.1