Merge pull request 'lju/load-paterns' (#3) from lju/load-paterns into main

Reviewed-on: #3
This commit was merged in pull request #3.
This commit is contained in:
2026-01-14 12:18:57 +00:00
5 changed files with 129 additions and 42 deletions

View File

@@ -33,6 +33,7 @@ typedef struct ctx {
std::shared_ptr<Selection> selection = nullptr; std::shared_ptr<Selection> selection = nullptr;
std::shared_ptr<PaternsMenu> paterns_menu = nullptr; std::shared_ptr<PaternsMenu> paterns_menu = nullptr;
nlohmann::json config_json; nlohmann::json config_json;
std::filesystem::path program_dir;
} ctx; } ctx;
} // namespace gol } // namespace gol

View File

@@ -8,17 +8,31 @@
#pragma once #pragma once
#include <memory>
#include <context.hpp>
#include <vector>
#include <map>
#include <string>
namespace gol { namespace gol {
class PaternsMenu { class PaternsMenu {
public: public:
PaternsMenu() = default; PaternsMenu(std::shared_ptr<ctx>);
~PaternsMenu() = default; ~PaternsMenu() = default;
void Toogle(); void Toogle();
bool isOpen(); bool isOpen();
void display(); void display();
void refresh();
private: private:
bool loadPatern(std::string &path);
bool is_open_ = false; bool is_open_ = false;
std::shared_ptr<ctx> context_ = nullptr;
std::map<std::string,std::string> paterns_paths_list_;
std::vector<std::string> paterns_name_list_;
int patern_width_ = 0;
int patern_height_ = 0;
std::vector<uint32_t> loaded_patern_;
}; };
} // namespace gol } // namespace gol

View File

@@ -82,6 +82,15 @@ int main(int ac, char **av) {
context->config_json["fps"] = 800; context->config_json["fps"] = 800;
} }
// Get program directory
char path_buf[1024];
ssize_t len = readlink("/proc/self/exe", path_buf, sizeof(path_buf)-1);
if (len == -1) {
std::cerr << "Failed to determine program directory" << std::endl;
return 1;
}
context->program_dir = std::filesystem::path(path_buf).parent_path();
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]); &av[0][2]);
@@ -97,7 +106,7 @@ int main(int ac, char **av) {
context->render = std::make_shared<Render>(context->settings_menu->getCellSize()); context->render = std::make_shared<Render>(context->settings_menu->getCellSize());
context->selection_menu = std::make_shared<gol::SelectionMenu>(context); context->selection_menu = std::make_shared<gol::SelectionMenu>(context);
context->selection = std::make_shared<gol::Selection>(context); context->selection = std::make_shared<gol::Selection>(context);
context->paterns_menu = std::make_shared<gol::PaternsMenu>(); context->paterns_menu = std::make_shared<gol::PaternsMenu>(context);
// Speed handling values // Speed handling values
float sim_speed = 1.0f; float sim_speed = 1.0f;
@@ -106,6 +115,7 @@ int main(int ac, char **av) {
// Setups // Setups
context->rules->setup(context->world); context->rules->setup(context->world);
context->paterns_menu->refresh();
// Diplay generations // Diplay generations
while (!WindowShouldClose()) { while (!WindowShouldClose()) {
// Frames shinenigans // Frames shinenigans

View File

@@ -6,30 +6,94 @@
* ------ * ------
*/ */
#include <paterns_menu.hpp>
#include <imgui.h> #include <imgui.h>
#include <raylib.h> #include <raylib.h>
#include <rlImGui.h> #include <rlImGui.h>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <paterns_menu.hpp>
#include <sstream>
namespace gol { namespace gol {
void PaternsMenu::Toogle() { PaternsMenu::PaternsMenu(std::shared_ptr<ctx> ctx) : context_(ctx) {}
is_open_ = !is_open_;
void PaternsMenu::Toogle() { is_open_ = !is_open_; }
bool PaternsMenu::isOpen() { return is_open_; }
void PaternsMenu::refresh() {
paterns_name_list_.clear();
paterns_paths_list_.clear();
auto paterns_path = context_->program_dir / "paterns";
if (std::filesystem::exists(paterns_path) &&
std::filesystem::is_directory(paterns_path)) {
for (const auto &entry :
std::filesystem::directory_iterator(paterns_path)) {
if (!std::filesystem::is_directory(entry) &&
entry.path().has_filename()) {
paterns_paths_list_[entry.path().filename()] = entry.path();
paterns_name_list_.push_back(entry.path().filename());
}
}
}
} }
bool PaternsMenu::isOpen() { bool PaternsMenu::loadPatern(std::string &path) {
return is_open_; std::ifstream file(path);
std::string file_data;
if (!file.is_open()) {
std::cerr << "Failure in opening patern : " << path << std::endl;
return false;
}
loaded_patern_.clear();
try {
std::getline(file, file_data);
std::stringstream ss(file_data);
std::string width, height, data;
std::getline(ss, width, '|');
std::getline(ss, height, '|');
std::getline(ss, data, '|');
patern_width_ = std::stoi(width);
patern_height_ = std::stoi(height);
for (int i = 0; i < patern_width_ * patern_height_; i++) {
loaded_patern_.push_back((data[i] == '1') ? 1 : 0);
}
} catch (std::exception &e) {
std::cerr << "Failure in loading patern : " << path << std::endl;
return 1;
}
return true;
} }
void PaternsMenu::display() { void PaternsMenu::display() {
if (is_open_) { if (is_open_) {
ImGuiWindowFlags paterns_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize; ImGuiWindowFlags paterns_flags =
ImGui::SetNextWindowSize(ImVec2(150, 200), ImGuiCond_Always); ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize;
ImGui::SetNextWindowSize(ImVec2(200, 250), ImGuiCond_Always);
ImGui::Begin("paterns", &is_open_, paterns_flags); ImGui::Begin("paterns", &is_open_, paterns_flags);
ImGui::Button("refresh"); for (auto patern_name : paterns_name_list_) {
ImGui::PushID(patern_name.c_str());
if (ImGui::Button(patern_name.c_str()) &&
loadPatern(paterns_paths_list_[patern_name])) {
// TODO: If patern is loaded successfuly, start the preview in the
// editor
}
ImGui::PopID();
ImGui::SameLine(ImGui::GetWindowWidth() - 57.);
std::string del_id = patern_name.c_str();
del_id.append("_del");
ImGui::PushID(del_id.c_str());
if (ImGui::Button("delete")) {
std::filesystem::remove(paterns_paths_list_[patern_name]);
refresh();
}
ImGui::PopID();
}
ImGui::End(); ImGui::End();
} }
} }
} // namespace gol } // namespace gol

View File

@@ -12,6 +12,7 @@
#include <filesystem> #include <filesystem>
#include <selection_menu.hpp> #include <selection_menu.hpp>
#include <paterns_menu.hpp>
namespace gol { namespace gol {
@@ -62,41 +63,38 @@ void SelectionMenu::display() {
rlImGuiImageSize(&selectionTexture_.texture, 200, 200); rlImGuiImageSize(&selectionTexture_.texture, 200, 200);
ImGui::InputText("patern_name", patern_name_, 255); ImGui::InputText("patern_name", patern_name_, 255);
if (ImGui::Button("Save")) { if (ImGui::Button("Save")) {
char path_buf[1024]; // Create paterns dir if not present
ssize_t len = readlink("/proc/self/exe", path_buf, sizeof(path_buf)-1); std::filesystem::path paterns_dir = context_->program_dir / "paterns";
if (len != -1) { if (!std::filesystem::exists(paterns_dir) && !std::filesystem::create_directory(paterns_dir)) {
// Create paterns dir if not present std::cerr << "Failed to create paterns directory" << std::endl;
std::filesystem::path paterns_dir = std::filesystem::path(path_buf).parent_path() / "paterns"; } else { // Could be optimized by early returning in a function
if (!std::filesystem::exists(paterns_dir) && !std::filesystem::create_directory(paterns_dir)) { std::ofstream patern_file;
std::cerr << "Failed to create paterns directory" << std::endl; paterns_dir += '/';
} else { // Could be optimized by early returning in a function paterns_dir += patern_name_;
std::ofstream patern_file; patern_file.open(paterns_dir);
paterns_dir += '/'; if (!patern_file) {
paterns_dir += patern_name_; std::cerr << "Failed to create the patern file" << std::endl;
patern_file.open(paterns_dir); } else {
if (!patern_file) { auto sel_it = sel_data_.begin();
std::cerr << "Failed to create the patern file" << std::endl; sel_it += 2; // skip dimensions
} else { patern_file << sel_data_[0];
auto sel_it = sel_data_.begin(); patern_file << "|"; // Separator needed to split as ascii values
sel_it += 2; // skip dimensions patern_file << sel_data_[1];
patern_file << sel_data_[0]; patern_file << "|"; // Separator needed to split as ascii values
patern_file << "|"; // Separator needed to split as ascii values for (int j = 0; j < sel_data_[1]; j++) {
patern_file << sel_data_[1]; for (int i = 0; i < sel_data_[0]; i++) {
patern_file << "|"; // Separator needed to split as ascii values patern_file << std::to_string(*sel_it);
for (int j = 0; j < sel_data_[1]; j++) { if (*sel_it == 1) {
for (int i = 0; i < sel_data_[0]; i++) {
patern_file << std::to_string(*sel_it);
if (*sel_it == 1) {
}
sel_it++;
} }
sel_it++;
} }
patern_file << std::flush;
patern_file.close();
} }
patern_file << std::flush;
patern_file.close();
context_->paterns_menu->refresh();
} }
sel_ctrl_ = false;
} }
sel_ctrl_ = false;
} }
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button("Discard")) { if (ImGui::Button("Discard")) {