feat(0036f): view menu accion 'Open NodeGroups for selected'

Anyade un item al menu View del framework via el nuevo callback
AppConfig.view_extras. El item:
- Esta enabled solo si la seleccion del viewport (o, en su defecto,
  el inspector) apunta a un nodo con type_ref Table o Group.
- Click → resuelve sql_id via entity_index_lookup, deriva
  NodeGroupsKind del type_ref y llama
  views_node_groups_open(g_app, sql_id, kind, ops_db). La API
  marca focus_request=true (cubierto por 0036c), de modo que la
  window emerge al frente si ya existia.
- Disabled → tooltip 'Select a Table or Group node first' (mostrado
  con AllowWhenDisabled).

Sin atajo de teclado (descartado por el usuario).
Sin submenu de windows abiertas (fase 2).

Refs: issues/0036f-view-menu-open-nodegroups.md
This commit is contained in:
2026-05-04 01:12:58 +02:00
parent 3e71fcc4ca
commit f6f53b60c3
2 changed files with 116 additions and 0 deletions
+53
View File
@@ -2431,6 +2431,58 @@ int main(int argc, char** argv) {
}
}
// 0036f — accion en el menu View que abre la NodeGroups window del
// nodo seleccionado. Disabled si la seleccion no es Table ni Group.
auto view_extras_cb = []() -> bool {
// Resolver seleccion actual: priorizamos el nodo del viewport;
// si no hay nada seleccionado en el canvas pero el inspector
// tiene una entidad cargada, usamos esa.
int sel_idx = -1;
if (!g_viewport.selection.empty()) {
int s = g_viewport.selection.front();
if (s >= 0 && s < g_graph.node_count) sel_idx = s;
}
if (sel_idx < 0
&& g_app.insp_node_idx >= 0
&& g_app.insp_node_idx < g_graph.node_count) {
sel_idx = g_app.insp_node_idx;
}
bool is_table = false;
bool is_group = false;
const char* sql_id = nullptr;
if (sel_idx >= 0) {
uint16_t tid = g_graph.nodes[sel_idx].type_id;
const char* tn = (tid < (uint16_t)g_graph.type_count
&& g_graph.types[tid].name)
? g_graph.types[tid].name : "";
if (tn && std::strcmp(tn, "Table") == 0) is_table = true;
else if (tn && std::strcmp(tn, "Group") == 0) is_group = true;
sql_id = ge::entity_index_lookup(
g_idx, g_graph.nodes[sel_idx].user_data);
}
const bool enabled = (is_table || is_group) && sql_id != nullptr;
ImGui::Separator();
bool acted = false;
if (!enabled) ImGui::BeginDisabled();
if (ImGui::MenuItem(TI_FOLDER_OPEN " Open NodeGroups for selected")) {
if (enabled) {
ge::NodeGroupsKind kind = is_group
? ge::NodeGroupsKind::Group
: ge::NodeGroupsKind::Table;
ge::views_node_groups_open(g_app, sql_id, kind,
g_input_path.c_str());
acted = true;
}
}
if (!enabled) ImGui::EndDisabled();
if (!enabled && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
ImGui::SetTooltip("Select a Table or Group node first");
}
return acted;
};
int rc = fn::run_app(
{.title = "graph_explorer",
.width = 1600,
@@ -2439,6 +2491,7 @@ int main(int argc, char** argv) {
.panels = g_panels,
.panel_count = sizeof(g_panels) / sizeof(g_panels[0]),
.layouts_cb = g_layout_storage ? &g_layout_cb : nullptr,
.view_extras = view_extras_cb,
.init_gl_loader = true},
render);