Skip to content

Commit 1dc67cd

Browse files
committed
Add configuration panel UI components: Implement header, test size controls, UI scale adjustments, and start button functionality for the SpeedTest application. This enhances user interaction by allowing configuration of test parameters and improving overall layout.
1 parent c754025 commit 1dc67cd

File tree

6 files changed

+230
-0
lines changed

6 files changed

+230
-0
lines changed

src/ui/config_panel/header.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
use eframe::egui;
2+
use egui_phosphor::regular::*;
3+
4+
pub fn render_header(ui: &mut egui::Ui) {
5+
ui.vertical_centered(|ui| {
6+
ui.add_space(10.0);
7+
ui.heading(format!("{LIGHTNING} DMA Speed Test"));
8+
ui.add_space(5.0);
9+
ui.label("Configure your test parameters below");
10+
ui.add_space(15.0);
11+
});
12+
}

src/ui/config_panel/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
mod connector_section;
2+
mod header;
3+
mod panel;
4+
mod start_button;
5+
mod test_sizes;
6+
mod ui_scale;
7+
8+
pub use panel::render_config_panel;

src/ui/config_panel/panel.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use eframe::egui;
2+
use egui_phosphor::regular::*;
3+
4+
use crate::speedtest::Connector;
5+
use crate::ui::types::ConfigParams;
6+
7+
use super::{
8+
connector_section::render_connector_section, header::render_header,
9+
start_button::render_start_button, test_sizes::render_test_size_controls,
10+
ui_scale::render_ui_scale_controls,
11+
};
12+
13+
pub fn render_config_panel(
14+
ui: &mut egui::Ui,
15+
params: &mut ConfigParams<'_>,
16+
on_start_test: impl FnOnce(),
17+
) {
18+
render_header(ui);
19+
20+
egui::Frame::new()
21+
.fill(ui.visuals().extreme_bg_color)
22+
.corner_radius(8.0)
23+
.inner_margin(15.0)
24+
.show(ui, |ui| {
25+
ui.set_width(ui.available_width());
26+
27+
render_ui_scale_controls(ui, params.ui_scale, params.ui_scale_text);
28+
ui.add_space(10.0);
29+
30+
render_connector_section(ui, params.connector, params.pcileech_device);
31+
render_duration_slider(ui, params.duration);
32+
33+
render_test_size_controls(params.test_sizes, ui);
34+
35+
ui.add_space(15.0);
36+
let needs_pcileech_device = *params.connector == Connector::Pcileech
37+
&& params.pcileech_device.trim().is_empty();
38+
let any_size_selected = params.test_sizes.iter().any(|(_, enabled)| *enabled);
39+
render_start_button(
40+
ui,
41+
needs_pcileech_device,
42+
any_size_selected,
43+
on_start_test,
44+
params.show_error_modal,
45+
params.error_modal_message,
46+
params.show_config,
47+
);
48+
});
49+
}
50+
51+
fn render_duration_slider(ui: &mut egui::Ui, duration: &mut u64) {
52+
ui.add_space(8.0);
53+
ui.label(format!("{CLOCK} Test Duration"));
54+
ui.horizontal(|ui| {
55+
ui.add(egui::Slider::new(duration, 1..=60).text("seconds"));
56+
});
57+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use eframe::egui;
2+
3+
pub fn render_start_button(
4+
ui: &mut egui::Ui,
5+
connector_requires_device: bool,
6+
has_selected_size: bool,
7+
on_start: impl FnOnce(),
8+
show_error_modal: &mut bool,
9+
error_modal_message: &mut String,
10+
show_config: &mut bool,
11+
) {
12+
ui.vertical_centered(|ui| {
13+
let start_button =
14+
egui::Button::new(egui::RichText::new("START TEST").color(egui::Color32::BLACK))
15+
.fill(egui::Color32::from_rgb(46, 204, 113))
16+
.stroke(egui::Stroke::new(2.0, egui::Color32::from_rgb(39, 174, 96)));
17+
18+
if ui.add_sized([250.0, 55.0], start_button).clicked() {
19+
if connector_requires_device {
20+
*show_error_modal = true;
21+
*error_modal_message = "PCILeech device must be specified".to_string();
22+
} else if !has_selected_size {
23+
*show_error_modal = true;
24+
*error_modal_message = "At least one test size must be selected".to_string();
25+
} else {
26+
*show_config = false;
27+
on_start();
28+
}
29+
}
30+
});
31+
}

src/ui/config_panel/test_sizes.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use eframe::egui;
2+
use egui_phosphor::regular::*;
3+
4+
use crate::ui::helpers::{color_for_size, get_size_label};
5+
6+
pub fn render_test_size_controls(test_sizes: &mut [(usize, bool)], ui: &mut egui::Ui) {
7+
ui.label(format!("{CHART_BAR} Test Sizes"));
8+
ui.label("Select which read sizes to test:");
9+
10+
render_bulk_actions(test_sizes, ui);
11+
ui.add_space(8.0);
12+
render_size_grid(test_sizes, ui);
13+
}
14+
15+
fn render_bulk_actions(test_sizes: &mut [(usize, bool)], ui: &mut egui::Ui) {
16+
ui.horizontal(|ui| {
17+
if ui.button("Select All").clicked() {
18+
for (_, enabled) in test_sizes.iter_mut() {
19+
*enabled = true;
20+
}
21+
}
22+
23+
ui.add_space(8.0);
24+
25+
if ui.button("Deselect All").clicked() {
26+
for (_, enabled) in test_sizes.iter_mut() {
27+
*enabled = false;
28+
}
29+
}
30+
31+
ui.add_space(8.0);
32+
33+
if ui.button("Default").clicked() {
34+
for (size, enabled) in test_sizes.iter_mut() {
35+
*enabled = matches!(*size, 4096 | 8192 | 16384 | 32768);
36+
}
37+
}
38+
});
39+
}
40+
41+
fn render_size_grid(test_sizes: &mut [(usize, bool)], ui: &mut egui::Ui) {
42+
egui::Grid::new("test_sizes_grid")
43+
.num_columns(3)
44+
.spacing([16.0, 8.0])
45+
.show(ui, |ui| {
46+
for (index, (size, enabled)) in test_sizes.iter_mut().enumerate() {
47+
let label = get_size_label(*size);
48+
let color = color_for_size(*size);
49+
50+
let is_selected = *enabled;
51+
let checkmark = if is_selected { CHECK } else { "" };
52+
let text = egui::RichText::new(format!("{checkmark} {label}"))
53+
.color(color)
54+
.strong();
55+
56+
let stroke = if is_selected {
57+
egui::Stroke::new(2.0, color)
58+
} else {
59+
ui.visuals().widgets.inactive.bg_stroke
60+
};
61+
62+
let fill = if is_selected {
63+
ui.visuals().faint_bg_color
64+
} else {
65+
ui.visuals().extreme_bg_color
66+
};
67+
68+
let button = egui::Button::new(text)
69+
.fill(fill)
70+
.stroke(stroke)
71+
.corner_radius(6.0);
72+
73+
if ui
74+
.add_sized([140.0, ui.spacing().interact_size.y * 1.2], button)
75+
.clicked()
76+
{
77+
*enabled = !*enabled;
78+
}
79+
80+
if (index + 1).is_multiple_of(3) {
81+
ui.end_row();
82+
}
83+
}
84+
85+
if !test_sizes.len().is_multiple_of(3) {
86+
ui.end_row();
87+
}
88+
});
89+
}

src/ui/config_panel/ui_scale.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use eframe::egui;
2+
use egui_phosphor::regular::*;
3+
4+
pub fn render_ui_scale_controls(ui: &mut egui::Ui, ui_scale: &mut f32, ui_scale_text: &mut String) {
5+
ui.horizontal(|ui| {
6+
ui.label(format!("{MAGNIFYING_GLASS} UI Scale"));
7+
let button_size = egui::vec2(22.0, ui.spacing().interact_size.y);
8+
9+
if ui.add_sized(button_size, egui::Button::new("-")).clicked() {
10+
*ui_scale = (*ui_scale - 0.1).max(0.3);
11+
}
12+
13+
if ui_scale_text.parse::<f32>().unwrap_or(1.0) != *ui_scale {
14+
*ui_scale_text = format!("{ui_scale:.1}");
15+
}
16+
17+
let text_width = 70.0;
18+
if ui
19+
.add_sized(
20+
[text_width, ui.spacing().interact_size.y],
21+
egui::TextEdit::singleline(ui_scale_text),
22+
)
23+
.changed()
24+
&& let Ok(parsed_scale) = ui_scale_text.parse::<f32>()
25+
{
26+
*ui_scale = parsed_scale.clamp(0.3, 3.0);
27+
}
28+
29+
if ui.add_sized(button_size, egui::Button::new("+")).clicked() {
30+
*ui_scale = (*ui_scale + 0.1).min(3.0);
31+
}
32+
});
33+
}

0 commit comments

Comments
 (0)