1use gpui::prelude::*;
10use gpui::{canvas, px, App, Hsla, IntoElement, Window};
11
12use crate::style::ColorValue;
13use crate::theme::theme;
14
15use super::{paint_polyline, resolve_color};
16
17#[derive(IntoElement)]
20pub struct Sparkline {
21 values: Vec<f32>,
22 color: Option<ColorValue>,
23 stroke: f32,
24 fill: bool,
25 width: Option<f32>,
26 full_width: bool,
27 height: f32,
28}
29
30impl Sparkline {
31 pub fn new(values: impl IntoIterator<Item = f32>) -> Self {
32 Sparkline {
33 values: values.into_iter().collect(),
34 color: None,
35 stroke: 2.0,
36 fill: false,
37 width: None,
38 full_width: false,
39 height: 32.0,
40 }
41 }
42
43 pub fn color(mut self, color: impl Into<ColorValue>) -> Self {
45 self.color = Some(color.into());
46 self
47 }
48
49 pub fn stroke(mut self, width: f32) -> Self {
51 self.stroke = width.max(0.5);
52 self
53 }
54
55 pub fn fill(mut self) -> Self {
57 self.fill = true;
58 self
59 }
60
61 pub fn width(mut self, width: f32) -> Self {
63 self.width = Some(width);
64 self
65 }
66
67 pub fn full_width(mut self) -> Self {
69 self.full_width = true;
70 self
71 }
72
73 pub fn height(mut self, height: f32) -> Self {
75 self.height = height;
76 self
77 }
78}
79
80impl RenderOnce for Sparkline {
81 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
82 let t = theme(cx);
83 let line = self
84 .color
85 .map(|c| resolve_color(t, c))
86 .unwrap_or_else(|| t.primary().hsla());
87 let area = self.fill.then_some(Hsla { a: 0.15, ..line });
88 let stroke = self.stroke;
89 let values = self.values;
90
91 let plot = canvas(
92 |_, _, _| (),
93 move |bounds, _, window, _cx| {
94 paint_polyline(window, bounds, &values, stroke, line, area);
95 },
96 )
97 .h(px(self.height));
98
99 if self.full_width {
100 plot.w_full()
101 } else {
102 plot.w(px(self.width.unwrap_or(120.0)))
103 }
104 }
105}