egui_charts/ui_kit/form/
mod.rs1use crate::localization as l10n;
26use crate::theme::ThemeExt;
27pub mod grid;
28
29use crate::tokens::DESIGN_TOKENS;
30use egui::{Align, Layout, RichText, Ui, vec2};
31
32pub use grid::FormGrid;
33
34pub struct FormRow<'a> {
36 label: &'a str,
37 description: Option<&'a str>,
38 label_width: f32,
39}
40
41impl<'a> FormRow<'a> {
42 pub fn new(label: &'a str) -> Self {
44 Self {
45 label,
46 description: None,
47 label_width: DESIGN_TOKENS.sizing.settings_dialog.label_width,
48 }
49 }
50
51 pub fn description(mut self, desc: &'a str) -> Self {
53 self.description = Some(desc);
54 self
55 }
56
57 pub fn label_width(mut self, width: f32) -> Self {
59 self.label_width = width;
60 self
61 }
62
63 pub fn show(self, ui: &mut Ui, add_widget: impl FnOnce(&mut Ui)) {
68 let spacing = ui.spacing().item_spacing;
69 ui.spacing_mut().item_spacing.y = ui.active_theme().spacing.md;
70 ui.horizontal(|ui| {
71 ui.spacing_mut().item_spacing.x = ui.active_theme().spacing.lg;
72 let label = ui.allocate_ui_with_layout(
73 vec2(self.label_width, ui.spacing().interact_size.y),
74 Layout::left_to_right(Align::Center),
75 |ui| {
76 ui.set_width(self.label_width);
77 ui.label(l10n::text(ui.ctx(), self.label))
78 },
79 );
80 ui.with_layout(Layout::left_to_right(Align::Center), |ui| {
81 ui.label_inputs_by(label.inner.id, add_widget);
82 });
83 });
84 if let Some(desc) = self.description {
85 ui.label(
86 RichText::new(l10n::text(ui.ctx(), desc))
87 .size(ui.active_theme().text.small)
88 .color(ui.visuals().weak_text_color()),
89 );
90 }
91 ui.spacing_mut().item_spacing = spacing;
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn rows_share_the_grid_control_edge_and_pitch() {
101 let ctx = egui::Context::default();
102 for frame in 0..3 {
103 ctx.run_ui(Default::default(), |ui| {
104 let width = 120.0;
105 let mut rows = Vec::new();
106 for control_width in [40.0, 100.0, 40.0] {
107 FormRow::new("Label").label_width(width).show(ui, |ui| {
108 rows.push(
109 ui.allocate_exact_size(vec2(control_width, 24.0), egui::Sense::hover())
110 .0,
111 );
112 });
113 }
114 let mut grid = Vec::new();
115 FormGrid::new("comparison").show(ui, |ui| {
116 for _ in 0..2 {
117 ui.add_sized(vec2(width, 24.0), egui::Label::new("Label"));
118 grid.push(
119 ui.allocate_exact_size(vec2(40.0, 24.0), egui::Sense::hover())
120 .0,
121 );
122 ui.end_row();
123 }
124 });
125 if frame < 2 {
126 return;
127 }
128 assert_eq!(rows[0].left(), rows[1].left());
129 assert_eq!(rows[0].left(), grid[0].left());
130 assert_eq!(rows[1].top() - rows[0].top(), grid[1].top() - grid[0].top());
131 })
132 .drop_without_applying_deltas();
133 }
134 }
135}