tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 660Markdown 302TOML 157RON 312382 Definiciones

⎇ main llimphi-voxel-studio/src/helpers.rs Rust · 166 líneas · 5.6 KB Historia Quién tocó qué crudo

chore: refresco desde el monorepo — 132 miembros, 79 widgets, la galería vuelve y licencia dual d8edd9a9c · Sergio ·

1use super::*;
2
3pub(crate) fn selectable_row(label: String, selected: bool, msg: Msg, theme: &Theme) -> View<Msg> {
4    View::new(Style {
5        size: Size { width: percent(1.0_f32), height: length(30.0_f32) },
6        align_items: Some(AlignItems::CENTER),
7        padding: pad(10.0, 0.0),
8        ..Default::default()
9    })
10    .fill(if selected { theme.bg_selected } else { theme.bg_panel })
11    .radius(6.0)
12    .text(label, 15.0, if selected { theme.fg_text } else { theme.fg_muted })
13    .on_click(msg)
14}
15
16pub(crate) fn section_title(text: &str, theme: &Theme) -> View<Msg> {
17    View::new(Style {
18        size: Size { width: percent(1.0_f32), height: length(20.0_f32) },
19        ..Default::default()
20    })
21    .text(text.to_string(), 12.0, theme.accent)
22    .bold()
23}
24
25pub(crate) fn body_text(s: String, color: Color, _theme: &Theme) -> View<Msg> {
26    View::new(Style {
27        size: Size { width: percent(1.0_f32), height: Dimension::auto() },
28        ..Default::default()
29    })
30    .text(s, 13.0, color)
31    .max_lines(2)
32}
33
34pub(crate) fn spacer(h: f32) -> View<Msg> {
35    View::new(Style {
36        size: Size { width: percent(1.0_f32), height: length(h) },
37        ..Default::default()
38    })
39}
40
41pub(crate) fn pad(
42    x: f32,
43    y: f32,
44) -> llimphi_ui::llimphi_layout::taffy::prelude::Rect<llimphi_ui::llimphi_layout::taffy::prelude::LengthPercentage> {
45    use llimphi_ui::llimphi_layout::taffy::prelude::Rect;
46    Rect { left: length(x), right: length(x), top: length(y), bottom: length(y) }
47}
48
49pub(crate) fn gap_y(h: f32) -> Size<llimphi_ui::llimphi_layout::taffy::prelude::LengthPercentage> {
50    Size { width: length(0.0_f32), height: length(h) }
51}
52
53// =============================================================================
54//  Persistencia RON
55// =============================================================================
56
57// Guardar/cargar el proyecto en el path por defecto usan el mismo `Documento`
58// (con marca + versión) que abrir/guardar-como/combinar — un solo formato.
59pub(crate) fn save_project(project: &Project) -> Result<(), String> {
60    Documento::nuevo(project.clone())
61        .guardar(PROJECT_PATH)
62        .map_err(|e| e.to_string())
63}
64
65pub(crate) fn load_project() -> Result<Project, String> {
66    Documento::abrir(PROJECT_PATH)
67        .map(|d| d.proyecto)
68        .map_err(|e| e.to_string())
69}
70
71/// Estado de arranque (sin `Handle`) — reusado por `init` y por el pantallazo.
72pub(crate) fn demo_model() -> Model {
73    let project = Project::starter();
74    // Orientación de los dientes (rail Adentro/Afuera) heredada del SO.
75    let dientes_outside = wawa_config::WawaConfig::load().dientes_outside;
76    let mut model = Model {
77        theme: Theme::dark(),
78        level: Level::Mundos,
79        sel: [0; 7],
80        tool_tab: 0,
81        gen: 1,
82        yaw: 35_f32.to_radians(),
83        pitch: 26_f32.to_radians(),
84        dist: default_dist(),
85        preview: Arc::new(Mutex::new(None)),
86        mapa: None,
87        status: "creador de mundos por niveles".into(),
88        name_input: TextInputState::new(),
89        name_focused: false,
90        seed_input: TextInputState::new(),
91        seed_focused: false,
92        ai_input: TextInputState::new(),
93        ai_focused: false,
94        ai_busy: false,
95        file_input: {
96            let mut t = TextInputState::new();
97            t.set_text(PROJECT_PATH.to_string());
98            t
99        },
100        file_focused: false,
101        historia: Historia::abrir(HISTORY_PATH).unwrap_or_default(),
102        jugando: false,
103        jugador: Arc::new(Mutex::new(Player::new(Vec3::ZERO))),
104        input_juego: InputJuego::default(),
105        volar: false,
106        respawn_jugador: Arc::new(Mutex::new(false)),
107        time: 0.0,
108        playing: false,
109        script_cam: true,
110        exporting: false,
111        simulating: false,
112        andar_estado: 1, // caminar
113        manada: false,
114        actor_sel: 0,
115        utileria_sel: 0,
116        decorado_sel: 0,
117        key_sel: 0,
118        rng: 0x1234_5678,
119        mueble_brush: Mueble::Mesa,
120        mueble_facing: 0,
121        pueblo_brush: PuebloTipo::Aldea,
122        // Los dos sidebars unificados: selectores fijos, abiertos sobre el nivel/tool
123        // activos. El eje "Rail Adentro/Afuera" hereda el viejo `dientes_outside` del
124        // SO. El izquierdo lista items (más angosto); el derecho, el editor de tools.
125        sidebar_left: {
126            let mut s = RagSidebarState {
127                open: Some(Level::Mundos.index() as u64),
128                selected: Some(Level::Mundos.index() as u64),
129                panel_w: 214.0,
130                rail_outside: dientes_outside,
131                ..Default::default()
132            };
133            // El ancho al que quedó el divisor la última vez (si lo hubo).
134            llimphi_widget_rag_sidebar::persistencia::restaurar(&mut s, "voxel-studio", "izq");
135            s
136        },
137        sidebar_right: {
138            let mut s = RagSidebarState {
139                open: Some(0),
140                selected: Some(0),
141                panel_w: 256.0,
142                rail_outside: dientes_outside,
143                ..Default::default()
144            };
145            llimphi_widget_rag_sidebar::persistencia::restaurar(&mut s, "voxel-studio", "der");
146            s
147        },
148        lab: None,
149        lab_gen: 1,
150        formula_input: TextInputState::new(),
151        formula_focused: false,
152        formula_target: 0,
153        cond_formula_input: TextInputState::new(),
154        cond_formula_focused: false,
155        cond_formula_target: 0,
156        leyes_node_mode: false,
157        eq_graph: None,
158        eq_graph_gen: 0,
159        clipboard: SystemClipboard::new(),
160        project,
161    };
162    reselect_all(&mut model);
163    sync_inputs(&mut model);
164    model
165}
166