use super::*; pub(crate) fn selectable_row(label: String, selected: bool, msg: Msg, theme: &Theme) -> View { View::new(Style { size: Size { width: percent(1.0_f32), height: length(30.0_f32) }, align_items: Some(AlignItems::CENTER), padding: pad(10.0, 0.0), ..Default::default() }) .fill(if selected { theme.bg_selected } else { theme.bg_panel }) .radius(6.0) .text(label, 15.0, if selected { theme.fg_text } else { theme.fg_muted }) .on_click(msg) } pub(crate) fn section_title(text: &str, theme: &Theme) -> View { View::new(Style { size: Size { width: percent(1.0_f32), height: length(20.0_f32) }, ..Default::default() }) .text(text.to_string(), 12.0, theme.accent) .bold() } pub(crate) fn body_text(s: String, color: Color, _theme: &Theme) -> View { View::new(Style { size: Size { width: percent(1.0_f32), height: Dimension::auto() }, ..Default::default() }) .text(s, 13.0, color) .max_lines(2) } pub(crate) fn spacer(h: f32) -> View { View::new(Style { size: Size { width: percent(1.0_f32), height: length(h) }, ..Default::default() }) } pub(crate) fn pad( x: f32, y: f32, ) -> llimphi_ui::llimphi_layout::taffy::prelude::Rect { use llimphi_ui::llimphi_layout::taffy::prelude::Rect; Rect { left: length(x), right: length(x), top: length(y), bottom: length(y) } } pub(crate) fn gap_y(h: f32) -> Size { Size { width: length(0.0_f32), height: length(h) } } // ============================================================================= // Persistencia RON // ============================================================================= // Guardar/cargar el proyecto en el path por defecto usan el mismo `Documento` // (con marca + versión) que abrir/guardar-como/combinar — un solo formato. pub(crate) fn save_project(project: &Project) -> Result<(), String> { Documento::nuevo(project.clone()) .guardar(PROJECT_PATH) .map_err(|e| e.to_string()) } pub(crate) fn load_project() -> Result { Documento::abrir(PROJECT_PATH) .map(|d| d.proyecto) .map_err(|e| e.to_string()) } /// Estado de arranque (sin `Handle`) — reusado por `init` y por el pantallazo. pub(crate) fn demo_model() -> Model { let project = Project::starter(); // Orientación de los dientes (rail Adentro/Afuera) heredada del SO. let dientes_outside = wawa_config::WawaConfig::load().dientes_outside; let mut model = Model { theme: Theme::dark(), level: Level::Mundos, sel: [0; 7], tool_tab: 0, gen: 1, yaw: 35_f32.to_radians(), pitch: 26_f32.to_radians(), dist: default_dist(), preview: Arc::new(Mutex::new(None)), mapa: None, status: "creador de mundos por niveles".into(), name_input: TextInputState::new(), name_focused: false, seed_input: TextInputState::new(), seed_focused: false, ai_input: TextInputState::new(), ai_focused: false, ai_busy: false, file_input: { let mut t = TextInputState::new(); t.set_text(PROJECT_PATH.to_string()); t }, file_focused: false, historia: Historia::abrir(HISTORY_PATH).unwrap_or_default(), jugando: false, jugador: Arc::new(Mutex::new(Player::new(Vec3::ZERO))), input_juego: InputJuego::default(), volar: false, respawn_jugador: Arc::new(Mutex::new(false)), time: 0.0, playing: false, script_cam: true, exporting: false, simulating: false, andar_estado: 1, // caminar manada: false, actor_sel: 0, utileria_sel: 0, decorado_sel: 0, key_sel: 0, rng: 0x1234_5678, mueble_brush: Mueble::Mesa, mueble_facing: 0, pueblo_brush: PuebloTipo::Aldea, // Los dos sidebars unificados: selectores fijos, abiertos sobre el nivel/tool // activos. El eje "Rail Adentro/Afuera" hereda el viejo `dientes_outside` del // SO. El izquierdo lista items (más angosto); el derecho, el editor de tools. sidebar_left: { let mut s = RagSidebarState { open: Some(Level::Mundos.index() as u64), selected: Some(Level::Mundos.index() as u64), panel_w: 214.0, rail_outside: dientes_outside, ..Default::default() }; // El ancho al que quedó el divisor la última vez (si lo hubo). llimphi_widget_rag_sidebar::persistencia::restaurar(&mut s, "voxel-studio", "izq"); s }, sidebar_right: { let mut s = RagSidebarState { open: Some(0), selected: Some(0), panel_w: 256.0, rail_outside: dientes_outside, ..Default::default() }; llimphi_widget_rag_sidebar::persistencia::restaurar(&mut s, "voxel-studio", "der"); s }, lab: None, lab_gen: 1, formula_input: TextInputState::new(), formula_focused: false, formula_target: 0, cond_formula_input: TextInputState::new(), cond_formula_focused: false, cond_formula_target: 0, leyes_node_mode: false, eq_graph: None, eq_graph_gen: 0, clipboard: SystemClipboard::new(), project, }; reselect_all(&mut model); sync_inputs(&mut model); model }