gioser

tawasuyu/brahman

Rust 582TOML 222Markdown 73JSON 198635 Sutichaykuna

⎇ 2b2a92a72b8aa6d4e006189cbeda5a53e74a80c0 crates/apps/pineal-demo/src/main.rs Rust · 231 siq'ikuna · 7.8 KB Ñawpa willay Pi imata llamkarqan ch'uya

refactor(monorepo): reorganización lógica + renames + SDDs + split CHANGELOG 550c98f27 · sergio ·

1//! `pineal-demo` — demo visual de Lapaloma sobre nahual.
2//!
3//! Ventana 900×560 con un chart cartesiano de **3 series**
4//! simultáneas sobre 1024 muestras:
5//!
6//! - `sin(x · 0.04)` — azul nórdico
7//! - `cos(x · 0.04)` — naranja
8//! - `0.5·sin(x · 0.02) + 0.5·cos(x · 0.08)` — verde
9//!
10//! Interacción: click+drag = pan, wheel = zoom, doble-click = reset.
11
12use gpui::{
13    div, prelude::*, px, ClickEvent, Context, IntoElement, MouseButton, MouseDownEvent,
14    MouseMoveEvent, MouseUpEvent, Point, Render, ScrollDelta, ScrollWheelEvent, Window,
15};
16
17use pineal_cartesian::{chart_cache, ChartCacheHandle, ChartViewport, LapalomaChartElement};
18use pineal_core::buffer::DataBuffer;
19use pineal_render::{Color, StrokeStyle};
20use nahual_launcher::launch_app;
21use nahual_theme::Theme;
22
23const N_SAMPLES: usize = 1024;
24const WHEEL_SENSITIVITY: f64 = 0.0015;
25
26fn main() {
27    launch_app(
28        "Lapaloma — multi-series (drag = pan, wheel = zoom, dbl-click = reset)",
29        (900., 560.),
30        Demo::new,
31    );
32}
33
34struct Demo {
35    series_sin: DataBuffer,
36    series_cos: DataBuffer,
37    series_mix: DataBuffer,
38    viewport: ChartViewport,
39    initial_viewport: ChartViewport,
40    drag: Option<DragAnchor>,
41    chart_cache: ChartCacheHandle,
42}
43
44#[derive(Clone, Copy)]
45struct DragAnchor {
46    start_position: Point<gpui::Pixels>,
47    viewport_at_start: ChartViewport,
48}
49
50impl Demo {
51    fn new(_cx: &mut Context<Self>) -> Self {
52        let mut sin = DataBuffer::with_capacity(N_SAMPLES);
53        let mut cos = DataBuffer::with_capacity(N_SAMPLES);
54        let mut mix = DataBuffer::with_capacity(N_SAMPLES);
55        for i in 0..N_SAMPLES {
56            let x = i as f32;
57            sin.push(x, (x * 0.04).sin());
58            cos.push(x, (x * 0.04).cos());
59            mix.push(x, 0.5 * (x * 0.02).sin() + 0.5 * (x * 0.08).cos());
60        }
61        let viewport = ChartViewport::new(0.0, (N_SAMPLES - 1) as f64, -1.3, 1.3);
62        Self {
63            series_sin: sin,
64            series_cos: cos,
65            series_mix: mix,
66            viewport,
67            initial_viewport: viewport,
68            drag: None,
69            chart_cache: chart_cache(),
70        }
71    }
72
73    fn on_mouse_down(&mut self, e: &MouseDownEvent, _w: &mut Window, cx: &mut Context<Self>) {
74        self.drag = Some(DragAnchor {
75            start_position: e.position,
76            viewport_at_start: self.viewport,
77        });
78        cx.notify();
79    }
80
81    fn on_mouse_move(&mut self, e: &MouseMoveEvent, window: &mut Window, cx: &mut Context<Self>) {
82        let Some(anchor) = self.drag else { return };
83        let win = window.viewport_size();
84        let w: f32 = win.width.into();
85        let h: f32 = win.height.into();
86        if w <= 0.0 || h <= 0.0 {
87            return;
88        }
89        let sx: f32 = e.position.x.into();
90        let sy: f32 = e.position.y.into();
91        let ax: f32 = anchor.start_position.x.into();
92        let ay: f32 = anchor.start_position.y.into();
93        let dfx = ((sx - ax) / w) as f64;
94        let dfy = ((sy - ay) / h) as f64;
95        let mut vp = anchor.viewport_at_start;
96        vp.pan_fraction(dfx, dfy);
97        self.viewport = vp;
98        cx.notify();
99    }
100
101    fn on_mouse_up(&mut self, _e: &MouseUpEvent, _w: &mut Window, cx: &mut Context<Self>) {
102        if self.drag.take().is_some() {
103            cx.notify();
104        }
105    }
106
107    fn on_scroll(&mut self, e: &ScrollWheelEvent, window: &mut Window, cx: &mut Context<Self>) {
108        let win = window.viewport_size();
109        let w: f32 = win.width.into();
110        let h: f32 = win.height.into();
111        if w <= 0.0 || h <= 0.0 {
112            return;
113        }
114        let dy_px: f32 = match e.delta {
115            ScrollDelta::Pixels(p) => p.y.into(),
116            ScrollDelta::Lines(p) => p.y * 16.0,
117        };
118        let factor = (-dy_px as f64 * WHEEL_SENSITIVITY).exp();
119        let sx: f32 = e.position.x.into();
120        let sy: f32 = e.position.y.into();
121        let ax = (sx / w).clamp(0.0, 1.0) as f64;
122        let ay = (1.0 - sy / h).clamp(0.0, 1.0) as f64;
123        self.viewport.zoom_uniform(factor, (ax, ay));
124        cx.notify();
125    }
126
127    fn on_click(&mut self, e: &ClickEvent, _w: &mut Window, cx: &mut Context<Self>) {
128        if let ClickEvent::Mouse(m) = e {
129            if m.up.click_count >= 2 {
130                self.viewport = self.initial_viewport;
131                cx.notify();
132            }
133        }
134    }
135}
136
137/// Color helper para usar el mismo hex tanto en `pineal_render`
138/// como en el body de texto del header del demo.
139const COLOR_SIN: u32 = 0x88c0d0; // azul nórdico
140const COLOR_COS: u32 = 0xd08770; // naranja
141const COLOR_MIX: u32 = 0xa3be8c; // verde
142
143impl Render for Demo {
144    fn render(&mut self, _w: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
145        let theme = Theme::global(cx).clone();
146
147        let plot_bg = Color::rgba(0.10, 0.12, 0.16, 1.0);
148        let chart = LapalomaChartElement::new(self.viewport)
149            .background(plot_bg)
150            .with_cache(self.chart_cache.clone())
151            .add_series_named(
152                self.series_sin.clone(),
153                StrokeStyle::new(2.0, Color::from_hex(COLOR_SIN)),
154                "sin",
155            )
156            .add_series_named(
157                self.series_cos.clone(),
158                StrokeStyle::new(2.0, Color::from_hex(COLOR_COS)),
159                "cos",
160            )
161            .add_series_named(
162                self.series_mix.clone(),
163                StrokeStyle::new(2.0, Color::from_hex(COLOR_MIX)),
164                "mix",
165            );
166
167        let drag_active = self.drag.is_some();
168        let (pan_blits, rebuilds) = {
169            let c = self.chart_cache.lock().unwrap();
170            (c.pan_blits(), c.rebuilds())
171        };
172
173        div()
174            .id("pineal-demo-root")
175            .size_full()
176            .bg(theme.bg_app.clone())
177            .p(px(16.))
178            .flex()
179            .flex_col()
180            .gap(px(12.))
181            .child(
182                div()
183                    .text_color(theme.fg_text)
184                    .text_size(px(18.))
185                    .child("Lapaloma — demo cartesian multi-series"),
186            )
187            .child(
188                div()
189                    .flex()
190                    .gap(px(14.))
191                    .text_size(px(11.))
192                    .child(
193                        div()
194                            .text_color(gpui::rgb(COLOR_SIN))
195                            .child("■ sin(x · 0.04)"),
196                    )
197                    .child(
198                        div()
199                            .text_color(gpui::rgb(COLOR_COS))
200                            .child("■ cos(x · 0.04)"),
201                    )
202                    .child(
203                        div()
204                            .text_color(gpui::rgb(COLOR_MIX))
205                            .child("■ ½·sin(x · 0.02) + ½·cos(x · 0.08)"),
206                    )
207                    .child(
208                        div()
209                            .text_color(theme.fg_muted)
210                            .child(format!(
211                                "· cache: {} pan-blits / {} rebuilds {}",
212                                pan_blits,
213                                rebuilds,
214                                if drag_active { "· dragging" } else { "" },
215                            )),
216                    ),
217            )
218            .child(
219                div()
220                    .id("pineal-chart-host")
221                    .w_full()
222                    .flex_grow()
223                    .child(chart)
224                    .on_mouse_down(MouseButton::Left, cx.listener(Self::on_mouse_down))
225                    .on_mouse_move(cx.listener(Self::on_mouse_move))
226                    .on_mouse_up(MouseButton::Left, cx.listener(Self::on_mouse_up))
227                    .on_scroll_wheel(cx.listener(Self::on_scroll))
228                    .on_click(cx.listener(Self::on_click)),
229            )
230    }
231}