mod button_content;
mod content;
mod label_content;
mod property_content;
mod visuals;
pub use button_content::{ButtonContent, ButtonStyle};
pub use content::{ContentContext, ListItem, ListItemContent};
pub use label_content::LabelContent;
pub use property_content::PropertyContent;
pub use visuals::ListVisuals;
use egui::{Color32, Response, Ui, Vec2};
use crate::tokens::DESIGN_TOKENS;
fn default_height() -> f32 {
DESIGN_TOKENS.sizing.list_item_height
}
impl ListItem {
pub fn show<C: ListItemContent>(self, ui: &mut Ui, content: C) -> Response {
let height = self.height.unwrap_or_else(default_height);
let width = ui.available_width();
let (rect, mut response) = ui.allocate_exact_size(
Vec2::new(width, height),
if self.interactive {
egui::Sense::click()
} else {
egui::Sense::hover()
},
);
if ui.is_rect_visible(rect) {
let egui_visuals = ui.style().visuals.clone();
let list_visuals = ListVisuals::new()
.with_hovered(response.hovered())
.with_selected(self.selected)
.with_interactive(self.interactive);
let bg_color = list_visuals
.bg_color(&egui_visuals)
.unwrap_or(Color32::TRANSPARENT);
if bg_color != Color32::TRANSPARENT {
ui.painter()
.rect_filled(rect, DESIGN_TOKENS.rounding.sm, bg_color);
}
let content_context = ContentContext {
rect: rect.shrink2(Vec2::new(DESIGN_TOKENS.spacing.sm, 0.0)),
bg_color,
selected: self.selected,
hovered: response.hovered(),
list_item: &self,
response: &response,
visuals: list_visuals,
};
let _content_response = content.ui(ui, &content_context);
if self.show_separator {
let sep_y = rect.bottom();
let sep_color = egui_visuals.widgets.noninteractive.bg_stroke.color;
ui.painter().hline(
rect.x_range(),
sep_y,
egui::Stroke::new(DESIGN_TOKENS.stroke.hairline, sep_color),
);
}
}
if response.clicked() && self.interactive {
response.mark_changed();
}
response
}
pub fn show_text(self, ui: &mut Ui, text: impl Into<String>) -> Response {
self.show(ui, LabelContent::new(text))
}
pub fn show_with_icon(
self,
ui: &mut Ui,
text: impl Into<String>,
icon: &crate::icons::Icon,
) -> Response {
self.show(ui, LabelContent::new(text).with_icon(icon))
}
pub fn show_property(
self,
ui: &mut Ui,
label: impl Into<String>,
value: impl Into<String>,
) -> Response {
self.show(ui, PropertyContent::new(label, value))
}
}
pub fn simple_list<T, F>(ui: &mut Ui, items: &[T], selected: &mut Option<usize>, mut show_item: F)
where
F: FnMut(&mut Ui, &T, bool) -> Response,
{
for (idx, item) in items.iter().enumerate() {
let is_selected = *selected == Some(idx);
let response = show_item(ui, item, is_selected);
if response.clicked() {
*selected = Some(idx);
}
}
}