# 0042 — C++ layout_storage: extraer y publicar como API reutilizable ## Metadata | Campo | Valor | |-------|-------| | **ID** | 0042 | | **Estado** | pendiente | | **Prioridad** | alta | | **Tipo** | feature — C++ core (`cpp/functions/core`) | ## Dependencias Ninguna. Habilita **0043** (estandarizar apps). --- ## Objetivo Extraer la persistencia de layouts ImGui (actualmente privada en `shaders_lab/main.cpp` lineas 415-447) a una funcion publica del registry: `layout_storage_cpp_core`. Cualquier app puede pasarla a `app_menubar` via `LayoutCallbacks` con un solo `setup`. ## Contexto `shaders_lab` guarda layouts (snapshots de `imgui.ini`) en SQLite via `shaderlab_db_cpp_core`. La logica que conecta SQLite con `LayoutCallbacks` (`save`, `load`, `list`, `remove`) esta inline en su `main.cpp` y no es reusable. Otras apps (registry_dashboard, primitives_gallery, chart_demo) no tienen layouts persistentes. ## Arquitectura ``` cpp/functions/core/ ├── layout_storage.h # NEW — API publica ├── layout_storage.cpp # NEW — impl con SQLite ├── layout_storage.md # NEW └── (opcional) layouts_menu.h ya existe — sin cambios cpp/apps/shaders_lab/ └── main.cpp # MOD — usa layout_storage en lugar de inline ``` ### API propuesta ```cpp namespace fn_ui { struct LayoutStorage; // opaque // Crea un storage que persiste layouts ImGui en una tabla SQLite del path dado. // Si la BD no existe, la crea. Tabla: `imgui_layouts(name TEXT PRIMARY KEY, ini TEXT, updated_at)`. LayoutStorage* layout_storage_open(const char* db_path); void layout_storage_close(LayoutStorage* s); // Helper que rellena un LayoutCallbacks usando este storage. // El caller mantiene vivo el storage durante la vida de los callbacks. void layout_storage_make_callbacks(LayoutStorage* s, LayoutCallbacks& out); } ``` `LayoutCallbacks` ya esta definido en `panel_menu.h`/`layouts_menu.h`. Esta funcion solo wirea SQLite. ## Tareas ### Fase 1 — Codigo 1.1 Crear `cpp/functions/core/layout_storage.{h,cpp,md}`. 1.2 Implementar usando sqlite3 vendoreada (`cpp/vendor/sqlite3`). Tabla unica `imgui_layouts`. 1.3 Save: serializa `ImGui::SaveIniSettingsToMemory()` y hace UPSERT por nombre. 1.4 Load: lee `ini` y llama `ImGui::LoadIniSettingsFromMemory(ini, len)`. 1.5 List: `SELECT name FROM imgui_layouts ORDER BY updated_at DESC`. 1.6 Remove: `DELETE FROM imgui_layouts WHERE name=?`. 1.7 Frontmatter `.md` con `purity: impure`, `error_type: error_go_core`, `uses_types: []`. ### Fase 2 — Migrar shaders_lab 2.1 Reemplazar el bloque inline (l. 415-447) por: ```cpp auto* g_layouts = fn_ui::layout_storage_open("shaders_lab.db"); fn_ui::LayoutCallbacks layouts_cb; fn_ui::layout_storage_make_callbacks(g_layouts, layouts_cb); // ...pasar layouts_cb a app_menubar ``` 2.2 Mantener `shaderlab_db_cpp_core` como esta (no es lo mismo: guarda shaders, no layouts) — pero quitar de el la parte de layouts si la tiene. 2.3 Verificar que los layouts existentes siguen cargando (compatibilidad de schema o migracion automatica). ### Fase 3 — Tests 3.1 Test unitario: open → save("test", ini) → list() == ["test"] → load("test") devuelve el ini → remove("test") → list() == []. 3.2 Test de regresion en shaders_lab (build + abrir/cerrar layout manual). ### Fase 4 — Indexar 4.1 `./fn index` y verificar `fn show layout_storage_cpp_core`. ## Decisiones de diseno - BD SQLite por app (no compartida) — cada app gestiona sus layouts. - Schema simple (`name PRIMARY KEY, ini, updated_at`) — sin namespaces ni jerarquia. - API opaca (`LayoutStorage*`) para no exponer sqlite3 en headers publicos. ## Riesgos - shaders_lab tiene layouts existentes en su `shaders_lab.db`. Si la tabla actual difiere del schema nuevo: migracion automatica al primer open o conservar ambas tablas. - Threading: ImGui::SaveIniSettingsToMemory solo es seguro desde el thread principal — documentar. ## Validacion ```bash cd cpp/build && cmake --build . --target shaders_lab # Abrir shaders_lab, guardar/cargar layouts, restart, verificar que persiste. ./fn show layout_storage_cpp_core ```