--- id: "0041" title: "C++ app shell estandarizado: BEST_PRACTICES + AppConfig extendido" status: completado type: feature domain: - cpp-stack scope: app-scoped priority: alta depends: [] blocks: [] related: [] created: 2026-05-17 updated: 2026-05-17 tags: [] --- # 0041 — C++ app shell estandarizado: BEST_PRACTICES + AppConfig extendido ## Metadata | Campo | Valor | |-------|-------| | **ID** | 0041 | | **Estado** | pendiente | | **Prioridad** | alta | | **Tipo** | feature — C++ framework (`cpp/framework/`) + docs | ## Dependencias Ninguna. Habilita **0043** (estandarizar apps existentes) y todo desarrollo futuro de apps C++. --- ## Objetivo 1. Documentar el patron canonico de apps C++ del registry en `cpp/PATTERNS.md` con checklist obligatorio. 2. Extender `fn::AppConfig` para que `fn::run_app()` registre About + paneles + theming en una sola llamada, eliminando boilerplate por app. ## Contexto La auditoria muestra que `chart_demo`, `primitives_gallery`, `shaders_lab` y `registry_dashboard` arrancan distinto: solo `shaders_lab` aprovecha `app_menubar` con paneles, solo `registry_dashboard` registra About + Settings, `primitives_gallery` llama `apply_dark_theme()` + `gl_loader_init()` a mano que el resto delega a `run_app()`. Sin estandar, cada app proxima reinventa esto. ## Arquitectura ``` cpp/ ├── PATTERNS.md # NEW — checklist y patrones ├── framework/ │ ├── app_base.h # MOD — extender AppConfig │ └── app_base.cpp # MOD — aplicar nuevos campos └── functions/core/ └── (sin cambios — app_menubar/app_about/app_settings ya existen) ``` ### AppConfig extendido (propuesta) ```cpp struct AppAboutInfo { const char* name = nullptr; const char* version = nullptr; const char* description = nullptr; }; struct AppConfig { const char* title = "fn app"; int width = 1280; int height = 800; bool vsync = true; bool viewports = false; ThemeMode theme = ThemeMode::FnDark; float bg_r=0,bg_g=0,bg_b=0; // NEW — registra About si name != nullptr. AppAboutInfo about{}; // NEW — paneles toggleables del menubar (si != nullptr). const fn_ui::PanelToggle* panels = nullptr; size_t panel_count = 0; // NEW — callbacks de layouts persistentes (si != nullptr). fn_ui::LayoutCallbacks* layouts_cb = nullptr; // NEW — si true, llama gl_loader_init() antes del primer frame. bool init_gl_loader = false; }; ``` `run_app()` aplica: - Si `about.name != nullptr` → `fn_ui::about_window_set_info(...)`. - Si `init_gl_loader` → `fn::gfx::gl_loader_init()` tras crear el contexto GL. - Cada frame, si `panels != nullptr` o `layouts_cb != nullptr`, llama `app_menubar(panels, panel_count, layouts_cb)` automaticamente — la app NO la llama. ## Tareas ### Fase 1 — Doc 1.1 Crear `cpp/PATTERNS.md` con checklist: - Usa `fn::run_app()` con `AppConfig` (jamas `glfwInit` directo). - Registra About via `AppConfig::about` o `about_window_set_info()`. - Registra Settings extras via `settings_window_add_section()`. - Si tienes paneles, define `static constexpr fn_ui::PanelToggle panels[]` y pasalo en `AppConfig::panels`. - Si necesitas layouts, implementa `LayoutCallbacks` y pasalas en `AppConfig::layouts_cb`. - Usa `fn_tokens::colors|spacing|radius` siempre. Nunca colores hex literales. - Evita `ImGui::BeginTable / Selectable / BeginPopupModal / BeginChild` con styling manual — usa `dashboard_grid`, `tree_view`/`select`, `modal_dialog`, `dashboard_panel`. ### Fase 2 — Framework 2.1 Anadir campos `about`, `panels`, `panel_count`, `layouts_cb`, `init_gl_loader` a `AppConfig` en `app_base.h`. 2.2 En `run_app()` (`app_base.cpp`): - Tras `gl_loader_init` opcional. - Tras `about_window_set_info` si procede. - Antes del `render_fn()` por frame, llama `app_menubar(panels, panel_count, layouts_cb)` si alguno != nullptr. 2.3 Backward-compat: campos nuevos opcionales con defaults — apps existentes compilan sin tocarlas. ### Fase 3 — Validacion 3.1 Compilar todas las apps existentes sin cambios, verificar que no rompe. 3.2 Build Linux + cross-compile Windows. ### Fase 4 — Indexar 4.1 `./fn index` para refrescar metadata (no cambia funciones — solo doc). ## Decisiones de diseno - `AppConfig` con campos opcionales (no nuevos overloads de `run_app`) — minimiza la API surface. - La menubar se llama desde `run_app` solo si la app declara paneles/layouts; en otro caso la app puede llamar `app_menubar(nullptr,0,nullptr)` ella misma (compat). ## Riesgos - Apps que ya llaman `app_menubar` manualmente con `panels` distintos al `AppConfig`: documentar — `run_app` la llama una vez al inicio del frame, la app puede dejar de hacerlo. ## Validacion - `cpp/PATTERNS.md` legible en GitHub. - `chart_demo` (la mas simple) puede ahora declararse asi: ```cpp fn::run_app({.title="chart demo", .about={.name="chart demo", .version="0.1", .description="..."}}, render); ``` - Tests de compilacion OK para shaders_lab/chart_demo/primitives_gallery/registry_dashboard sin modificar.