feat(cosmobiologia): rectificador automático — UI de entrada y disparo

Segundo incremento: el rectificador ya es usable de punta a punta
desde el panel, sin infraestructura de UI nueva.

- cosmobiologia-panel: Control::TextInput pasa a renderizarse desde
  string_state — deja de ser un display estático y se vuelve un campo
  de sólo-lectura que el shell escribe vía set_string (resultados,
  etiquetas).
- cosmobiologia-modules: el módulo primary_directions gana 3 sliders
  «Evento N · edad» (0 = ranura sin usar), un Action «Rectificar
  hora» y un TextInput «Resultado».
- shell: run_rectificacion lee las edades de los sliders, llama a
  engine::rectificar (ventana ±15 min, paso 1) y escribe la hora
  rectificada + el puntaje en el campo Resultado del panel.

El rectificador queda funcional: activar GR → fijar edades de eventos
→ «Rectificar hora» → leer el resultado. Falta sólo la curva del
perfil del barrido como visualización (incremento opcional).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-22 15:53:18 +00:00
parent 0ada1050f7
commit a7e9662fad
3 changed files with 111 additions and 17 deletions
@@ -173,6 +173,14 @@ impl ControlPanel {
.entry((m.id().to_string(), key))
.or_insert(Some(default));
}
// `TextInput` es un campo de sólo-display que el
// shell escribe (resultados, etiquetas) vía
// `set_string`; su estado vive en `string_state`.
Control::TextInput { key, default, .. } => {
self.string_state
.entry((m.id().to_string(), key))
.or_insert(Some(default));
}
_ => {}
}
}
@@ -550,7 +558,16 @@ impl ControlPanel {
options,
default,
} => self.render_select(theme, module_id, key, label, options, default, cx),
Control::TextInput { label, default, .. } => display_row(theme, label, default),
Control::TextInput { key, label, default } => {
// Sólo-display: muestra lo último que el shell escribió
// con `set_string`, o el `default` si nada se escribió.
let valor = self
.string_state
.get(&(module_id.to_string(), key.to_string()))
.and_then(|o| o.clone())
.unwrap_or_else(|| default.clone());
display_row(theme, label, &valor)
}
Control::Action { key, label } => {
self.render_action(theme, module_id, key, label, cx)
}