1use crate::brick::{BrickGrade, BrickScore};
4use presentar_core::{Canvas, Color, Point, Rect, TextStyle};
5use presentar_terminal::{Meter, Widget};
6
7use super::LoadControlPanelBrick;
8
9impl LoadControlPanelBrick {
10 pub(super) fn render_score_bar(value: u8, max: u8, width: usize) -> String {
12 BrickScore::render_bar(value, max, width)
13 }
14
15 pub(super) fn format_size(size: usize) -> String {
17 if size >= 1024 {
18 format!("{}K", size / 1024)
19 } else {
20 format!("{}", size)
21 }
22 }
23
24 pub fn paint(&self, canvas: &mut dyn Canvas, width: f32, _height: f32) {
26 let label_style = TextStyle {
27 color: self.theme.foreground,
28 ..Default::default()
29 };
30 let dim_style = TextStyle {
31 color: self.theme.dim,
32 ..Default::default()
33 };
34 let selected_style = TextStyle {
35 color: Color::new(0.3, 0.8, 1.0, 1.0), ..Default::default()
37 };
38 let running_style = TextStyle {
39 color: Color::new(0.3, 1.0, 0.5, 1.0), ..Default::default()
41 };
42 let stopped_style = TextStyle {
43 color: Color::new(1.0, 0.5, 0.3, 1.0), ..Default::default()
45 };
46 let error_style = TextStyle {
47 color: Color::new(1.0, 0.2, 0.2, 1.0), ..Default::default()
49 };
50
51 canvas.draw_text("Load Control", Point::new(2.0, 2.0), &label_style);
52
53 let status_text = if self.is_running {
55 "RUNNING"
56 } else {
57 "STOPPED"
58 };
59 let status_style = if self.is_running {
60 &running_style
61 } else {
62 &stopped_style
63 };
64 canvas.draw_text(status_text, Point::new(width - 12.0, 2.0), status_style);
65
66 let backend_style = if self.selected_item == 0 {
68 &selected_style
69 } else {
70 &dim_style
71 };
72 canvas.draw_text("Backend:", Point::new(2.0, 4.0), backend_style);
73 canvas.draw_text(
74 &format!("< {} >", self.backend.name()),
75 Point::new(12.0, 4.0),
76 &label_style,
77 );
78
79 let workload_style = if self.selected_item == 1 {
81 &selected_style
82 } else {
83 &dim_style
84 };
85 canvas.draw_text("Workload:", Point::new(2.0, 5.0), workload_style);
86 canvas.draw_text(
87 &format!("< {} >", self.workload.short_name()),
88 Point::new(12.0, 5.0),
89 &label_style,
90 );
91
92 let intensity_style = if self.selected_item == 2 {
94 &selected_style
95 } else {
96 &dim_style
97 };
98 canvas.draw_text("Intensity:", Point::new(2.0, 6.0), intensity_style);
99 let intensity_color = self.theme.cpu_color(self.intensity);
100 let mut intensity_meter = Meter::new(self.intensity, 100.0).with_color(intensity_color);
101 intensity_meter.layout(Rect::new(12.0, 6.0, width - 30.0, 1.0));
102 intensity_meter.paint(canvas);
103 canvas.draw_text(
104 &format!("{:.0}%", self.intensity),
105 Point::new(width - 16.0, 6.0),
106 &label_style,
107 );
108
109 let size_style = if self.selected_item == 3 {
111 &selected_style
112 } else {
113 &dim_style
114 };
115 canvas.draw_text("Size:", Point::new(2.0, 7.0), size_style);
116 canvas.draw_text(
117 &format!("< {} >", Self::format_size(self.problem_size)),
118 Point::new(12.0, 7.0),
119 &label_style,
120 );
121
122 let button_style = if self.selected_item == 4 {
124 &selected_style
125 } else {
126 &dim_style
127 };
128 let button_text = if self.is_running { "[STOP]" } else { "[START]" };
129 canvas.draw_text(button_text, Point::new(2.0, 9.0), button_style);
130
131 if let Some(ref err) = self.error {
133 canvas.draw_text("Error:", Point::new(2.0, 11.0), &error_style);
134 canvas.draw_text(err, Point::new(9.0, 11.0), &error_style);
135 }
136
137 self.paint_score_or_stats(canvas, width, &label_style, &dim_style);
139
140 canvas.draw_text(
142 "Use arrow keys to navigate, Enter to toggle",
143 Point::new(2.0, 20.0),
144 &dim_style,
145 );
146 }
147
148 fn paint_score_or_stats(
150 &self,
151 canvas: &mut dyn Canvas,
152 width: f32,
153 label_style: &TextStyle,
154 dim_style: &TextStyle,
155 ) {
156 if let Some(ref score) = self.brick_score {
157 let grade = score.grade();
158 let grade_color = match grade {
159 BrickGrade::A | BrickGrade::B => Color::new(0.3, 1.0, 0.5, 1.0), BrickGrade::C => Color::new(1.0, 0.8, 0.3, 1.0), BrickGrade::D | BrickGrade::F => Color::new(1.0, 0.3, 0.3, 1.0), };
163 let grade_style = TextStyle {
164 color: grade_color,
165 ..Default::default()
166 };
167
168 canvas.draw_text("ComputeBrick Score", Point::new(2.0, 13.0), label_style);
169 canvas.draw_text(
170 &format!("{}/100 ({})", score.total(), grade.letter()),
171 Point::new(22.0, 13.0),
172 &grade_style,
173 );
174 canvas.draw_text(
175 &format!("{:.2} GFLOP/s", self.gflops),
176 Point::new(width - 18.0, 13.0),
177 label_style,
178 );
179
180 let bar_width = 20;
182 canvas.draw_text("Performance:", Point::new(2.0, 15.0), dim_style);
183 canvas.draw_text(
184 &Self::render_score_bar(score.performance, 40, bar_width),
185 Point::new(14.0, 15.0),
186 label_style,
187 );
188 canvas.draw_text(
189 &format!("{}/40", score.performance),
190 Point::new(36.0, 15.0),
191 dim_style,
192 );
193
194 canvas.draw_text("Efficiency:", Point::new(2.0, 16.0), dim_style);
195 canvas.draw_text(
196 &Self::render_score_bar(score.efficiency, 25, bar_width),
197 Point::new(14.0, 16.0),
198 label_style,
199 );
200 canvas.draw_text(
201 &format!("{}/25", score.efficiency),
202 Point::new(36.0, 16.0),
203 dim_style,
204 );
205
206 canvas.draw_text("Correctness:", Point::new(2.0, 17.0), dim_style);
207 canvas.draw_text(
208 &Self::render_score_bar(score.correctness, 20, bar_width),
209 Point::new(14.0, 17.0),
210 label_style,
211 );
212 canvas.draw_text(
213 &format!("{}/20", score.correctness),
214 Point::new(36.0, 17.0),
215 dim_style,
216 );
217
218 canvas.draw_text("Stability:", Point::new(2.0, 18.0), dim_style);
219 canvas.draw_text(
220 &Self::render_score_bar(score.stability, 15, bar_width),
221 Point::new(14.0, 18.0),
222 label_style,
223 );
224 canvas.draw_text(
225 &format!("{}/15", score.stability),
226 Point::new(36.0, 18.0),
227 dim_style,
228 );
229 } else {
230 canvas.draw_text("Statistics", Point::new(2.0, 13.0), label_style);
232
233 canvas.draw_text("Iterations:", Point::new(2.0, 14.0), dim_style);
234 canvas.draw_text(
235 &format!("{}", self.stats.iterations),
236 Point::new(14.0, 14.0),
237 label_style,
238 );
239
240 canvas.draw_text("Ops/sec:", Point::new(2.0, 15.0), dim_style);
241 canvas.draw_text(
242 &format!("{:.1}", self.stats.ops_per_sec),
243 Point::new(14.0, 15.0),
244 label_style,
245 );
246
247 canvas.draw_text("Throughput:", Point::new(2.0, 16.0), dim_style);
248 canvas.draw_text(
249 &format!("{:.2} GB/s", self.stats.throughput_gbs),
250 Point::new(14.0, 16.0),
251 label_style,
252 );
253
254 canvas.draw_text("Avg Latency:", Point::new(2.0, 17.0), dim_style);
255 canvas.draw_text(
256 &format!("{:.1} us", self.stats.avg_latency_us),
257 Point::new(14.0, 17.0),
258 label_style,
259 );
260
261 canvas.draw_text("P99 Latency:", Point::new(2.0, 18.0), dim_style);
262 canvas.draw_text(
263 &format!("{:.1} us", self.stats.p99_latency_us),
264 Point::new(14.0, 18.0),
265 label_style,
266 );
267 }
268 }
269}