Files
fn_registry/dev/issues/completed/0041-cpp-app-best-practices.md

5.2 KiB

id, title, status, type, domain, scope, priority, depends, blocks, related, created, updated, tags
id title status type domain scope priority depends blocks related created updated tags
0041 C++ app shell estandarizado: BEST_PRACTICES + AppConfig extendido completado feature
cpp-stack
app-scoped alta
2026-05-17 2026-05-17

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)

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 != nullptrfn_ui::about_window_set_info(...).
  • Si init_gl_loaderfn::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:
    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.