use super::Label;
use egui::{Pos2, Rect, Response, Sense, StrokeKind, Ui, Vec2, Widget, epaint::RectShape};
#[must_use = "You should put this widget in a ui with `ui.add(widget);`"]
#[derive(Clone)]
pub struct MultiLabel {
labels: Vec<Label>,
inter_spacing: f32,
sense: Option<Sense>,
}
impl MultiLabel {
pub fn new(labels: Vec<Label>) -> Self {
Self {
labels,
inter_spacing: 6.0,
sense: None,
}
}
pub fn inter_spacing(mut self, spacing: f32) -> Self {
self.inter_spacing = spacing;
self
}
pub fn sense(mut self, sense: Sense) -> Self {
self.sense = Some(sense);
self
}
}
impl Widget for MultiLabel {
fn ui(self, ui: &mut Ui) -> Response {
if self.labels.is_empty() {
return ui.allocate_response(Vec2::ZERO, Sense::empty());
}
let mut total_width = 0.0;
let mut max_height: f32 = 0.0;
let mut label_sizes: Vec<Vec2> = Vec::with_capacity(self.labels.len());
for label in &self.labels {
let (_, size) = label.galley_and_size(ui, f32::INFINITY);
label_sizes.push(size);
total_width += size.x;
max_height = max_height.max(size.y);
}
let num_gaps = (self.labels.len() as f32).max(0.0) - 1.0;
total_width += self.inter_spacing * num_gaps;
let desired_size = Vec2::new(total_width, max_height);
let sense = self.sense.unwrap_or(Sense::empty());
let (rect, response) = ui.allocate_exact_size(desired_size, sense);
if ui.is_rect_visible(rect) {
let visuals = if self.sense.is_some() {
ui.style().interact(&response).clone()
} else {
ui.style().noninteractive().clone()
};
let is_interactive = self.sense.is_some();
if is_interactive
&& (response.hovered() || response.is_pointer_button_down_on() || response.has_focus())
{
let background_rect = rect.expand(visuals.expansion);
ui.painter().add(RectShape::new(
background_rect,
visuals.corner_radius,
visuals.weak_bg_fill,
visuals.bg_stroke,
StrokeKind::Inside,
));
}
let mut x = rect.left();
let mut i = 0;
for label in self.labels {
if i > 0 {
x += self.inter_spacing;
}
let label_size = label_sizes[i];
let y_offset = (max_height - label_size.y) * 0.5;
let label_rect = Rect::from_min_size(Pos2::new(x, rect.top() + y_offset), label_size);
label.paint_content_within_rect(ui, label_rect, &visuals);
x += label_size.x;
i += 1;
}
}
response
}
}