From d6bdab89e88a262f3900c203095122ea307cf918 Mon Sep 17 00:00:00 2001 From: Egutierrez Date: Fri, 24 Apr 2026 21:31:26 +0200 Subject: [PATCH] feat(views): chart panels con tamano fijo, altura de row constante, gitignore imgui.ini - Nuevo chart_panel_begin/end local (reemplaza dashboard_panel con AutoResizeY): BeginChild con altura explicita pasada por parametro, NoScrollbar | NoScrollWithMouse. Rompe el feedback loop plot <-> panel que causaba deslizamiento lateral y scrollbar fugaz. - Altura de charts fija 260px (antes GetContentRegionAvail().y * 0.35). Sin esto, redimensionar la ventana propaga cambios de altura a todos los plots y se ve vibracion. - KPIs reorganizados en ImGui::BeginTable 4 cols x 2 rows. Las celdas de tabla propagan ancho constrained, necesario para que el BeginChild interno del kpi_card (card v1.2 compacta 78px) ocupe exactamente la celda. - imgui.ini al .gitignore: estado local de la ventana, no versionable. Co-Authored-By: Claude Opus 4.7 (1M context) --- .gitignore | 1 + views.cpp | 126 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 89 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index c794538..f7b2944 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ operations.db operations.db-wal operations.db-shm *.exe +imgui.ini diff --git a/views.cpp b/views.cpp index 638fe11..4fc2ec7 100644 --- a/views.cpp +++ b/views.cpp @@ -59,42 +59,93 @@ void draw_kpi_row(const RegistryStats& stats) { } } +// Chart panel con tamano FIJO (no AutoResizeY) para evitar el feedback loop +// con ImPlot que provocaba deslizamiento lateral de las barras y scrollbar +// intermitente. Usa los mismos tokens que dashboard_panel para consistencia +// visual, pero con tamano determinista. +static bool chart_panel_begin(const char* title, const ImVec2& size) { + using namespace fn_tokens; + ImGui::PushStyleColor(ImGuiCol_ChildBg, colors::surface); + ImGui::PushStyleColor(ImGuiCol_Border, colors::border); + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, radius::md); + ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 1.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(spacing::md, spacing::md)); + + ImGui::BeginChild(title, size, ImGuiChildFlags_Borders, + ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + + ImGui::PushStyleColor(ImGuiCol_Text, colors::text_muted); + ImGui::TextUnformatted(title); + ImGui::PopStyleColor(); + ImGui::Separator(); + return true; +} + +static void chart_panel_end() { + ImGui::EndChild(); + ImGui::PopStyleVar(3); + ImGui::PopStyleColor(2); +} + void draw_charts(RegistryData& data, float height) { - dashboard_grid_begin(4, 8.0f); + // ImGui::BeginTable para reparto equitativo de ancho en 4 columnas y que + // cada chart_panel tenga ancho constrained via GetContentRegionAvail. + const ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame + | ImGuiTableFlags_NoPadOuterX; - if (dashboard_panel_begin("By Language", 0, height)) { - auto labels = to_cstr(data.lang_labels); - if (!labels.empty()) - bar_chart("##lang", labels.data(), data.lang_values.data(), static_cast(labels.size())); + // Altura util dentro del panel (height total - title row - separator - padding). + // El plot recibe exactamente esto, asi que no hay redimensionado recursivo. + const float plot_h = height - 48.0f; + + if (ImGui::BeginTable("##chart_grid", 4, flags)) { + ImGui::TableNextRow(); + + ImGui::TableSetColumnIndex(0); + { + ImVec2 sz(ImGui::GetContentRegionAvail().x, height); + chart_panel_begin("By Language", sz); + auto labels = to_cstr(data.lang_labels); + if (!labels.empty()) + bar_chart("##lang", labels.data(), data.lang_values.data(), + static_cast(labels.size()), 0.67f, plot_h); + chart_panel_end(); + } + + ImGui::TableSetColumnIndex(1); + { + ImVec2 sz(ImGui::GetContentRegionAvail().x, height); + chart_panel_begin("By Domain", sz); + auto labels = to_cstr(data.domain_labels); + if (!labels.empty()) + bar_chart("##domain", labels.data(), data.domain_values.data(), + static_cast(labels.size()), 0.67f, plot_h); + chart_panel_end(); + } + + ImGui::TableSetColumnIndex(2); + { + ImVec2 sz(ImGui::GetContentRegionAvail().x, height); + chart_panel_begin("Purity", sz); + const char* labels[] = {"Pure", "Impure"}; + float values[] = {static_cast(data.stats.pure_functions), + static_cast(data.stats.impure_functions)}; + pie_chart("##purity", labels, values, 2); + chart_panel_end(); + } + + ImGui::TableSetColumnIndex(3); + { + ImVec2 sz(ImGui::GetContentRegionAvail().x, height); + chart_panel_begin("Kind", sz); + auto labels = to_cstr(data.kind_labels); + if (!labels.empty()) + pie_chart("##kind", labels.data(), data.kind_values.data(), + static_cast(labels.size())); + chart_panel_end(); + } + + ImGui::EndTable(); } - dashboard_panel_end(); - dashboard_grid_next(); - - if (dashboard_panel_begin("By Domain", 0, height)) { - auto labels = to_cstr(data.domain_labels); - if (!labels.empty()) - bar_chart("##domain", labels.data(), data.domain_values.data(), static_cast(labels.size())); - } - dashboard_panel_end(); - dashboard_grid_next(); - - if (dashboard_panel_begin("Purity", 0, height)) { - const char* labels[] = {"Pure", "Impure"}; - float values[] = {static_cast(data.stats.pure_functions), - static_cast(data.stats.impure_functions)}; - pie_chart("##purity", labels, values, 2); - } - dashboard_panel_end(); - dashboard_grid_next(); - - if (dashboard_panel_begin("Kind", 0, height)) { - auto labels = to_cstr(data.kind_labels); - if (!labels.empty()) - pie_chart("##kind", labels.data(), data.kind_values.data(), static_cast(labels.size())); - } - dashboard_panel_end(); - - dashboard_grid_end(); } void draw_recent_functions(const std::vector& funcs) { @@ -211,11 +262,10 @@ void draw_dashboard(RegistryData& data) { draw_kpi_row(data.stats); ImGui::Dummy(ImVec2(0, fn_tokens::spacing::md)); - // Charts — 35% de la altura restante - float remaining = ImGui::GetContentRegionAvail().y; - float chart_h = remaining * 0.35f; - if (chart_h < 150.0f) chart_h = 150.0f; - + // Charts — altura FIJA en pixeles (no depende del resize de la ventana). + // Antes usabamos remaining*0.35, pero eso recalculaba todo el layout al + // redimensionar, provocando vibracion visible en los plots. + constexpr float chart_h = 260.0f; draw_charts(data, chart_h); ImGui::Dummy(ImVec2(0, fn_tokens::spacing::md));