tawasuyu

tawasuyu/brahman

Rust 326TOML 123JSON 17Markdown 144606 Definitions

⎇ d3649bfd1a80153652c2a028315369bb4b184024 crates/modules/ui_engine/libs/launcher/src/lib.rs Rust · 123 lines · 4.0 KB History Who touched what raw

feat(yahweh-launcher): F3 — extracción del shell standard de explorers 37e40073e · Sergio ·

1//! Yahweh shell — reduce el boot de un app GPUI temed a una línea.
2//!
3//! Las 4 (próximamente más) apps explorer del repo declaran el mismo
4//! patrón: `Application::new + Theme::install_default + cx.open_window
5//! + cx.activate(true)`. Sólo varían el título, el tamaño inicial y la
6//! fábrica del root entity.
7//!
8//! Antes (~20 líneas):
9//!
10//! ```ignore
11//! Application::new().run(|cx: &mut App| {
12//!     Theme::install_default(cx);
13//!     let bounds = Bounds::centered(None, gpui::size(px(900.), px(640.)), cx);
14//!     cx.open_window(
15//!         WindowOptions {
16//!             window_bounds: Some(WindowBounds::Windowed(bounds)),
17//!             titlebar: Some(gpui::TitlebarOptions {
18//!                 title: Some(SharedString::from("Nakui — Event Log")),
19//!                 ..Default::default()
20//!             }),
21//!             ..Default::default()
22//!         },
23//!         |_w, cx| cx.new(Explorer::new),
24//!     ).expect("open window");
25//!     cx.activate(true);
26//! });
27//! ```
28//!
29//! Ahora (1 línea):
30//!
31//! ```ignore
32//! launch_app("Nakui — Event Log", (900., 640.), Explorer::new);
33//! ```
34
35use gpui::{
36    App, AppContext, Application, Bounds, Context, Render, SharedString, TitlebarOptions,
37    WindowBounds, WindowOptions, px,
38};
39use yahweh_theme::Theme;
40
41/// Configuración del primer (y normalmente único) ventana del app.
42///
43/// `size` es `(ancho, alto)` en píxeles lógicos. La ventana queda
44/// centrada en el monitor primario.
45pub struct AppLaunchConfig {
46    pub title: SharedString,
47    pub size: (f32, f32),
48}
49
50impl AppLaunchConfig {
51    pub fn new(title: impl Into<SharedString>, size: (f32, f32)) -> Self {
52        Self {
53            title: title.into(),
54            size,
55        }
56    }
57}
58
59/// Levanta un app GPUI con tema instalado y root entity construido.
60///
61/// El root debe implementar `Render`. La fábrica `root_factory` recibe
62/// el `Context<T>` del nuevo entity para que pueda usar `cx.spawn`,
63/// suscribirse a eventos, etc — lo mismo que en el patrón directo.
64///
65/// Bloquea el thread main hasta que se cierre la ventana
66/// (`Application::run` no retorna).
67pub fn launch_app<T, F>(title: impl Into<SharedString>, size: (f32, f32), root_factory: F)
68where
69    T: Render + 'static,
70    F: FnOnce(&mut Context<T>) -> T + Send + 'static,
71{
72    launch_app_with(AppLaunchConfig::new(title, size), root_factory);
73}
74
75/// Variante que acepta un `AppLaunchConfig` armado afuera. Útil cuando
76/// el config se calcula condicionalmente (env var para tamaño, etc).
77pub fn launch_app_with<T, F>(config: AppLaunchConfig, root_factory: F)
78where
79    T: Render + 'static,
80    F: FnOnce(&mut Context<T>) -> T + Send + 'static,
81{
82    Application::new().run(move |cx: &mut App| {
83        Theme::install_default(cx);
84        let bounds = Bounds::centered(None, gpui::size(px(config.size.0), px(config.size.1)), cx);
85        cx.open_window(
86            WindowOptions {
87                window_bounds: Some(WindowBounds::Windowed(bounds)),
88                titlebar: Some(TitlebarOptions {
89                    title: Some(config.title.clone()),
90                    ..Default::default()
91                }),
92                ..Default::default()
93            },
94            |_w, cx| cx.new(root_factory),
95        )
96        .expect("open window");
97        cx.activate(true);
98    });
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn config_new_normalizes_inputs() {
107        let c = AppLaunchConfig::new("My App", (800.0, 600.0));
108        assert_eq!(c.title.as_ref(), "My App");
109        assert_eq!(c.size, (800.0, 600.0));
110    }
111
112    #[test]
113    fn config_accepts_owned_string_title() {
114        let owned = String::from("Owned Title");
115        let c = AppLaunchConfig::new(owned, (400.0, 300.0));
116        assert_eq!(c.title.as_ref(), "Owned Title");
117    }
118
119    // No hay test de `launch_app` aquí: bloquea el thread main hasta
120    // que la ventana se cierre, y en sandbox no hay DISPLAY. La
121    // cobertura real es que cada explorer app lo invoque y arranque
122    // (smoke test manual o con DISPLAY).
123}