From f4e4dd5a0b47de6c6a0d5e4d8adfa09e6090014f Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Mon, 4 May 2026 01:06:30 +0200 Subject: [PATCH] feat(0036e): row click en NodeGroups enfoca la entidad (kind-aware) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Reusa la infra de focus existente (AppState::want_focus_entity / focus_entity_id) ya cableada en main.cpp desde 0011. - kind=Group: single click sobre la fila pone want_focus_entity con row.id; tooltip "Click to focus entity in viewport" en hover. El doble click sigue funcionando (mismo efecto). El menu contextual y el boton Promote-out-of-group quedan intactos. - kind=Table promovida (row.promoted_entity_id no vacio): single click pone want_focus_entity con promoted_entity_id; tooltip de focus. - kind=Table no promovida: single click es no-op visual; tooltip "promote first to focus\n(double click or right click to promote)" como hint sutil. El doble click sigue lanzando el flujo de promote (legado de 0036c) y el menu contextual ofrece Promote. - Sin cambios en el handler de main.cpp — la logica de pan/zoom + select + load inspector ya existe y se reutiliza tal cual. - Sin tests Python nuevos: el comportamiento es UI ImGui (no testeable desde pytest). 102 passed WSL / 91+11 skipped Windows sin regresion. Refs: issues/0036e-row-click-focus-viewport.md --- issues/0036e-row-click-focus-viewport.md | 70 ++++++++++++++++++++++++ views.cpp | 35 ++++++++++-- 2 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 issues/0036e-row-click-focus-viewport.md diff --git a/issues/0036e-row-click-focus-viewport.md b/issues/0036e-row-click-focus-viewport.md new file mode 100644 index 0000000..4048ef7 --- /dev/null +++ b/issues/0036e-row-click-focus-viewport.md @@ -0,0 +1,70 @@ +--- +id: 0036e +title: Row click en NodeGroups enfoca la entidad en el viewport (kind-aware) +status: pending +priority: medium +created: 2026-05-04 +parent: 0036 +depends_on: [0036b] +--- + +## Objetivo + +Click sobre una fila en la NodeGroups window centra/selecciona la +entidad correspondiente en el viewport. Comportamiento ramificado por +kind: + +- **kind = Group**: la fila ES una entidad. Click -> pan/zoom de la + camara hacia su posicion + select. +- **kind = Table** (DuckDB): la fila NO es entidad necesariamente. + Resolucion **opcion (c)**: + - Si ya existe una entidad promovida para ese row_id: click = + focus. + - Si no: click = no-op visual + texto disabled abajo del row tipo + "promote first to focus" como hint sutil. Sin auto-promote. + +## Cambios + +### Estado para focus + +`AppState::want_focus_entity = true; AppState::focus_entity_id = id;` +Render loop consume el flag, recentra la camara al nodo, marca +`viewport.selected_node_idx = ...` y limpia el flag. + +(Probablemente ya existe esta infra desde issue 0011 promote+open +inspector — reusar `app.want_focus_entity` / `app.focus_entity_id`.) + +### Lookup de entidad para fila DuckDB + +Para kind=Table, dado un row_id, comprobar si existe entity con +`SELECT id FROM entities WHERE source = '' AND +metadata LIKE '%"row_id": ""%' LIMIT 1` (o el query exacto +usado en 0011 para detectar promovidas). + +Cache simple: por window, mantener un `unordered_set +promoted_row_ids` que se rellena en cada paginacion. Asi el render +sabe sin query extra que filas tienen entidad lista para focus. + +### Render + +Hacer la fila completa clickable (Selectable o boton invisible +sobre la fila). Hover indica accion clara. + +## Acceptance criteria + +- Click en row de Group: el viewport recentra al nodo y lo + selecciona. +- Click en row Table promovida: focus como kind=Group. +- Click en row Table no promovida: no-op + hint visible. +- Tests: + - `test_node_groups_row_click_sets_focus_entity_for_group` + - `test_node_groups_row_click_noop_for_unpromoted_table_row` + +## TBD + +Branch `issue/0036e-row-click-focus`, merge `--no-ff` a master. + +## Out of scope + +- Multi-select (fase 2). +- Hover preview (fase 2). diff --git a/views.cpp b/views.cpp index c05ecb7..bf42f4b 100644 --- a/views.cpp +++ b/views.cpp @@ -2089,14 +2089,18 @@ void views_node_groups_window(AppState& app) { ImGui::Selectable(row.id.c_str(), false, sf); if (is_group) { - // En kind=Group la fila YA es una entidad real del grafo. - // Doble click → focus inspector. Right click → focus. - // (El boton "Promote" no aplica — 0036d hace eso para - // contextos donde tenga sentido.) - if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) { + // 0036e: en kind=Group la fila YA es una entidad real del + // grafo. Single click → focus + select en viewport. + // Doble click tambien dispara focus (mismo efecto). + // Right click → menu contextual con focus. + if (ImGui::IsItemHovered() + && (ImGui::IsMouseClicked(0) || ImGui::IsMouseDoubleClicked(0))) { app.want_focus_entity = true; app.focus_entity_id = row.id; } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Click to focus entity in viewport"); + } if (ImGui::BeginPopupContextItem()) { if (ImGui::MenuItem(TI_FOCUS " Focus in Inspector")) { app.want_focus_entity = true; @@ -2122,8 +2126,20 @@ void views_node_groups_window(AppState& app) { ImGui::SetTooltip("Promote out of group (move to canvas)"); } } else { - // kind=Table — comportamiento original (DuckDB-backed). + // kind=Table (DuckDB-backed). + // 0036e: click ramificado por estado de promocion: + // - promovida → single click = focus en viewport. + // - no promovida → single click = no-op + hint tooltip. + // El doble click sobre fila no promovida sigue lanzando + // el flujo de promote (legado de 0036c) por convenience. bool is_promoted = !row.promoted_entity_id.empty(); + if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0)) { + if (is_promoted) { + app.want_focus_entity = true; + app.focus_entity_id = row.promoted_entity_id; + } + // else: no-op (hint mostrado via tooltip abajo). + } if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) { if (is_promoted) { app.want_focus_entity = true; @@ -2134,6 +2150,13 @@ void views_node_groups_window(AppState& app) { app.promote_row_id = row.id; } } + if (ImGui::IsItemHovered()) { + if (is_promoted) { + ImGui::SetTooltip("Click to focus entity in viewport"); + } else { + ImGui::SetTooltip("promote first to focus\n(double click or right click to promote)"); + } + } if (ImGui::BeginPopupContextItem()) { if (is_promoted) { if (ImGui::MenuItem(TI_FOCUS " Focus in Inspector")) {