zeus_widgets/
multi_label.rs1use super::Label;
2use egui::{Pos2, Rect, Response, Sense, StrokeKind, Ui, Vec2, Widget, epaint::RectShape};
3
4#[must_use = "You should put this widget in a ui with `ui.add(widget);`"]
7#[derive(Clone)]
8pub struct MultiLabel {
9 labels: Vec<Label>,
10 inter_spacing: f32,
11 sense: Option<Sense>,
12}
13
14impl MultiLabel {
15 pub fn new(labels: Vec<Label>) -> Self {
18 Self {
19 labels,
20 inter_spacing: 6.0,
21 sense: None,
22 }
23 }
24
25 pub fn inter_spacing(mut self, spacing: f32) -> Self {
27 self.inter_spacing = spacing;
28 self
29 }
30
31 pub fn sense(mut self, sense: Sense) -> Self {
34 self.sense = Some(sense);
35 self
36 }
37}
38
39impl Widget for MultiLabel {
40 fn ui(self, ui: &mut Ui) -> Response {
41 if self.labels.is_empty() {
42 return ui.allocate_response(Vec2::ZERO, Sense::empty());
43 }
44
45 let mut total_width = 0.0;
47 let mut max_height: f32 = 0.0;
48 let mut label_sizes: Vec<Vec2> = Vec::with_capacity(self.labels.len());
49
50 for label in &self.labels {
51 let (_, size) = label.galley_and_size(ui, f32::INFINITY);
52 label_sizes.push(size);
53 total_width += size.x;
54 max_height = max_height.max(size.y);
55 }
56
57 let num_gaps = (self.labels.len() as f32).max(0.0) - 1.0;
58 total_width += self.inter_spacing * num_gaps;
59 let desired_size = Vec2::new(total_width, max_height);
60
61 let sense = self.sense.unwrap_or(Sense::empty());
63 let (rect, response) = ui.allocate_exact_size(desired_size, sense);
64
65 if ui.is_rect_visible(rect) {
67 let visuals = if self.sense.is_some() {
68 ui.style().interact(&response).clone()
69 } else {
70 ui.style().noninteractive().clone()
71 };
72
73 let is_interactive = self.sense.is_some();
75 if is_interactive
76 && (response.hovered() || response.is_pointer_button_down_on() || response.has_focus())
77 {
78 let background_rect = rect.expand(visuals.expansion);
79 ui.painter().add(RectShape::new(
80 background_rect,
81 visuals.corner_radius,
82 visuals.weak_bg_fill,
83 visuals.bg_stroke,
84 StrokeKind::Inside,
85 ));
86 }
87
88 let mut x = rect.left();
90 let mut i = 0;
91
92 for label in self.labels {
93 if i > 0 {
94 x += self.inter_spacing;
95 }
96
97 let label_size = label_sizes[i];
98 let y_offset = (max_height - label_size.y) * 0.5;
99 let label_rect = Rect::from_min_size(Pos2::new(x, rect.top() + y_offset), label_size);
100
101 label.paint_content_within_rect(ui, label_rect, &visuals);
102
103 x += label_size.x;
104 i += 1;
105 }
106 }
107 response
108 }
109}