fix: docking gaps + hover radius + node spread + markdown notes

Bug fixes
- ImGui ID conflict en menu Change type: dedup tipos del grafo +
  defaults; PushID/PopID por entrada.
- Dockspace ya no tapa la toolbar: se posiciona 44 px por debajo, asi
  las ventanas dockeadas al borde superior quedan bajo la barra de
  filtros, no detras.
- Hover radius proporcional al tamaño visual del nodo: query espacial
  amplio (24/zoom) + filtro fino por (radio_visual + 2 px) / zoom. El
  tooltip solo se dispara si el raton esta efectivamente sobre el nodo.

Layout
- Default layout = grid (en vez de force) para que los grafos cargados
  se distribuyan ordenadamente al abrir.
- Boton "Reset layout" en la toolbar: limpia NF_PINNED en todos los
  nodos, resetea velocidades y reaplica el layout activo.
- Nodos recien creados (add_node, duplicate) caen en un anillo poisson
  alrededor del centro de la vista, no en el origen. Posicion
  determinista por user_data para que el mismo nodo no salte entre
  reloads.

Notes (markdown)
- Panel "Note" (dockeable) abierto con doble click sobre un nodo.
- entity_get_notes / entity_set_notes en entity_ops sobre la columna
  `notes` de operations.db (ya existente en el schema).
- Ctrl+S guarda. Cabecera muestra entity, type, id.
This commit is contained in:
2026-04-30 23:11:48 +02:00
parent 02eef6e339
commit adde3026ea
5 changed files with 273 additions and 27 deletions
+21 -2
View File
@@ -1,6 +1,7 @@
#pragma once
#include <string>
#include <vector>
struct GraphData;
struct GraphViewportState;
@@ -14,9 +15,11 @@ struct AppState {
GraphData* graph = nullptr;
GraphViewportState* viewport = nullptr;
// Layout activo
int layout_mode = 0; // 0=force, 1=grid, 2=circular, 3=radial, 4=hierarchical, 5=fixed
// Layout activo — default grid (1) para que los grafos cargados de
// operations.db se distribuyan ordenadamente al abrir.
int layout_mode = 1; // 0=force, 1=grid, 2=circular, 3=radial, 4=hierarchical, 5=fixed
int apply_layout_tick = 0; // se incrementa cuando hay que reaplicar layout
bool want_unpin_all = false; // Reset layout: limpia NF_PINNED y reaplica
// Force layout — config + GPU toggle
float repulsion = 1500.0f;
@@ -38,6 +41,7 @@ struct AppState {
bool panel_inspector = true;
bool panel_stats = true;
bool panel_viewport = true;
bool panel_note = false;
bool show_filters_modal = false;
bool show_open_modal = false;
@@ -68,6 +72,17 @@ struct AppState {
// Context menu state — popup global identificado por nombre.
bool ctx_open_request = false; // se setea en on_context_menu
// Note editor (panel "Note" abierto con doble click sobre nodo).
int note_node = -1; // node_idx siendo editado
std::string note_entity_id; // sql id resuelto
std::string note_entity_label; // display
std::string note_entity_type;
std::vector<char> note_buf; // editable, NUL-terminated
bool note_dirty = false;
bool want_save_note = false;
bool want_open_note = false; // doble click → cargar y abrir
int open_note_target = -1; // node_idx a abrir
};
// Toolbar superior (Open file, Layout selector, Filters..., Fit, Save layout).
@@ -82,6 +97,10 @@ void views_inspector(AppState& app);
// Stats line — counts + fps + energy + selection.
void views_stats(AppState& app);
// Note editor — abre con doble click sobre un nodo. Edita la columna `notes`
// (markdown) de la entidad y guarda con un boton.
void views_note(AppState& app);
// Modal Filters — toggles por tipo agrupados en columnas. Devuelve true si
// el usuario togglo algo.
bool views_filters_modal(AppState& app);