Commit Graph

122 Commits

Author SHA1 Message Date
egutierrez 35312ea66e feat(viz): graph_force_layout_gpu compute + spatial hash (issue 0049h)
Layout force-directed en GPU usando 5 compute shaders 4.3 + spatial hash
grid 64x64. API simetrica con graph_force_layout (CPU) para que el consumer
pueda swappear sin cambios. atomicCompSwap loop para float-add portable.

- cpp/functions/viz/graph_force_layout_gpu.{h,cpp,md}: nuevo modulo
- cpp/functions/gfx/gl_loader: anade glDispatchCompute, glMemoryBarrier,
  glBindBufferBase, glGetBufferSubData (Windows wgl)
- cpp/tests/test_graph_force_layout_gpu.cpp: smoke + pinned + CPU vs GPU.
  Crea ventana GLFW oculta GL 4.3; SKIP si headless o sin compute.
- demos_graph: checkbox "GPU layout" para swappear CPU/GPU en runtime
- issue movido a dev/issues/completed/
2026-04-29 23:29:16 +02:00
egutierrez 54cee13e8e feat(viz): graph_sources lector operations.db + streaming (issue 0049g)
- graph_load_from_operations: SQLite read-only, schema-detect (type_ref/type,
  from_entity/source, to_entity/target, name/type, weight, updated_at).
- 16-color indigo palette por hash FNV1a32 del nombre de tipo. user_data
  por nodo es FNV1a64(entity.id) — deterministico entre cargas.
- Label pool interno: metadata.name (JSON simple) > entities.name > id.
- graph_free libera nodes/edges/types/rel_types/labels/strdup'd names via
  arena_map (GraphData* -> arena).
- Streaming pull-based con tiebreak (updated_at, id) y crecimiento x2 de
  capacidad. Tipos nuevos descubiertos en stream se anaden a types.
- Tests: fixture in-memory (3 entity types, 2 rel types, 10 entities,
  15 relations) + smoke contra apps/script_navegador/operations.db.
- Issue movido a completed/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 23:12:31 +02:00
egutierrez ac11300335 feat(viz): renderer shapes/iconos/flechas/edge-styles (issue 0049f)
graph_renderer 1.5.0:
- 6 shapes SDF (circle, square, diamond, hex, triangle, rounded square)
  con dispatch en fragment shader y AA via fwidth.
- Atlas opcional de iconos Tabler bakeado por graph_icons; el shader
  compone overlay desde un uniform vec4 u_icon_uvs[256]. Setter publico
  graph_renderer_set_icon_atlas(r, tex, uv_table, count).
- Aristas direccionales: 6 vertices por arista (line + chevron de la
  flecha) en una sola draw call; segmento principal acortado por el
  radio del nodo target.
- Edge styles solid/dashed/dotted via descarte por arc_length en el
  fragment shader; las lineas del chevron son siempre solidas.

graph_icons 1.0.0 (nuevo):
- Atlas RGBA8 512x512 = grid 16x16 (256 iconos max) bakeado con
  stb_truetype desde tabler-icons.ttf.
- API: graph_icons_build/texture/region/uv_table/destroy. icon_id es
  1-based; 0 reservado para "sin icono".
- Hook FN_GRAPH_ICONS_SKIP_GL=1 para tests sin contexto GL.

Demo demos_graph_styles en primitives_gallery: 6 EntityTypes (uno por
shape) con icono Tabler representativo + 3 RelationTypes (knows/uses/
owns) con flechas direccionales y los 3 estilos.

test_graph_icons: 6 casos cubriendo bake, regiones 1-indexed, uv_table
consistente, layout en grid 16x16, validacion de count fuera de rango,
y verificacion de alpha != 0 en las celdas tras bake.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 23:01:49 +02:00
egutierrez b9ffc13caf feat(viz): graph_types modelo extendido + EntityType/RelationType + flags (issue 0049e)
Extiende el modelo agnostico de graph_types.h para soportar shapes/iconos/
filtros/labels/streaming sin acoplar a backend. Migra el unico consumer
(demos_graph) en el mismo cambio.

- GraphNode v2: type_id + shape_override/color_override/size_override +
  flags (NF_PINNED/VISIBLE/SELECTED/HOVERED) + label_idx + user_data.
- GraphEdge v2: type_id + style_override + flags (EF_DIRECTED/VISIBLE).
- EntityType / RelationType: tablas en GraphData (types, rel_types).
- Helpers de resolucion (resolve_node_color/shape/size, resolve_edge_*)
  y constructores ergonomicos (graph_node, graph_edge, entity_type,
  relation_type) — sentinel-based para herencia automatica del tipo.
- graph_renderer v1.4: lee NF_VISIBLE / EF_VISIBLE, resuelve apariencia
  via override → EntityType → fallback indexado por type_id. Skipea
  aristas con endpoints invisibles. Shapes siguen pintandose como
  circulo (0049f cableara el dispatch real).
- graph_force_layout v1.2: pinned ahora vive en flags & NF_PINNED.
- graph_viewport v1.1: hover/seleccion publican NF_HOVERED/SELECTED en
  el grafo (clear-then-set). Drag usa NF_PINNED. Tooltip muestra Type/
  user_data en lugar de community/value/label.
- demos_graph: 8 EntityType (paleta antigua) + 1 RelationType. type_id
  por cluster. user_data = indice numerico del nodo. Apariencia visual
  identica al pre-cambio.
- test_graph_types.cpp: 12 casos cubriendo helpers, defaults, bitmask
  manipulation y resoluciones override-vs-EntityType. test_graph_edge_
  static actualizado al nuevo modelo (ya no tiene .color directo).
- 4 .md de tipos nuevos (graph_node, graph_edge, entity_type,
  relation_type) + GraphData v2.0 actualizado.

Tests: 31/31 ctest verdes (incluye test_visual golden).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 22:44:40 +02:00
egutierrez 79b5f0b194 perf(viz): graph_renderer edges via TBO + vertex pulling (issue 0049d)
El buffer de aristas pasa a estatico (16B/arista: source, target, color,
flags) y solo se reupload cuando cambia el grafo. Las posiciones de los
nodos viven en un Texture Buffer Object (RG32F) actualizado por frame; el
vertex shader hace texelFetch con gl_VertexID & 1 para elegir endpoint.
Draw call: glDrawArraysInstanced(GL_LINES, 0, 2, edge_count) con divisor=1.

Para 100k aristas: el upload de 4.8 MB/frame baja a 0 en regimen estable.
edge_alpha pasa a uniform; la pre-multiplicacion en CPU desaparece. GLSL
sigue en 330 core (samplerBuffer/texelFetch estan en 1.40+).

gl_loader gana glBufferSubData, glVertexAttribIPointer y glTexBuffer (en
Linux ya estaban via GL_GLEXT_PROTOTYPES; ahora estan disponibles tambien
en MinGW/Windows).

Tests: nuevo test_graph_edge_static valida el layout de 16B y el packing
RGBA8 del fallback. test_visual sigue verde — render visualmente identico.

Bump graph_renderer 1.2.0 -> 1.3.0.
2026-04-29 22:32:38 +02:00
egutierrez 427262b892 perf(viz): graph_renderer Tier 1 (RGBA8 + orphan + frustum cull) + force_layout auto-pause helper
Issue 0049c. Tres optimizaciones internas en graph_renderer.cpp + un
helper puro en graph_force_layout para detectar convergencia. API publica
intacta — solo cambian el layout interno de los buffers, el shader y
los costes por frame.

1. RGBA8 color packing
   - El instance buffer de nodos pasa de (x,y,size,r,g,b,a) 28B a
     (x,y,size,color_u32) 16B (-43%). Aristas: 24B → 12B/vertex (-50%).
   - Shaders desempaquetan con bit shifts (compatible GL 3.30+, no
     necesita unpackUnorm4x8 que es 4.20+).
   - Helpers expuestos: pack_rgba8 / unpack_rgba8 / modulate_alpha_rgba8
     en graph_renderer.h. Los GraphNode.color y la paleta ya tenian el
     layout correcto (R en LSB), asi que CPU ahora pasa el uint32 directo
     sin convertir a 4 floats por nodo y por frame.

2. Capacity-tracked streaming buffers
   - Sustituye el doble glBufferData de antes por:
       glBufferData(NULL, capacity, STREAM_DRAW)   // orphan + reserva
       glBufferSubData(0, used_bytes, data)        // solo lo usado
   - capacity crece x2 cuando hace falta (inicial 4096 nodos /
     8192 vertices de aristas) → reallocaciones en O(log N).
   - Staging CPU (NodeInstance* / EdgeVertex*) reusado entre frames con
     realloc, no malloc/free per frame.

3. Frustum cull (CPU-side)
   - AABB del viewport en world coords con margen 10%.
   - Aristas: skip si AABB del segmento no intersecta el viewport.
   - Nodos: solo los visibles entran al instance buffer; visible_count
     es el N que pasa a glDrawArraysInstanced. Pop-in de borde mitigado
     por el margen.

4. graph_force_layout_should_pause(low_frames, min_consecutive)
   - Helper puro: el caller mantiene el contador, la funcion solo
     decide si parar. Reemplaza la rama inline en demos_graph.cpp.
   - Test Catch2 con secuencias artificiales.

Tests: test_graph_pack_rgba8 (16401 asserts, 4 cases — roundtrip exhaustivo
+ alpha modulation + clamp). test_graph_should_pause (3 cases, 14 asserts).
Los 29 tests del cpp/tests/ siguen verdes (incluido test_visual con goldens).

Bump versiones:
- graph_renderer 1.1.0 → 1.2.0
- graph_force_layout 1.0.0 → 1.1.0  (tested: true via should_pause test)
2026-04-29 22:17:13 +02:00
egutierrez 97725e0641 feat(graph): wheel-zoom no scrollea, slider 1M nodos, edges/node configurable
Tres mejoras de UX/escala en el demo de grafos:

1. **Wheel zoom dentro del canvas no scrollea la pagina**
   En graph_viewport.cpp tras procesar MouseWheel para zoom hacemos
   io.MouseWheel = 0 — consume el evento para que el BeginChild padre
   (la galeria) no scrollee a la vez que el grafo se acerca. Antes
   sentia "doble accion" al rodar la rueda sobre el canvas.

2. **graph_force_layout: pool dinamico (soporta 1M nodos)**
   El array static QuadNode[1<<20] (~48MB siempre reservados, tope
   rigido en ~250k nodos por la fan-out) se reemplaza por
   std::vector<QuadNode>. graph_force_layout_step llama a
   quad_pool_reserve(5*N + 1024) ANTES de construir el arbol — asi las
   referencias QuadNode& que mantenemos vivas durante quad_subdivide
   no se invalidan por reallocaciones a mitad del build (resize solo
   ocurre en el reserve inicial). Memoria escala lineal con N: 1M
   nodos ≈ 240MB de pool, una vez por programa.

3. **Demo de grafo: sliders extendidos + cluster_r escala con sqrt(N)**
   - "Nodes" pasa de 100..20k a 100..1M con escala logaritmica
     (ImGuiSliderFlags_Logarithmic) para que el rango medio sea util.
   - Nuevos sliders "Edges/node" (1..10) e "Inter %" (0..30%) — antes
     hardcoded a 3 y 5%.
   - cluster_radius y scatter ahora escalan con sqrt(N): a 1k nodos
     ~370 px de radio, a 1M ~12000 px. Antes era constante a 200/40
     y los nodos quedaban empaquetados al subir N — visualmente "sin
     limite cuadrado", esparcidos sobre un area proporcional al grafo.
   - Golden de graph_viewport regenerado por la nueva fila de sliders.

Notas:
- A 1M nodos sin GPU compute esta limitado por el upload de aristas
  (vertex pulling con TBO llega en 0049d). Render mantenible hasta
  ~200-300k.
- En Linux/Windows ambos builds limpios. 27/27 tests verde.
2026-04-29 21:53:33 +02:00
egutierrez 32e58556fa perf(graph): quick wins — OpenMP force step + buffer orphan + auto-pause
Tres atajos de rendimiento sin GPU compute (eso llega en 0049h). Probados
en Linux y cross-compile Windows, todos los tests pasan, OpenMP 4.5
detectado.

1. **OpenMP en graph_force_layout_step** (cpp/functions/viz/...)
   - find_package(OpenMP) en cpp/CMakeLists.txt; fn_framework lo enlaza
     PUBLIC para que cualquier app/funcion lo herede transparentemente.
     Si no esta disponible, los pragmas se ignoran (single-thread).
   - #pragma omp parallel for con guard if(N>=1024) en los 4 bucles
     embarazosamente paralelos: zero forces, repulsion Barnes-Hut (con
     schedule dynamic), gravity, integration (con reduction sobre energy).
     La attraction-along-edges se queda secuencial: edges multiples
     escriben en el mismo nodo y meterle atomic mata el speedup.
   - quad_force usaba un static int stack[1<<20] (4MB compartidos entre
     threads — race). Lo reemplazo por int stack[256] en pila: el
     quadtree crece como log4(N) ~= 10 niveles para N <= 1M, asi que 256
     es holgado y thread-safe sin coste.
   - Esperable: ~4-8x menos tiempo CPU/step en 20k nodos en CPU multicore.

2. **Buffer orphan en graph_renderer** (edges + nodes)
   - Antes del glBufferData(.., data, DYNAMIC_DRAW), un primer
     glBufferData(.., NULL, DYNAMIC_DRAW) que descarta el buffer previo.
     El driver da uno fresco sin esperar al frame anterior — evita los
     sync stalls clasicos del DYNAMIC_DRAW reuploadeado cada frame.
   - Esperable: 2-3x throughput de upload (Mesa/NVIDIA/AMD respetan el
     hint).

3. **Auto-pause en demo_graph cuando converge**
   - Si energy_per_node < 0.001 durante 30 frames consecutivos, paramos
     la simulacion automaticamente. CPU/GPU a 0% cuando el grafo ya
     esta estable. Resume con "Resume layout" o "Regenerate".

Lo de OpenMP se sustituye cuando entre 0049h (force layout en compute
shader): cuando llegue, los #pragma omp se borran. Orphan y auto-pause
son keepers definitivos.
2026-04-29 21:38:13 +02:00
egutierrez ebc012a5db fix(primitives_gallery): preserve scroll position when font size changes
Cuando se cambia "Size" en Settings la fuente se escala via
style.FontSizeBase y el contenido del child "##gallery_content" crece o
encoge proporcionalmente. La scroll_y se quedaba en pixeles absolutos,
asi que la linea logica visible "se bajaba" al usuario tras el cambio
de zoom.

Fix: cachear FontSizeBase entre frames y, cuando cambia, escalar
scroll_y por el ratio nuevo/viejo. Mantiene la misma linea arriba del
viewport — sin saltos.
2026-04-29 21:32:44 +02:00
egutierrez 2124f6be07 feat(framework): bump OpenGL 3.3 → 4.3 core context
Cierra 0049b. El context de fn::run_app pide ahora GL 4.3 core con
forward-compat global, habilitando compute shaders, SSBOs, image
load/store y atomic counters — bloques esenciales del graph_renderer GPU
del proyecto osint_graph (issues 0049f y 0049h).

Cambios:

- cpp/framework/app_base.cpp: 4.3 core + forward-compat. Comentario
  marcando que es backward-compatible con shaders #version 330.
- cpp/apps/primitives_gallery/capture.cpp: deja explicitamente 3.3 core
  porque WSL Mesa no entrega 4.3 offscreen (GLXBadFBConfig); ImGui +
  ImPlot funcionan igual en 3.3 para los goldens.
- primitives_gallery: nuevo demo Gfx > gl_info que muestra
  Vendor/Renderer/Version/GLSL en runtime + status 4.3 (verde) +
  limites (MAX_TEXTURE_SIZE, MAX_VERTEX_ATTRIBS, MAX_UNIFORM_BLOCK_SIZE
  y, si 4.3+, MAX_SHADER_STORAGE_BUFFER_BINDINGS y compute shared mem).
  Solo glGetString/glGetIntegerv — sin loader extra.
- About bumped a 0.4.0 con la nota del nuevo demo y de GL 4.3.
- cpp/tests/test_visual.cpp: usa LIBGL_ALWAYS_SOFTWARE=1 al lanzar el
  capture para alinear el driver con update_goldens.sh; sin esto las
  diferencias de strings (llvmpipe vs d3d12) hacen que gl_info supere
  el 1% de tolerancia.
- cpp/tests/golden/gl_info.png: nuevo golden.

Build verificado en Linux (cmake build OK) + Windows cross-compile
(cmake build OK). Las 27 pruebas pasan (incluida test_visual con 42
demos comparadas).
2026-04-29 21:23:15 +02:00
egutierrez 6dd1fe07bd feat(cpp/apps): bump versions — chart_demo 0.2, gallery 0.3, shaders_lab 0.3 2026-04-29 00:56:24 +02:00
egutierrez 9b2745fa25 feat(cpp/framework): viewports=true por defecto en AppConfig — ventanas arrastrables fuera del main 2026-04-29 00:54:43 +02:00
egutierrez cbe162630c fix(primitives_gallery): Windows mkdir() solo acepta el path en --capture 2026-04-29 00:31:53 +02:00
egutierrez 2aceccfd7e refactor(shaders_lab): usar modal_dialog en save-as (issue 0046)
El modal Save-as-generator usaba BeginPopupModal + InputText + Button
crudo. Ahora usa fn_ui::modal_dialog_begin/end + fn_ui::text_input +
fn_ui::button del registry. El error inline usa fn_tokens::colors::error
en vez de ImVec4(1, 0.4, 0.4, 1). Anade modal_dialog.cpp, text_input.cpp
y button.cpp al CMakeLists del app.

Raw ImGui::Begin*/Selectable/BeginPopupModal: 11 -> 8.
2026-04-29 00:29:50 +02:00
egutierrez cd445d8e1a refactor(primitives_gallery): usar tree_view en sidebar (issue 0046)
El sidebar agrupaba demos por categoria con un Selectable+PushStyleColor
manual por item. Ahora usa fn_ui::tree_view con las categorias como
ramas (default-open via SetNextItemOpen + ImGuiCond_FirstUseEver) y las
demos como hojas seleccionables. Visualmente equivalente: separadores
por categoria, item activo coloreado.

Raw ImGui::Begin*/Selectable: 4 -> 3 (Selectable eliminado).
2026-04-29 00:29:44 +02:00
egutierrez 33aace3686 docs(cpp): tests visuales y CI gate en PATTERNS.md
Nueva seccion "Tests visuales y CI gate (issue 0048)" describiendo:
- Como capturar/regenerar goldens con cpp/scripts/update_goldens.sh.
- Como diagnosticar un diff (PNG actual en cpp/build/tests/visual_actual/
  vs golden en cpp/tests/golden/).
- Cuando test_visual SKIPea (sin goldens, sin binario, sin GL).
- CI gate check_tested.sh y los pasos para satisfacerlo.

Issue 0048.
2026-04-29 00:18:51 +02:00
egutierrez cbc0714c80 chore(cpp/scripts): update_goldens.sh y check_tested.sh
- update_goldens.sh: build primitives_gallery + lanza --capture sobre
  cpp/tests/golden/ con LIBGL_ALWAYS_SOFTWARE=1.
- check_tested.sh [days]: CI gate que falla si una funcion C++ creada en
  los ultimos N dias (default 30) no tiene tested:true en su .md. Hookeado
  al final de run_tests.sh. No-op si registry.db no existe.

Issue 0048.
2026-04-29 00:18:45 +02:00
egutierrez 405ceacb0a feat(cpp/tests): test_visual con png diff vs goldens (skip si vacio)
- png_diff.{h,cpp}: pixel_diff_ratio(path_a, path_b, channel_threshold) con
  stb_image. Devuelve PngDiffResult con pixels_total, pixels_different y
  diff_ratio. Si dimensiones difieren, diff_ratio=1.0.
- test_visual.cpp: invoca primitives_gallery --capture sobre tmpdir, compara
  cada PNG vs cpp/tests/golden/<demo>.png con tolerancia 1% pixels distintos
  (threshold 5/255 por canal). SKIPea con WARN si:
  * golden dir vacio (no hay goldens todavia)
  * binario primitives_gallery no construido
  * el binario falla al capturar (entorno sin GL)
- CMakeLists: registra test_visual con FN_TEST_GOLDEN_DIR, FN_TEST_GALLERY_BIN,
  FN_TEST_TMP_DIR y FN_TEST_REPO_ROOT (para que la captura corra desde la
  raiz del repo y resuelva paths relativos como sql_workbench's registry.db).
- golden/: 41 PNGs iniciales generados en este entorno (WSL +
  LIBGL_ALWAYS_SOFTWARE=1). Pueden regenerarse con cpp/scripts/update_goldens.sh.

Issue 0048.
2026-04-29 00:18:39 +02:00
egutierrez 13b12e2471 feat(primitives_gallery): añadir --capture <dir> mode (offscreen render + glReadPixels)
Modo de captura que renderiza cada demo de la gallery en una ventana GLFW
invisible (GLFW_VISIBLE=GLFW_FALSE) y guarda PNG por demo via stb_image_write.

- capture.{h,cpp}: API gallery::run_capture(cfg, items) — warmup_frames,
  glReadPixels(GL_RGBA), flip vertical, stbi_write_png.
- main.cpp: parsea --capture <dir> antes de fn::run_app y delega a capture.cpp.
- vendor: stb_image_write.h v1.16 (mismo commit que stb_image.h).

Funciona en WSL con LIBGL_ALWAYS_SOFTWARE=1 (Mesa/llvmpipe). Si el entorno
no tiene contexto GL, el binario sale con rc!=0 sin generar PNGs.

Issue 0048.
2026-04-29 00:18:27 +02:00
egutierrez 015cf290eb refactor(shaders_lab): usar AppConfig.panels + layouts_cb (issue 0043) 2026-04-29 00:08:40 +02:00
egutierrez cbf8fd911f refactor(primitives_gallery): usar AppConfig.about + init_gl_loader (issue 0043) 2026-04-29 00:06:51 +02:00
egutierrez 503ccf30f4 refactor(chart_demo): usar AppConfig.about (issue 0043) 2026-04-29 00:06:20 +02:00
egutierrez 00d18d38b6 test(cpp): tests para sql_parse, process_state_machine, file_poll_diff 2026-04-28 23:58:40 +02:00
egutierrez 5044528175 refactor(shaders_lab): extraer compile_* a compiler.{h,cpp} 2026-04-28 23:56:33 +02:00
egutierrez b5058c56fe refactor(cpp/core): file_watcher usa file_poll_diff 2026-04-28 23:55:11 +02:00
egutierrez 13339abdb3 feat(cpp/core): añadir file_poll_diff pure 2026-04-28 23:53:49 +02:00
egutierrez ad254beeac refactor(cpp/core): process_runner usa process_state_machine 2026-04-28 23:53:08 +02:00
egutierrez 7779ce7b46 feat(cpp/core): añadir process_state_machine pure 2026-04-28 23:52:37 +02:00
egutierrez e70d0940a4 refactor(cpp/core): sql_workbench usa sql_parse 2026-04-28 23:51:59 +02:00
egutierrez dd3f73905f feat(cpp/core): añadir sql_parse pure 2026-04-28 23:51:23 +02:00
egutierrez 50c7452df3 merge: issue/0047-cpp-tests-foundation — implementación paralela 2026-04-28 23:44:55 +02:00
egutierrez f62392179f merge: issue/0044-cpp-orphans-audit — implementación paralela 2026-04-28 23:44:52 +02:00
egutierrez 41e66f60df merge: issue/0042-cpp-layout-storage-public — implementación paralela 2026-04-28 23:44:44 +02:00
egutierrez 78dc004371 merge: issue/0041-cpp-app-best-practices — implementación paralela 2026-04-28 23:44:24 +02:00
egutierrez 6b8f0dc10e chore(cpp): script run_tests.sh para build+ctest one-shot 2026-04-28 23:42:38 +02:00
egutierrez 3699a2554d docs(registry): tested:true + test_file_path en .md de primitivos
20 funciones C++ pasan de tested:false a tested:true con sus tests
correspondientes y test_file_path apuntando a cpp/tests/. Cubre 4 tests
reales (tween_curves, pie/kpi/bar math) y 16 placeholders (componentes
UI con tests visuales pendientes para 0048).

Coverage cpp pasa de 4% (3/81) a 28% (23/81).
2026-04-28 23:42:35 +02:00
egutierrez 715074c2e8 test(cpp): placeholders para top-19 primitivos UI (logica visual en 0048)
Cada placeholder garantiza que el .cpp compila y linka contra Catch2,
y reserva el slot para tests futuros una vez se extraiga logica pura
del componente. La validacion visual real vive en primitives_gallery
(issue 0048).

Cubre: tokens, button, select, text_input, badge, kpi_card, pie_chart,
bar_chart, tree_view, modal_dialog, toolbar, toast, empty_state,
page_header, dashboard_panel, dashboard_grid, sparkline, table_view,
icon_button.
2026-04-28 23:42:29 +02:00
egutierrez f858f3a9fc test(cpp): tests reales para tween_curves, pie/kpi/bar math
- test_tween_curves: boundary conditions (t=0, t=0.5, t=1), monotonicidad
  para curvas no oscilantes, dispatch via apply(), names() no nulos.
- test_pie_chart_math: replica slice_at (anonymous namespace en pie_chart.cpp)
  y testea hit-test angular, edge del radio, distribucion proporcional.
- test_kpi_card_math: classify_delta (Up/Down/Flat) y pct_change con
  zero/negativos. La logica visual la cubre primitives_gallery (issue 0048).
- test_bar_chart_math: compute_y_range (incluye 0, negativos, vacio,
  single value) y clamp_bar_width [0.05, 1.0].
2026-04-28 23:42:22 +02:00
egutierrez 557ec658c9 feat(cpp): integrar Catch2 en CMake con BUILD_TESTING + add_fn_test helper
cpp/tests/CMakeLists.txt compila Catch2 amalgamated como STATIC libreria
una sola vez. Cada test es su propio executable (CATCH_CONFIG_MAIN por
archivo) y se registra con add_test(). add_fn_test(name srcs...) es el
helper: incluye paths de cpp/functions y cpp/framework, linka catch2.

Tests que necesitan symbols reales (fn_framework, imgui) los anaden
explicitamente con target_link_libraries despues.
2026-04-28 23:42:14 +02:00
egutierrez 6123c87483 feat(cpp): vendor Catch2 v3.5.0 amalgamated
BSL-1.0. Single-header + single-source para tests con ctest.
2026-04-28 23:42:08 +02:00
egutierrez e4f86594f0 refactor(shaders_lab): migrar layouts inline a layout_storage publico
Sustituye ~30 lineas de cableado manual de save/load/list/delete contra
layout_storage_sqlite por dos llamadas a la nueva API publica:

    g_layouts = fn_ui::layout_storage_open("shaders_lab.db");
    fn_ui::layout_storage_make_callbacks(g_layouts, g_layout_cb);

El blob pendiente lo gestiona el storage (layout_storage_apply_pending).
on_reset se override para ademas re-mostrar los paneles de shaders_lab.
La tabla ui_layouts heredada queda intacta — la nueva API usa
imgui_layouts en la misma BD.
2026-04-28 23:41:03 +02:00
egutierrez 958189227d chore(registry): notes en huerfanas usadas por framework/apps
Auditoria del issue 0044: anota en notes: el contexto de consumo de
huerfanos que no pueden registrarse en uses_functions porque sus
consumidores no son funciones del registry:
- consumido por cpp/framework/app_base.cpp (framework no indexado)
- consumido por cpp/apps/{shaders_lab,chart_demo,text_editor_smoke}/main.cpp
- scaffolding/demo en primitives_gallery

31 huerfanas anotadas. Las que quedan en uses_functions=[] tras esto
son hojas legitimas (no llaman a nada) o realmente sin uso (lista
DEAD reportada en el issue 0044).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:40:51 +02:00
egutierrez 96fcd05511 chore(registry): añadir uses_functions a consumidores reales (viz)
Auditoria del issue 0044: 9 archivos .md de cpp/functions/viz/ con
uses_functions actualizado. Resuelve dependencias detectadas via
#include: plot_static (consumido por bar_chart, histogram, line_plot,
pie_chart, scatter_plot), gl_loader, gl_framebuffer, gl_shader,
graph_force_layout, graph_renderer, graph_spatial_hash, orbit_camera,
sparkline y tokens.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:40:37 +02:00
egutierrez 08cc179ca8 chore(registry): añadir uses_functions a consumidores reales (gfx)
Auditoria del issue 0044: 14 archivos .md de cpp/functions/gfx/ con
uses_functions actualizado. Resuelve dependencias detectadas via
#include: gl_loader (consumido por casi todo el dominio gfx),
dag_catalog (consumido por la familia dag_*), fullscreen_quad,
gl_framebuffer, gl_shader, mesh_obj_load, uniform_parser y
dag_node_previews.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:40:31 +02:00
egutierrez e356b7ac42 chore(registry): añadir uses_functions a consumidores reales (core)
Auditoria del issue 0044: 17 archivos .md de cpp/functions/core/ con
uses_functions actualizado para reflejar las llamadas reales detectadas
mediante #include en sus .cpp/.h. Los huerfanos referenciados (tokens,
app_about, app_settings, layouts_menu, panel_menu, table_view,
text_editor, tween_curves, app_settings) ahora aparecen en el grafo de
dependencias del registry.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:40:22 +02:00
egutierrez 914372a517 feat(cpp/core): añadir layout_storage publico (SQLite-backed LayoutCallbacks)
API publica con handle opaco LayoutStorage* que envuelve la persistencia
de layouts ImGui en SQLite. Cualquier app puede obtener un LayoutCallbacks
listo para app_menubar/layouts_menu_items con dos llamadas:

    auto* st = fn_ui::layout_storage_open("app.db");
    fn_ui::LayoutCallbacks cb;
    fn_ui::layout_storage_make_callbacks(st, cb);

Tabla SQLite imgui_layouts(name, ini, updated_at) creada con
CREATE TABLE IF NOT EXISTS para no chocar con tablas pre-existentes.
fn_framework ahora enlaza SQLite::SQLite3 para que cualquier app que use
el framework herede acceso a layout_storage sin trabajo extra.
2026-04-28 23:39:34 +02:00
egutierrez 3e0d3d612a fix(cpp/viz,core): bell icon TI_BELL, candlestick Setup-inside-BeginPlot, pie legend, kpi sparkline a la derecha
- toast.cpp: TI_BELL en lugar de \xf0\x9f\x94\x94 (fuera del rango cargado por icon_font, renderizaba como ?)
- candlestick.cpp: SetupAxes/SetupAxisScale/SetupAxisLimits movidos dentro de BeginPlot/EndPlot — antes el plot desaparecia al entrar
- pie_chart.cpp: SetupLegend(East, Outside, NoButtons), eliminado NoLegend
- kpi_card.cpp: layout 2 cols con sparkline a la derecha centrado verticalmente
2026-04-28 23:38:51 +02:00
egutierrez 10e0b712ca feat(cpp/framework): extender AppConfig con about, panels, layouts_cb, init_gl_loader 2026-04-28 23:37:23 +02:00
egutierrez c1b1d8fbad docs(cpp): añadir PATTERNS.md con checklist de apps 2026-04-28 23:34:07 +02:00
egutierrez 836ff02578 docs: ADR 0002 + CHANGELOG + reglas para dataforge/<name>+master
- docs/adr/0002-apps-analyses-as-dataforge-master.md: decision arquitectural
  con contexto, alternativas descartadas y cambios concretos del 2026-04-28.
- CHANGELOG.md: entrada 2026-04-28 con Added/Changed/Fixed.
- .claude/CLAUDE.md: nota sobre /full-git-push y dataforge/<name>+master.
- .claude/rules/apps_tbd.md: tronco unico master + init.defaultBranch.
- cpp/functions/core/app_menubar.md: notas del submenu Settings con About.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 22:41:55 +02:00