docs(issues): marcar 0025 y 0026 como completados + WIP master
Wave 1 de parallel-fix-issues integrada a master: - 0025: text_editor_cpp_core + file_watcher_cpp_core - 0026: gl_texture_load_cpp_gfx (vendor: stb_image v2.30) Ademas se commitea WIP previo de master que estaba sin commitear (cambios en shaders_lab, dag_*, framework, tokens, kpi_card, gl_loader.md, etc.) para dejar HEAD buildable. Notas: - Algunos deps del gallery (button.cpp, toolbar.cpp, modal_dialog.cpp...) siguen UNTRACKED — gating con FN_BUILD_GALLERY=ON (default OFF) para que master build (sin flag) no los necesite. - Build OK con y sin flag. fn index registra 904 functions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
#include "kpi_card.h"
|
||||
#include "sparkline.h"
|
||||
#include "core/tokens.h"
|
||||
#include "core/icons_tabler.h"
|
||||
#include <imgui.h>
|
||||
#include <cstdio>
|
||||
|
||||
void kpi_card(const char* label, float value, float delta_percent,
|
||||
const float* history, int history_count,
|
||||
const char* format) {
|
||||
const char* format,
|
||||
const char* icon) {
|
||||
using namespace fn_tokens;
|
||||
|
||||
// Card container — surface bg, border, rounded, padding.
|
||||
@@ -28,42 +30,40 @@ void kpi_card(const char* label, float value, float delta_percent,
|
||||
|
||||
// Altura fija (no AutoResizeY) para que:
|
||||
// (a) todas las cards de un grid queden alineadas visualmente,
|
||||
// (b) no haya recalculo de layout por card en cada resize de la ventana.
|
||||
// 78px alcanza para: label (~14px) + value (~22px con escala x1.4) + trend
|
||||
// (~14px) + padding sm*2 (~16px) ≈ 66px, +12px de aire.
|
||||
constexpr float card_height = 78.0f;
|
||||
// (b) no haya recalculo de layout por card en cada resize.
|
||||
constexpr float card_height = 86.0f;
|
||||
ImGui::BeginChild(child_id, ImVec2(width, card_height),
|
||||
ImGuiChildFlags_Borders,
|
||||
ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
|
||||
// Label — muted
|
||||
// Top row: optional icon + label, ambos en text_muted.
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, colors::text_muted);
|
||||
if (icon && *icon) {
|
||||
ImGui::TextUnformatted(icon);
|
||||
ImGui::SameLine(0, spacing::xs);
|
||||
}
|
||||
ImGui::TextUnformatted(label);
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
// Value — escala compacta 1.4x, proporcional a una card de 78px.
|
||||
// El format controla el sufijo (ej: "%.0f%%" para porcentajes).
|
||||
// Value — escala compacta 1.4x, proporcional a una card de 86px.
|
||||
ImGui::SetWindowFontScale(1.4f);
|
||||
char value_buf[64];
|
||||
std::snprintf(value_buf, sizeof(value_buf), format, value);
|
||||
ImGui::TextUnformatted(value_buf);
|
||||
ImGui::SetWindowFontScale(1.0f);
|
||||
|
||||
// Delta / trend — SIEMPRE se reserva la linea aunque no haya tendencia,
|
||||
// para que todas las cards tengan la misma altura. Cuando no hay delta
|
||||
// ni history, se muestra un guion en text_dim para mantener el ritmo
|
||||
// visual sin hacer ruido con "+0.0%".
|
||||
// Delta / trend — SIEMPRE se reserva la linea aunque no haya tendencia.
|
||||
const bool has_delta = delta_percent != 0.0f;
|
||||
const bool has_history = history != nullptr && history_count > 0;
|
||||
|
||||
if (has_delta) {
|
||||
const bool positive = delta_percent >= 0.0f;
|
||||
const ImVec4 delta_color = positive ? colors::success : colors::error;
|
||||
char delta_buf[32];
|
||||
char delta_buf[48];
|
||||
if (positive) {
|
||||
std::snprintf(delta_buf, sizeof(delta_buf), "\xe2\x96\xb2 +%.1f%%", delta_percent);
|
||||
std::snprintf(delta_buf, sizeof(delta_buf), TI_TRENDING_UP " +%.1f%%", delta_percent);
|
||||
} else {
|
||||
std::snprintf(delta_buf, sizeof(delta_buf), "\xe2\x96\xbc %.1f%%", delta_percent);
|
||||
std::snprintf(delta_buf, sizeof(delta_buf), TI_TRENDING_DOWN " %.1f%%", delta_percent);
|
||||
}
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, delta_color);
|
||||
ImGui::TextUnformatted(delta_buf);
|
||||
@@ -73,12 +73,11 @@ void kpi_card(const char* label, float value, float delta_percent,
|
||||
sparkline(label, history, history_count, delta_color, 120.0f, 24.0f);
|
||||
}
|
||||
} else if (has_history) {
|
||||
// Sin delta pero con historia: sparkline en primary (neutro).
|
||||
sparkline(label, history, history_count, colors::primary, 120.0f, 24.0f);
|
||||
} else {
|
||||
// Placeholder para preservar altura de la card.
|
||||
// Placeholder para preservar altura.
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, colors::text_dim);
|
||||
ImGui::TextUnformatted("\xe2\x80\x94"); // em dash
|
||||
ImGui::TextUnformatted(TI_MINUS);
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user