// primitives_gallery — catalogo visual interactivo de los primitivos UI // del registry (cpp/functions/core y cpp/functions/viz). // // Sidebar izquierdo con lista de primitivos agrupados por dominio; panel // derecho renderiza la demo del item seleccionado (+ snippet de codigo). // // Rol: smoke test visual + documentacion viva + build gate en CI. // NO se conecta a sqlite_api ni a ningun backend. Datos sinteticos. #include "app_base.h" #include "imgui.h" #include "core/fullscreen_window.h" #include "core/tokens.h" #include "core/page_header.h" #include "core/toast.h" #include "core/app_menubar.h" #include "gfx/gl_loader.h" #include "demos.h" #include "demo.h" #include #include #include #include struct DemoEntry { const char* id; // id estable, apto para comparar seleccion const char* label; // texto en sidebar const char* category; // "Core" o "Viz" void (*fn)(); // puntero a la demo_xxx }; static const DemoEntry k_demos[] = { // Core {"button", "button", "Core", &gallery::demo_button}, {"icon_button", "icon_button", "Core", &gallery::demo_icon_button}, {"toolbar", "toolbar", "Core", &gallery::demo_toolbar}, {"modal_dialog", "modal_dialog", "Core", &gallery::demo_modal}, {"text_input", "text_input", "Core", &gallery::demo_text_input}, {"select", "select", "Core", &gallery::demo_select}, {"toast", "toast + inbox", "Core", &gallery::demo_toast}, {"tree_view", "tree_view", "Core", &gallery::demo_tree_view}, {"badge", "badge", "Core", &gallery::demo_badge}, {"empty_state", "empty_state", "Core", &gallery::demo_empty_state}, {"page_header", "page_header", "Core", &gallery::demo_page_header}, {"dashboard_panel", "dashboard_panel", "Core", &gallery::demo_dashboard_panel}, {"kpi_card", "kpi_card", "Core", &gallery::demo_kpi_card}, {"text_editor", "text_editor + watcher", "Core", &gallery::demo_text_editor}, // Viz {"bar_chart", "bar_chart", "Viz", &gallery::demo_bar_chart}, {"pie_chart", "pie_chart", "Viz", &gallery::demo_pie_chart}, {"line_plot", "line_plot", "Viz", &gallery::demo_line_plot}, {"scatter_plot", "scatter_plot", "Viz", &gallery::demo_scatter_plot}, {"histogram", "histogram", "Viz", &gallery::demo_histogram}, {"sparkline", "sparkline", "Viz", &gallery::demo_sparkline}, {"graph_viewport", "graph_viewport", "Viz", &gallery::demo_graph}, // Gfx (shaders_lab core) {"shader_canvas", "shader_canvas", "Gfx", &gallery::demo_shader_canvas}, }; static constexpr int k_demo_count = sizeof(k_demos) / sizeof(k_demos[0]); static std::string g_selected_id = "button"; static const DemoEntry* find_demo(const std::string& id) { for (int i = 0; i < k_demo_count; i++) { if (id == k_demos[i].id) return &k_demos[i]; } return &k_demos[0]; } static void draw_sidebar() { using namespace fn_tokens; ImGui::BeginChild("##gallery_sidebar", ImVec2(220, 0), ImGuiChildFlags_Borders); const char* current_category = nullptr; for (int i = 0; i < k_demo_count; i++) { const auto& d = k_demos[i]; if (!current_category || std::strcmp(current_category, d.category) != 0) { if (current_category) ImGui::Dummy(ImVec2(0, spacing::sm)); ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim); ImGui::TextUnformatted(d.category); ImGui::PopStyleColor(); ImGui::Separator(); current_category = d.category; } const bool selected = (g_selected_id == d.id); ImGui::PushStyleColor(ImGuiCol_Header, selected ? colors::surface_hover : ImVec4(0,0,0,0)); ImGui::PushStyleColor(ImGuiCol_HeaderHovered, colors::surface_hover); ImGui::PushStyleColor(ImGuiCol_HeaderActive, colors::surface); ImGui::PushStyleColor(ImGuiCol_Text, selected ? colors::primary : colors::text); char label[96]; std::snprintf(label, sizeof(label), "%s##sel_%s", d.label, d.id); if (ImGui::Selectable(label, selected)) { g_selected_id = d.id; } ImGui::PopStyleColor(4); } ImGui::EndChild(); } static void render() { static bool init_done = false; if (!init_done) { fn_tokens::apply_dark_theme(); // En Linux es no-op; en Windows resuelve los punteros GL via wglGetProcAddress. // Imprescindible antes de invocar primitivos que usen OpenGL 2.0+ (graph_viewport, // shader_canvas, etc). fn::gfx::gl_loader_init(); init_done = true; } // MainMenuBar (solo Settings — la gallery no tiene paneles toggleables ni layouts) fn_ui::app_menubar(nullptr, 0, nullptr); fullscreen_window_begin("##gallery"); page_header_begin("Primitives Gallery", "Visual catalog of fn_registry C++ UI primitives"); page_header_end(); if (ImGui::BeginTable("##layout", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit)) { ImGui::TableSetupColumn("sidebar", ImGuiTableColumnFlags_WidthFixed, 220.0f); ImGui::TableSetupColumn("content", ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); draw_sidebar(); ImGui::TableSetColumnIndex(1); ImGui::BeginChild("##gallery_content", ImVec2(0, 0), ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar); const DemoEntry* d = find_demo(g_selected_id); if (d && d->fn) d->fn(); ImGui::EndChild(); ImGui::EndTable(); } fullscreen_window_end(); // Toasts se renderizan encima para que el demo de toast funcione aqui tambien. fn_ui::toast_render(); } int main(int /*argc*/, char** /*argv*/) { return fn::run_app( {.title = "fn_registry · Primitives Gallery", .width = 1400, .height = 900, .viewports = true}, render ); }