From f614e9774f32708d72fb8cf8c8e9ad9417a6070e Mon Sep 17 00:00:00 2001 From: Pcornat Date: Wed, 18 Mar 2026 14:59:04 +0100 Subject: [PATCH 1/4] Menu bar with Cambalache --- menu_bar.ui | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/menu_bar.ui b/menu_bar.ui index b2aa985..43842b8 100644 --- a/menu_bar.ui +++ b/menu_bar.ui @@ -1,5 +1,7 @@ - + + + From bae36631d2fb966b030625def72622b1ae71a304 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Wed, 18 Mar 2026 19:36:11 +0100 Subject: [PATCH 2/4] Properly removing a window --- app_win_2_back.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app_win_2_back.cpp b/app_win_2_back.cpp index b51ea15..951358f 100644 --- a/app_win_2_back.cpp +++ b/app_win_2_back.cpp @@ -16,6 +16,7 @@ namespace gui_to_app { namespace views = std::views; AppWin2Back::AppWin2Back() : Gtk::Application("org.billy_adventures.character_sheet", Flags::HANDLES_OPEN) { + signal_window_removed().connect([](const Gtk::Window *window) { delete window; }); Glib::set_application_name("Billy's character sheet"); selection_buttons.reserve(signal_handlers.size()); } @@ -215,9 +216,8 @@ namespace gui_to_app { void AppWin2Back::on_quit() noexcept { ranges::for_each(get_windows() | views::filter([](const auto windows) { return windows != nullptr; }), - [](auto *window) { - window->set_visible(false); - delete window; + [this](auto *window) { + remove_window(*window); }); quit(); } From 0b38380437c5ebf9991d963e3a4320a354982128 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Wed, 18 Mar 2026 19:39:02 +0100 Subject: [PATCH 3/4] Keeping both builders, renaming them. --- app_win_2_back.cpp | 59 +++++++++++++++++++++++++--------------------- app_win_2_back.hpp | 3 ++- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/app_win_2_back.cpp b/app_win_2_back.cpp index 951358f..eaec021 100644 --- a/app_win_2_back.cpp +++ b/app_win_2_back.cpp @@ -23,10 +23,15 @@ namespace gui_to_app { void AppWin2Back::on_startup() { Application::on_startup(); - const auto menu_bar = []() -> Glib::RefPtr { + const auto menu_bar = [this]() -> Glib::RefPtr { try { - const auto builder = Gtk::Builder::create_from_file("menu_bar.ui"); - return builder->get_object("menu"); + menu_builder = Gtk::Builder::create_from_file("menu_bar.ui"); + if (menu_builder != nullptr) { + return menu_builder->get_object("menu"); + } else { + spdlog::error("Error while loading menu bar UI"); + return nullptr; + } } catch (const std::exception &e) { spdlog::error("Error occurred while loader menu bar: {}", e.what()); return nullptr; @@ -73,18 +78,18 @@ namespace gui_to_app { } bool AppWin2Back::switches_procedure() { - sword_switch = app_builder->get_widget("sword_button"); - lance_switch = app_builder->get_widget("lance_button"); - morgen_switch = app_builder->get_widget("morgenstern_button"); - bow_switch = app_builder->get_widget("arc_button"); - chainmail_switch = app_builder->get_widget("chainmail_button"); - cookpot_switch = app_builder->get_widget("cookingpot_button"); - pamphlet_switch = app_builder->get_widget("pamphlet_tourist_button"); - medkit_switch = app_builder->get_widget("medkit_button"); - fourche_switch = app_builder->get_widget("fourche_button"); - dagger_switch = app_builder->get_widget("dagger_button"); - rock_kit_switch = app_builder->get_widget("rock_kit_button"); - sack_switch = app_builder->get_widget("sack_button"); + sword_switch = window_builder->get_widget("sword_button"); + lance_switch = window_builder->get_widget("lance_button"); + morgen_switch = window_builder->get_widget("morgenstern_button"); + bow_switch = window_builder->get_widget("arc_button"); + chainmail_switch = window_builder->get_widget("chainmail_button"); + cookpot_switch = window_builder->get_widget("cookingpot_button"); + pamphlet_switch = window_builder->get_widget("pamphlet_tourist_button"); + medkit_switch = window_builder->get_widget("medkit_button"); + fourche_switch = window_builder->get_widget("fourche_button"); + dagger_switch = window_builder->get_widget("dagger_button"); + rock_kit_switch = window_builder->get_widget("rock_kit_button"); + sack_switch = window_builder->get_widget("sack_button"); const auto test_result = ranges::to >( std::array{ @@ -143,7 +148,7 @@ namespace gui_to_app { void AppWin2Back::on_activate() { Application::on_activate(); - app_builder = [] -> Glib::RefPtr { + window_builder = [] -> Glib::RefPtr { try { return Gtk::Builder::create_from_file("window_ui.ui"); } catch (const std::exception &e) { @@ -151,16 +156,16 @@ namespace gui_to_app { return nullptr; } }(); - if (!app_builder) { + if (!window_builder) { spdlog::critical("Error while loading UI"); quit(); return; } - main_window = Gtk::Builder::get_widget_derived(app_builder, "main_window"); + main_window = Gtk::Builder::get_widget_derived(window_builder, "main_window"); if (main_window != nullptr) { add_window(*main_window); main_window->set_show_menubar(true); - main_window->set_visible(true); + main_window->present(); } else { spdlog::critical("Error while getting window from builder"); on_quit(); @@ -169,7 +174,7 @@ namespace gui_to_app { if (switches_procedure()) { return; } - debug_button = app_builder->get_widget("debug_button"); + debug_button = window_builder->get_widget("debug_button"); hab_labels = CaracInterface{ { "habilete_label_base", @@ -177,7 +182,7 @@ namespace gui_to_app { "habilete_label_materiel", "habilete_label_total" }, - app_builder + window_builder }; endu_labels = CaracInterface{ { @@ -186,7 +191,7 @@ namespace gui_to_app { "endurance_label_materiel", "endurance_label_total" }, - app_builder + window_builder }; addr_labels = CaracInterface{ { @@ -195,7 +200,7 @@ namespace gui_to_app { "adresse_label_materiel", "adresse_label_total" }, - app_builder + window_builder }; luck_labels = CaracInterface{ { @@ -204,12 +209,12 @@ namespace gui_to_app { "chance_label_materiel", "chance_label_total" }, - app_builder + window_builder }; - damage_label = app_builder->get_widget("label_degat"); - armor_label = app_builder->get_widget("label_armure"); - critic_label = app_builder->get_widget("label_critique"); + damage_label = window_builder->get_widget("label_degat"); + armor_label = window_builder->get_widget("label_armure"); + critic_label = window_builder->get_widget("label_critique"); debug_button->signal_clicked().connect(sigc::mem_fun(*this, &AppWin2Back::debug_button_clicked), false); } diff --git a/app_win_2_back.hpp b/app_win_2_back.hpp index 2865b72..1c35836 100644 --- a/app_win_2_back.hpp +++ b/app_win_2_back.hpp @@ -83,7 +83,8 @@ namespace gui_to_app { bool erase_obj(const character::billyEnums &obj) noexcept; - Glib::RefPtr app_builder; + Glib::RefPtr window_builder; + Glib::RefPtr menu_builder; learn_gtkmm4::HelloWorld *main_window{ nullptr }; selection_button *sword_switch{ nullptr }; selection_button *lance_switch{ nullptr }; From a84cace7b62f3bd569445347614e0eb5b940d9e4 Mon Sep 17 00:00:00 2001 From: Pcornat Date: Wed, 18 Mar 2026 19:39:25 +0100 Subject: [PATCH 4/4] Using resources instead of .ui files. --- CMakeLists.txt | 32 +++++++++++++++++++++++++++++++- app_win_2_back.cpp | 4 ++-- billy_gui.gresource.xml | 7 +++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 billy_gui.gresource.xml diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a67ac1..73d5617 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,12 @@ cmake_minimum_required(VERSION 3.30) -project(BillyGui LANGUAGES CXX) +project(BillyGui LANGUAGES C CXX) include(FetchContent) find_package(PkgConfig REQUIRED) pkg_check_modules(GTKMM4 REQUIRED IMPORTED_TARGET gtkmm-4.0) +find_program(GLIB_COMPILE_RESOURCES NAMES glib-compile-resources REQUIRED) + fetchcontent_declare(BillySheet GIT_REPOSITORY https://gitea.pcornatcloud.fr/Pcornat/BillySheet.git GIT_TAG main @@ -73,13 +75,41 @@ set(SPDLOG_NO_TLS ON) set(SPDLOG_NO_ATOMIC_LEVELS ON) fetchcontent_makeavailable(spdlog) +set(GRESOURCE_C resources.c) +set(GRESOURCE_XML billy_gui.gresource.xml) + +# Step 2: +add_custom_command( + OUTPUT ${GRESOURCE_C} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMAND ${GLIB_COMPILE_RESOURCES} + ARGS + --target=${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} ${GRESOURCE_XML} --generate-source + VERBATIM + MAIN_DEPENDENCY ${GRESOURCE_XML} + DEPENDS window_ui.ui menu_bar.ui +) + +# Step 3: +add_custom_target( + dummy-resource + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} +) + add_executable(${PROJECT_NAME} main.cpp hello_world.cpp hello_world.hpp app_win_2_back.cpp app_win_2_back.hpp + ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} ) +set_source_files_properties( + ${CMAKE_CURRENT_BINARY_DIR}/${GRESOURCE_C} + PROPERTIES GENERATED TRUE +) +add_dependencies(${PROJECT_NAME} dummy-resource) + set_target_properties(${PROJECT_NAME} spdlog_header_only PROPERTIES CXX_STANDARD 23 CXX_STANDARD_REQUIRED ON diff --git a/app_win_2_back.cpp b/app_win_2_back.cpp index eaec021..0138856 100644 --- a/app_win_2_back.cpp +++ b/app_win_2_back.cpp @@ -25,7 +25,7 @@ namespace gui_to_app { Application::on_startup(); const auto menu_bar = [this]() -> Glib::RefPtr { try { - menu_builder = Gtk::Builder::create_from_file("menu_bar.ui"); + menu_builder = Gtk::Builder::create_from_resource("/org/gtkmm/billy_gui/menu_bar.ui"); if (menu_builder != nullptr) { return menu_builder->get_object("menu"); } else { @@ -150,7 +150,7 @@ namespace gui_to_app { window_builder = [] -> Glib::RefPtr { try { - return Gtk::Builder::create_from_file("window_ui.ui"); + return Gtk::Builder::create_from_resource("/org/gtkmm/billy_gui/window_ui.ui"); } catch (const std::exception &e) { spdlog::critical("Error occurred while loading Window's UI: {}", e.what()); return nullptr; diff --git a/billy_gui.gresource.xml b/billy_gui.gresource.xml new file mode 100644 index 0000000..0d1fb18 --- /dev/null +++ b/billy_gui.gresource.xml @@ -0,0 +1,7 @@ + + + + window_ui.ui + menu_bar.ui + + \ No newline at end of file