use egui::{Color32, Frame, InnerResponse, Margin, Stroke, Ui};
use egui_components_theme::Theme;
use crate::common::Size;
use crate::label::Label;
use crate::separator::Separator;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum CardVariant {
#[default]
Fill,
Outline,
Normal,
}
pub struct Card {
title: Option<String>,
description: Option<String>,
padding: f32,
divider: bool,
variant: CardVariant,
}
impl Default for Card {
fn default() -> Self {
Self::new()
}
}
impl Card {
pub fn new() -> Self {
Self {
title: None,
description: None,
padding: 16.0,
divider: false,
variant: CardVariant::default(),
}
}
pub fn title(mut self, t: impl Into<String>) -> Self {
self.title = Some(t.into());
self
}
pub fn description(mut self, d: impl Into<String>) -> Self {
self.description = Some(d.into());
self
}
pub fn padding(mut self, p: f32) -> Self {
self.padding = p;
self
}
pub fn divider(mut self) -> Self {
self.divider = true;
self
}
pub fn variant(mut self, v: CardVariant) -> Self {
self.variant = v;
self
}
pub fn fill(self) -> Self {
self.variant(CardVariant::Fill)
}
pub fn outline(self) -> Self {
self.variant(CardVariant::Outline)
}
pub fn normal(self) -> Self {
self.variant(CardVariant::Normal)
}
pub fn show<R>(self, ui: &mut Ui, body: impl FnOnce(&mut Ui) -> R) -> InnerResponse<R> {
let theme = Theme::get(ui.ctx());
let c = theme.colors;
let (fill, stroke) = match self.variant {
CardVariant::Fill => (c.muted_background, Stroke::NONE),
CardVariant::Outline => (Color32::TRANSPARENT, theme.border_stroke()),
CardVariant::Normal => (Color32::TRANSPARENT, Stroke::NONE),
};
Frame::new()
.fill(fill)
.stroke(stroke)
.corner_radius(theme.corner_lg())
.inner_margin(Margin::same(self.padding as i8))
.show(ui, |ui| {
let has_header = self.title.is_some() || self.description.is_some();
if let Some(title) = self.title {
ui.add(Label::new(title).strong().size(Size::Large));
}
if let Some(desc) = self.description {
ui.add(Label::new(desc).muted().size(Size::Small));
}
if has_header {
if self.divider {
ui.add_space(self.padding * 0.5);
ui.add(Separator::horizontal());
}
ui.add_space(self.padding * 0.75);
}
body(ui)
})
}
}