Skip to main content

egui_components/
description_list.rs

1//! `DescriptionList` — term / description pairs (an HTML `<dl>` equivalent).
2//!
3//! ```ignore
4//! sc::DescriptionList::new()
5//!     .item("Name", "Ada Lovelace")
6//!     .item("Role", "Mathematician")
7//!     .bordered()
8//!     .show(ui);
9//! ```
10
11use egui::{Frame, Margin, Ui};
12use egui_components_theme::Theme;
13
14use crate::common::Size;
15use crate::label::Label;
16use crate::separator::Separator;
17
18pub struct DescriptionList {
19    rows: Vec<(String, String)>,
20    label_width: f32,
21    bordered: bool,
22}
23
24impl Default for DescriptionList {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl DescriptionList {
31    pub fn new() -> Self {
32        Self {
33            rows: Vec::new(),
34            label_width: 140.0,
35            bordered: false,
36        }
37    }
38    pub fn item(mut self, term: impl Into<String>, description: impl Into<String>) -> Self {
39        self.rows.push((term.into(), description.into()));
40        self
41    }
42    pub fn label_width(mut self, w: f32) -> Self {
43        self.label_width = w;
44        self
45    }
46    /// Wrap the list in a bordered card with separators between rows.
47    pub fn bordered(mut self) -> Self {
48        self.bordered = true;
49        self
50    }
51
52    pub fn show(self, ui: &mut Ui) -> egui::Response {
53        let theme = Theme::get(ui.ctx());
54        if self.bordered {
55            Frame::new()
56                .fill(theme.colors.background)
57                .stroke(theme.border_stroke())
58                .corner_radius(theme.corner())
59                .inner_margin(Margin::symmetric(14, 10))
60                .show(ui, |ui| self.rows_ui(ui))
61                .response
62        } else {
63            ui.scope(|ui| self.rows_ui(ui)).response
64        }
65    }
66
67    fn rows_ui(&self, ui: &mut Ui) {
68        let row_count = self.rows.len();
69        for (i, (term, desc)) in self.rows.iter().enumerate() {
70            ui.horizontal(|ui| {
71                ui.allocate_ui(egui::vec2(self.label_width, 0.0), |ui| {
72                    ui.add(Label::new(term.clone()).muted().size(Size::Small));
73                });
74                ui.add(Label::new(desc.clone()));
75            });
76            if self.bordered && i + 1 < row_count {
77                ui.add_space(6.0);
78                ui.add(Separator::horizontal());
79                ui.add_space(6.0);
80            } else {
81                ui.add_space(6.0);
82            }
83        }
84    }
85}