docs(flows): DoD obligatorio con user-facing surface + abrir issues 0100-0103 (taxonomia, frontmatter migration, dev_console, work dashboard)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
#include "core/app_about.h"
|
||||
|
||||
#include "app_base.h"
|
||||
#include "app_modules.h"
|
||||
#include "imgui.h"
|
||||
|
||||
#include <string>
|
||||
@@ -58,6 +60,40 @@ void about_window_render() {
|
||||
ImGui::TextWrapped("%s", g_description.c_str());
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
// --- Framework version (issue 0097) ---
|
||||
ImGui::Text("Framework");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextDisabled("v%s", fn::framework_version());
|
||||
|
||||
// --- Modules consumidos por la app (issue 0097) ---
|
||||
if (fn::app_modules_count > 0) {
|
||||
ImGui::Spacing();
|
||||
ImGui::Text("Modules (%lu)", fn::app_modules_count);
|
||||
if (ImGui::BeginTable("##fn_modules_table", 2,
|
||||
ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersInnerH |
|
||||
ImGuiTableFlags_SizingStretchProp)) {
|
||||
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 140.0f);
|
||||
ImGui::TableSetupColumn("Version", ImGuiTableColumnFlags_WidthFixed, 80.0f);
|
||||
for (unsigned long i = 0; i < fn::app_modules_count; ++i) {
|
||||
const auto& m = fn::app_modules_array[i];
|
||||
if (!m.name) continue;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableSetColumnIndex(0);
|
||||
ImGui::TextUnformatted(m.name);
|
||||
if (m.description && *m.description && ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("%s", m.description);
|
||||
}
|
||||
ImGui::TableSetColumnIndex(1);
|
||||
ImGui::TextDisabled("v%s", m.version ? m.version : "?");
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::TextDisabled("fn_registry");
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Promovido al registry desde cpp/apps/primitives_gallery/playground/tables/.
|
||||
// Ver issue 0081 + docs/TQL.md. Pure value types + enums.
|
||||
// Issue 0081-N: CellRenderer / ColumnSpec / BadgeRule / IconMapEntry (v1.1.0).
|
||||
// v1.4.0: ChipRule / ColorStop / CategoricalChip / ColorScale renderers.
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
@@ -131,16 +132,19 @@ enum class JoinStrategy { Left, Inner, Right, Full };
|
||||
// CellRenderer: declarative rendering mode per column (issue 0081-N, v1.1.0).
|
||||
// Phase 2 (issue 0081-O, v1.2.0): Button=5 added.
|
||||
// Phase 2.5 (issue 0081-O.5, v1.3.0): Dots=8 added (inline status timeline).
|
||||
// v1.4.0: CategoricalChip=9, ColorScale=10.
|
||||
// ----------------------------------------------------------------------------
|
||||
enum class CellRenderer : uint8_t {
|
||||
Text = 0, // default — current behavior
|
||||
Badge = 1, // colored badge per-value
|
||||
Progress = 2, // progress bar (0..1 or 0..100)
|
||||
Duration = 3, // milliseconds with color gradient
|
||||
Icon = 4, // icon lookup by value string
|
||||
Button = 5, // clickable button; emits TableEvent::ButtonClick
|
||||
Text = 0, // default — current behavior
|
||||
Badge = 1, // colored badge per-value
|
||||
Progress = 2, // progress bar (0..1 or 0..100)
|
||||
Duration = 3, // milliseconds with color gradient
|
||||
Icon = 4, // icon lookup by value string
|
||||
Button = 5, // clickable button; emits TableEvent::ButtonClick
|
||||
// 6, 7: reserved for Phase 3 (TextInput, Custom).
|
||||
Dots = 8, // inline dots sparkline; cell = separator-delimited tokens
|
||||
Dots = 8, // inline dots sparkline; cell = separator-delimited tokens
|
||||
CategoricalChip = 9, // filled circle (8px) to left of text; color by value match
|
||||
ColorScale = 10, // continuous N-color gradient tint on cell background
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -178,6 +182,19 @@ struct IconMapEntry {
|
||||
std::string color_hex; // optional; "" -> default text color
|
||||
};
|
||||
|
||||
// ChipRule: maps a cell value to a dot color for CategoricalChip renderer (v1.4.0).
|
||||
// If no rule matches, no dot is drawn (fallback: plain text only).
|
||||
struct ChipRule {
|
||||
std::string match; // exact match (case-sensitive) against cell value
|
||||
std::string color; // "#rrggbb" hex color for the filled circle
|
||||
};
|
||||
|
||||
// ColorStop: one stop in an N-color gradient for ColorScale renderer (v1.4.0).
|
||||
struct ColorStop {
|
||||
float position; // 0.0 (leftmost/min) to 1.0 (rightmost/max)
|
||||
std::string color; // "#rrggbb" hex color at this stop
|
||||
};
|
||||
|
||||
// ColumnSpec: rendering spec for one column. Indexed by column position.
|
||||
struct ColumnSpec {
|
||||
std::string id; // stable id, used in TQL
|
||||
@@ -215,6 +232,20 @@ struct ColumnSpec {
|
||||
float dots_glyph_size = 0.0f; // glyph size px; 0 = default font size
|
||||
int dots_max = 0; // hard limit on dots shown; 0 = no limit
|
||||
bool dots_show_count = false; // if true, appends " (N)" after dots
|
||||
|
||||
// CategoricalChip (v1.4.0): CellRenderer::CategoricalChip.
|
||||
// Draws a filled circle (radius ~4px) to the left of the cell text.
|
||||
// Color is determined by matching cell value against `chips` rules.
|
||||
// Always visible (not hover-only). If no rule matches, no dot is drawn.
|
||||
std::vector<ChipRule> chips; // value → color rules
|
||||
|
||||
// ColorScale (v1.4.0): CellRenderer::ColorScale.
|
||||
// Maps numeric cell value to a background tint via N-color gradient LERP.
|
||||
// Low alpha so text remains legible.
|
||||
double range_min = 0.0; // value at t=0.0
|
||||
double range_max = 1.0; // value at t=1.0
|
||||
float range_alpha = 0.25f; // [0..1]; background tint opacity
|
||||
std::vector<ColorStop> range_stops; // N≥2 stops; empty → default green→amber→red
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -292,6 +323,14 @@ struct State {
|
||||
// Caller-provided column_specs take precedence over aux_column_specs.
|
||||
std::vector<std::vector<ColumnSpec>> aux_column_specs;
|
||||
|
||||
// Per-table "Show UI" toggle. Moved from global UiCache to per-State so each
|
||||
// table's chrome (chips bar) can be toggled independently (issue: multiple
|
||||
// tables on screen, "Show UI" used to flip all at once).
|
||||
// Defaults: user_set=true + visible=false => chrome closed by default, ignoring
|
||||
// the API arg show_chrome from frame 1 (preserves legacy behavior).
|
||||
bool chrome_user_set = true;
|
||||
bool chrome_user_visible = false;
|
||||
|
||||
// Helpers (definidos en compute_stage.cpp).
|
||||
Stage& raw();
|
||||
const Stage& raw() const;
|
||||
|
||||
@@ -540,12 +540,14 @@ ApplyResult apply(const std::string& lua_text,
|
||||
lua_getfield(L, -1, "renderer");
|
||||
if (lua_isstring(L, -1)) {
|
||||
std::string rn = lua_tostring(L, -1);
|
||||
if (rn == "badge") cs.renderer = data_table::CellRenderer::Badge;
|
||||
else if (rn == "progress") cs.renderer = data_table::CellRenderer::Progress;
|
||||
else if (rn == "duration") cs.renderer = data_table::CellRenderer::Duration;
|
||||
else if (rn == "icon") cs.renderer = data_table::CellRenderer::Icon;
|
||||
else if (rn == "button") cs.renderer = data_table::CellRenderer::Button;
|
||||
else if (rn == "dots") cs.renderer = data_table::CellRenderer::Dots;
|
||||
if (rn == "badge") cs.renderer = data_table::CellRenderer::Badge;
|
||||
else if (rn == "progress") cs.renderer = data_table::CellRenderer::Progress;
|
||||
else if (rn == "duration") cs.renderer = data_table::CellRenderer::Duration;
|
||||
else if (rn == "icon") cs.renderer = data_table::CellRenderer::Icon;
|
||||
else if (rn == "button") cs.renderer = data_table::CellRenderer::Button;
|
||||
else if (rn == "dots") cs.renderer = data_table::CellRenderer::Dots;
|
||||
else if (rn == "categorical_chip") cs.renderer = data_table::CellRenderer::CategoricalChip;
|
||||
else if (rn == "color_scale") cs.renderer = data_table::CellRenderer::ColorScale;
|
||||
else cs.renderer = data_table::CellRenderer::Text;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
@@ -642,6 +644,57 @@ ApplyResult apply(const std::string& lua_text,
|
||||
if (lua_isnumber(L, -1)) cs.dots_glyph_size = (float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
// CategoricalChip (v1.4.0)
|
||||
lua_getfield(L, -1, "chips");
|
||||
if (lua_istable(L, -1)) {
|
||||
int nc = (int)lua_rawlen(L, -1);
|
||||
for (int j = 1; j <= nc; ++j) {
|
||||
lua_rawgeti(L, -1, j);
|
||||
if (lua_istable(L, -1)) {
|
||||
data_table::ChipRule cr;
|
||||
lua_getfield(L, -1, "match");
|
||||
if (lua_isstring(L, -1)) cr.match = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, -1, "color");
|
||||
if (lua_isstring(L, -1)) cr.color = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
cs.chips.push_back(std::move(cr));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1); // chips
|
||||
|
||||
// ColorScale (v1.4.0)
|
||||
lua_getfield(L, -1, "range_min");
|
||||
if (lua_isnumber(L, -1)) cs.range_min = (double)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, -1, "range_max");
|
||||
if (lua_isnumber(L, -1)) cs.range_max = (double)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, -1, "range_alpha");
|
||||
if (lua_isnumber(L, -1)) cs.range_alpha = (float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, -1, "range_stops");
|
||||
if (lua_istable(L, -1)) {
|
||||
int ns = (int)lua_rawlen(L, -1);
|
||||
for (int j = 1; j <= ns; ++j) {
|
||||
lua_rawgeti(L, -1, j);
|
||||
if (lua_istable(L, -1)) {
|
||||
data_table::ColorStop stop;
|
||||
lua_getfield(L, -1, "position");
|
||||
if (lua_isnumber(L, -1)) stop.position = (float)lua_tonumber(L, -1);
|
||||
lua_pop(L, 1);
|
||||
lua_getfield(L, -1, "color");
|
||||
if (lua_isstring(L, -1)) stop.color = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
cs.range_stops.push_back(std::move(stop));
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(L, 1); // range_stops
|
||||
|
||||
// Tooltip
|
||||
lua_getfield(L, -1, "tooltip");
|
||||
if (lua_isstring(L, -1)) cs.tooltip = lua_tostring(L, -1);
|
||||
|
||||
@@ -283,8 +283,7 @@ std::string emit(const State& state,
|
||||
// Emit the block only if at least one spec has a non-default renderer OR tooltip.
|
||||
bool any_renderable = false;
|
||||
for (const auto& cs : specs) {
|
||||
if (cs.renderer != data_table::CellRenderer::Text || cs.tooltip_on_hover ||
|
||||
cs.renderer == data_table::CellRenderer::Dots) {
|
||||
if (cs.renderer != data_table::CellRenderer::Text || cs.tooltip_on_hover) {
|
||||
any_renderable = true; break;
|
||||
}
|
||||
}
|
||||
@@ -297,12 +296,14 @@ std::string emit(const State& state,
|
||||
// renderer
|
||||
const char* rname = "text";
|
||||
switch (cs.renderer) {
|
||||
case data_table::CellRenderer::Badge: rname = "badge"; break;
|
||||
case data_table::CellRenderer::Progress: rname = "progress"; break;
|
||||
case data_table::CellRenderer::Duration: rname = "duration"; break;
|
||||
case data_table::CellRenderer::Icon: rname = "icon"; break;
|
||||
case data_table::CellRenderer::Button: rname = "button"; break;
|
||||
case data_table::CellRenderer::Dots: rname = "dots"; break;
|
||||
case data_table::CellRenderer::Badge: rname = "badge"; break;
|
||||
case data_table::CellRenderer::Progress: rname = "progress"; break;
|
||||
case data_table::CellRenderer::Duration: rname = "duration"; break;
|
||||
case data_table::CellRenderer::Icon: rname = "icon"; break;
|
||||
case data_table::CellRenderer::Button: rname = "button"; break;
|
||||
case data_table::CellRenderer::Dots: rname = "dots"; break;
|
||||
case data_table::CellRenderer::CategoricalChip: rname = "categorical_chip"; break;
|
||||
case data_table::CellRenderer::ColorScale: rname = "color_scale"; break;
|
||||
default: break;
|
||||
}
|
||||
out += ", renderer = " + lua_string_literal(rname);
|
||||
@@ -370,6 +371,41 @@ std::string emit(const State& state,
|
||||
out += std::string(", dots_glyph_size = ") + buf;
|
||||
}
|
||||
}
|
||||
// CategoricalChip (v1.4.0)
|
||||
if (cs.renderer == data_table::CellRenderer::CategoricalChip) {
|
||||
if (!cs.chips.empty()) {
|
||||
out += ", chips = {\n";
|
||||
for (const auto& cr : cs.chips) {
|
||||
out += " { match = " + lua_string_literal(cr.match);
|
||||
out += ", color = " + lua_string_literal(cr.color);
|
||||
out += " },\n";
|
||||
}
|
||||
out += " }";
|
||||
}
|
||||
}
|
||||
// ColorScale (v1.4.0)
|
||||
if (cs.renderer == data_table::CellRenderer::ColorScale) {
|
||||
char buf[64];
|
||||
std::snprintf(buf, sizeof(buf), "%g", cs.range_min);
|
||||
out += std::string(", range_min = ") + buf;
|
||||
std::snprintf(buf, sizeof(buf), "%g", cs.range_max);
|
||||
out += std::string(", range_max = ") + buf;
|
||||
if (cs.range_alpha != 0.25f) {
|
||||
std::snprintf(buf, sizeof(buf), "%g", (double)cs.range_alpha);
|
||||
out += std::string(", range_alpha = ") + buf;
|
||||
}
|
||||
if (!cs.range_stops.empty()) {
|
||||
out += ", range_stops = {\n";
|
||||
for (const auto& stop : cs.range_stops) {
|
||||
std::snprintf(buf, sizeof(buf), "%g", (double)stop.position);
|
||||
out += " { position = ";
|
||||
out += buf;
|
||||
out += ", color = " + lua_string_literal(stop.color);
|
||||
out += " },\n";
|
||||
}
|
||||
out += " }";
|
||||
}
|
||||
}
|
||||
// Tooltip
|
||||
if (cs.tooltip_on_hover) {
|
||||
out += ", tooltip = " + lua_string_literal(cs.tooltip.empty() ? "auto" : cs.tooltip);
|
||||
|
||||
Reference in New Issue
Block a user