feat(tahuantinsuyu): fase 14 — Return abstracto + Control::Select interactivo
El módulo SolarReturn se generaliza a PlanetaryReturn parametrizable
por cuerpo (Sun/Moon/Mercury/Venus/Mars/Jupiter/Saturn/Uranus/Neptune/
Pluto). Validado contra `Control::Select`, ahora interactivo como
tercer tipo de control draggable (después de Toggle/Slider/ChartPicker).
Refactor estructural: el dropdown del ChartPicker pasa a ser
infraestructura compartida — chart_picker_value/chart_picker_open
desaparecen, reemplazados por string_state/dropdown_open que sirven
a CUALQUIER control basado en string (picker + select).
render_chart_picker y render_select ahora son thin wrappers sobre
render_dropdown(options, include_auto).
- engine:
- PipelineRequest::SolarReturn → PipelineRequest::PlanetaryReturn
{ body: String, target_age_years }. Body como string agnóstico
(sun/moon/jupiter/...) que el bridge mapea a eternal_sky::Body
vía map_body — el mismo helper que ya usa StoredChartConfig.
- build_solar_return_overlay → build_planetary_return_overlay con
parameter `body: Body`. next_return acepta cualquier body, así que
Moon return (mensual) y Saturn return (29 años) funcionan igual.
Mensajes de error incluyen body.name() para diagnóstico.
- modules:
- SolarReturnModule → PlanetaryReturnModule (mod planetary_return).
id "planetary_return". Controles: toggle "enabled" + Select "body"
con 10 opciones de cuerpo (Sol → Plutón) + Slider edad. label
"Retornos planetarios".
- panel:
- Refactor: chart_picker_value/chart_picker_open → string_state/
dropdown_open (compartido entre ChartPicker y Select).
- set_string(module_id, key, value, cx) — API unificada. set_chart_picker
queda como alias retrocompatible.
- render_dropdown(options, include_auto, …) — helper común. picker
pasa include_auto=true (muestra "(automático)" + separador);
select pasa include_auto=false (las options son la única opción).
- render_select implementado — el botón muestra la option's label
(no value); click abre dropdown; click en opción emite ControlChanged
con Value::String(option.value).
- shell:
- OUTER_RING_MODULES const: "solar_return" → "planetary_return".
- build_requests para planetary_return: lee body string del
module_configs (default "sun"), arma PipelineRequest::PlanetaryReturn.
- apply_selection inicializa target_age + body=sun default para
planetary_return.
- sync_panel_from_configs strings → set_string (era set_chart_picker).
Probarlo: en el panel del módulo "Retornos planetarios", click en el
dropdown "Cuerpo" abre el popup; click en "Saturno" + slider en 29
años + toggle "Activar" = ves la carta del primer retorno de Saturno
(cuando recién terminaba la primera vuelta) en el outer ring con
cross aspects al natal.
NOTE: La persistencia con id "solar_return" de fase 13 queda huérfana
en la DB de los users que ya hayan probado. No es destructivo —
simplemente esas rows quedan sin módulo que las lea. Pre-1.0.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -136,7 +136,7 @@ impl Registry {
|
||||
r.register(Box::new(progression::ProgressionModule));
|
||||
r.register(Box::new(solar_arc::SolarArcModule));
|
||||
r.register(Box::new(synastry::SynastryModule));
|
||||
r.register(Box::new(solar_return::SolarReturnModule));
|
||||
r.register(Box::new(planetary_return::PlanetaryReturnModule));
|
||||
r
|
||||
}
|
||||
|
||||
@@ -395,26 +395,27 @@ pub mod synastry {
|
||||
}
|
||||
|
||||
// =====================================================================
|
||||
// SolarReturnModule — carta del año en curso (Sun back to natal Sun)
|
||||
// PlanetaryReturnModule — retornos de cualquier cuerpo a su pos natal
|
||||
// =====================================================================
|
||||
|
||||
pub mod solar_return {
|
||||
pub mod planetary_return {
|
||||
use super::*;
|
||||
|
||||
/// Computa la carta natal completa al instante del próximo retorno
|
||||
/// solar para la edad pedida. Comparte el outer ring con Transit y
|
||||
/// Synastry — mutuamente excluyentes a nivel de Shell.
|
||||
pub struct SolarReturnModule;
|
||||
/// del cuerpo elegido. Sun = anual (cumpleaños), Moon = mensual,
|
||||
/// Júpiter/Saturno = generacionales. Comparte el outer ring con
|
||||
/// Transit y Synastry — mutuamente excluyentes a nivel de Shell.
|
||||
pub struct PlanetaryReturnModule;
|
||||
|
||||
impl Module for SolarReturnModule {
|
||||
impl Module for PlanetaryReturnModule {
|
||||
fn id(&self) -> &'static str {
|
||||
"solar_return"
|
||||
"planetary_return"
|
||||
}
|
||||
fn label(&self) -> &'static str {
|
||||
"Retorno solar"
|
||||
"Retornos planetarios"
|
||||
}
|
||||
fn description(&self) -> &'static str {
|
||||
"Carta del año — Sol de vuelta a su posición natal."
|
||||
"Carta del próximo retorno (Sol, Luna, Júpiter, Saturno…)."
|
||||
}
|
||||
fn applies_to(&self, kind: ChartKind) -> bool {
|
||||
matches!(kind, ChartKind::Natal)
|
||||
@@ -430,6 +431,23 @@ pub mod solar_return {
|
||||
default: false,
|
||||
hotkey: None,
|
||||
},
|
||||
Control::Select {
|
||||
key: "body".into(),
|
||||
label: "Cuerpo".into(),
|
||||
default: "sun".into(),
|
||||
options: vec![
|
||||
SelectOption { value: "sun".into(), label: "Sol".into() },
|
||||
SelectOption { value: "moon".into(), label: "Luna".into() },
|
||||
SelectOption { value: "mercury".into(), label: "Mercurio".into() },
|
||||
SelectOption { value: "venus".into(), label: "Venus".into() },
|
||||
SelectOption { value: "mars".into(), label: "Marte".into() },
|
||||
SelectOption { value: "jupiter".into(), label: "Júpiter".into() },
|
||||
SelectOption { value: "saturn".into(), label: "Saturno".into() },
|
||||
SelectOption { value: "uranus".into(), label: "Urano".into() },
|
||||
SelectOption { value: "neptune".into(), label: "Neptuno".into() },
|
||||
SelectOption { value: "pluto".into(), label: "Plutón".into() },
|
||||
],
|
||||
},
|
||||
Control::Slider {
|
||||
key: "target_age_years".into(),
|
||||
label: "Edad del retorno".into(),
|
||||
@@ -511,7 +529,7 @@ mod tests {
|
||||
assert!(r.find("progression").is_some());
|
||||
assert!(r.find("solar_arc").is_some());
|
||||
assert!(r.find("synastry").is_some());
|
||||
assert!(r.find("solar_return").is_some());
|
||||
assert!(r.find("planetary_return").is_some());
|
||||
// Natal kind tiene 6 módulos aplicables.
|
||||
assert_eq!(r.for_kind(ChartKind::Natal).len(), 6);
|
||||
assert!(r.for_kind(ChartKind::Synastry).is_empty());
|
||||
|
||||
Reference in New Issue
Block a user