feat(table-node): edge CONTAINS_ROW al promover + tabla cuadrada real
Tres ajustes derivados de feedback en uso: 1. tableview_promote_row recibe ahora `table_entity_id` y, si no es nulo, inserta una relacion 'CONTAINS_ROW' (id estable, INSERT OR IGNORE) entre la tabla origen y la entidad promovida. El viewport pinta la arista de pertenencia automaticamente sin codigo extra. 2. apply_types_yaml fija default_size = 32 px (world) para tipos Table junto al SHAPE_SQUARE ya existente. La GPU pinta el cuadrado real; antes era invisible bajo el overlay rectangular. 3. views_table_overlay adelgaza al rol que le toca: solo dibuja un contador discreto "<N> rows" debajo del cuadrado (texto pequeno con bg semitransparente). El cuadrado en si lo pinta el GPU. Defensiva: views_table_windows_sync marca page_dirty=true en TODAS las windows live tras cada sync para que el flag promoted se refresque inmediatamente despues de promote/demote/import.
This commit is contained in:
@@ -1801,17 +1801,21 @@ void views_table_windows_sync(AppState& app, const char* ops_db) {
|
||||
if (live.find(it->first) == live.end()) it = app.table_windows.erase(it);
|
||||
else ++it;
|
||||
}
|
||||
// Anadir las nuevas o refrescar metadata.
|
||||
// Anadir las nuevas o refrescar metadata. Tras cualquier sync forzamos
|
||||
// page_dirty = true para que la siguiente iteracion del render relea
|
||||
// la pagina contra DuckDB (se evita asi mostrar pages obsoletas tras
|
||||
// promote/demote/import — donde el flag promoted de cada fila puede
|
||||
// haber cambiado).
|
||||
for (auto& kv : live) {
|
||||
auto& w = app.table_windows[kv.first];
|
||||
bool was_present = !w.meta.entity_id.empty();
|
||||
w.meta = std::move(kv.second);
|
||||
w.open = true;
|
||||
w.page_dirty = true;
|
||||
if (!was_present) {
|
||||
w.offset = 0;
|
||||
w.page.clear();
|
||||
w.total_rows = 0;
|
||||
w.page_dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2019,6 +2023,9 @@ void views_table_overlay(AppState& app) {
|
||||
if (!dl) return;
|
||||
ImFont* font = ImGui::GetFont();
|
||||
|
||||
// El cuadrado lo pinta el GPU (apply_types_yaml fija shape=SQUARE +
|
||||
// size=32 para tipos Table). Aqui solo añadimos un contador discreto
|
||||
// BAJO el cuadrado: "1000 rows".
|
||||
for (int i = 0; i < g.node_count; ++i) {
|
||||
const GraphNode& n = g.nodes[i];
|
||||
if (!(n.flags & NF_VISIBLE)) continue;
|
||||
@@ -2026,44 +2033,38 @@ void views_table_overlay(AppState& app) {
|
||||
const EntityType& t = g.types[n.type_id];
|
||||
if (!t.name || std::strcmp(t.name, "Table") != 0) continue;
|
||||
|
||||
const float vx = (n.x - app.viewport->cam_x) * app.viewport->zoom + cx;
|
||||
const float vy = (n.y - app.viewport->cam_y) * app.viewport->zoom + cy;
|
||||
if (vx < wmin.x - 200 || vx > wmax.x + 200) continue;
|
||||
const float zoom = app.viewport->zoom;
|
||||
const float vx = (n.x - app.viewport->cam_x) * zoom + cx;
|
||||
const float vy = (n.y - app.viewport->cam_y) * zoom + cy;
|
||||
if (vx < wmin.x - 100 || vx > wmax.x + 100) continue;
|
||||
if (vy < wmin.y - 100 || vy > wmax.y + 100) continue;
|
||||
|
||||
int64_t count = -1;
|
||||
auto it = app.table_node_counts.find(n.user_data);
|
||||
if (it != app.table_node_counts.end()) count = it->second;
|
||||
if (count < 0) continue;
|
||||
|
||||
char buf[96];
|
||||
if (count >= 0) std::snprintf(buf, sizeof(buf), TI_TABLE " Table %lld", (long long)count);
|
||||
else std::snprintf(buf, sizeof(buf), TI_TABLE " Table");
|
||||
char buf[64];
|
||||
std::snprintf(buf, sizeof(buf), "%lld rows", (long long)count);
|
||||
|
||||
const float font_size = 13.0f;
|
||||
ImVec2 ts = font ? font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, buf)
|
||||
: ImVec2(60.0f, 14.0f);
|
||||
const float pad_x = 10.0f, pad_y = 6.0f;
|
||||
const float w = std::max(96.0f, ts.x + pad_x * 2.0f);
|
||||
const float h = ts.y + pad_y * 2.0f;
|
||||
ImVec2 a(vx - w * 0.5f, vy - h * 0.5f);
|
||||
ImVec2 b(vx + w * 0.5f, vy + h * 0.5f);
|
||||
const float font_size = 12.0f;
|
||||
if (!font) continue;
|
||||
ImVec2 ts = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, buf);
|
||||
|
||||
// Sombra ligera
|
||||
dl->AddRectFilled(ImVec2(a.x + 1, a.y + 2), ImVec2(b.x + 1, b.y + 2),
|
||||
IM_COL32(0, 0, 0, 80), 6.0f);
|
||||
// Cuerpo
|
||||
dl->AddRectFilled(a, b, IM_COL32(38, 56, 92, 240), 6.0f);
|
||||
// Borde
|
||||
uint32_t border = (n.flags & NF_SELECTED)
|
||||
? IM_COL32(180, 200, 255, 255)
|
||||
: IM_COL32(120, 160, 220, 220);
|
||||
dl->AddRect(a, b, border, 6.0f, 0, (n.flags & NF_SELECTED) ? 2.0f : 1.5f);
|
||||
// Posicion: bajo el cuadrado. La mitad del shape en pixeles depende
|
||||
// del default_size del tipo y del zoom.
|
||||
const float half_h = (t.default_size * zoom) * 0.5f;
|
||||
const float gap = 4.0f;
|
||||
const float tx = vx - ts.x * 0.5f;
|
||||
const float ty = vy + half_h + gap;
|
||||
|
||||
if (font) {
|
||||
dl->AddText(font, font_size,
|
||||
ImVec2(vx - ts.x * 0.5f, vy - ts.y * 0.5f),
|
||||
IM_COL32(230, 240, 255, 255), buf);
|
||||
}
|
||||
// Pequeño bg semitransparente para que el texto sea legible sobre
|
||||
// grafos densos, sin parecer un chip.
|
||||
dl->AddRectFilled(ImVec2(tx - 4, ty - 1),
|
||||
ImVec2(tx + ts.x + 4, ty + ts.y + 1),
|
||||
IM_COL32(20, 25, 35, 180), 3.0f);
|
||||
dl->AddText(font, font_size, ImVec2(tx, ty),
|
||||
IM_COL32(200, 220, 240, 230), buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user