---
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.
