use crate::theme::{contrast::MacBackgroundStyle, MacTheme};
use egui::{CornerRadius, Rect, Response, Sense, Stroke, StrokeKind, Ui, Vec2};
#[derive(Default)]
pub struct MacCard<'a> {
theme: Option<&'a MacTheme>,
fill: Option<egui::Color32>,
stroke: Option<Stroke>,
corner_radius: Option<f32>,
shadow: bool,
width: Option<f32>,
height: Option<f32>,
}
impl<'a> MacCard<'a> {
pub fn new() -> Self {
Self::default()
}
pub fn theme(mut self, theme: &'a MacTheme) -> Self {
self.theme = Some(theme);
self
}
pub fn fill(mut self, fill: egui::Color32) -> Self {
self.fill = Some(fill);
self
}
pub fn stroke(mut self, stroke: Stroke) -> Self {
self.stroke = Some(stroke);
self
}
pub fn corner_radius(mut self, radius: f32) -> Self {
self.corner_radius = Some(radius);
self
}
pub fn shadow(mut self, shadow: bool) -> Self {
self.shadow = shadow;
self
}
pub fn width(mut self, width: f32) -> Self {
self.width = Some(width);
self
}
pub fn height(mut self, height: f32) -> Self {
self.height = Some(height);
self
}
pub fn background_style(&self, theme: &MacTheme) -> MacBackgroundStyle {
let fill = self.fill.unwrap_or_else(|| theme.control_background());
MacBackgroundStyle::from_color(fill)
}
pub fn show<R>(
self,
ui: &mut Ui,
rect: Rect,
add_contents: impl FnOnce(&mut Ui, MacBackgroundStyle) -> R,
) -> (Response, R) {
let theme_cow = MacTheme::resolve(self.theme, ui.ctx());
let theme: &MacTheme = &theme_cow;
let metrics = theme.popover_metrics();
let rounding = self
.corner_radius
.unwrap_or_else(|| metrics.corner_radius.points());
let bg_fill = self.fill.unwrap_or_else(|| theme.control_background());
let border_stroke = self
.stroke
.unwrap_or_else(|| Stroke::new(metrics.border_width.points(), theme.separator()));
let resp = ui.interact(
rect,
ui.scope_id().with("mac_card"),
Sense::click_and_drag(),
);
let painter = ui.painter_at(rect);
if self.shadow {
let shadow_offset = metrics.border_width.points() * 2.0;
let shadow_rect = rect.translate(Vec2::new(0.0, shadow_offset));
painter.rect_filled(
shadow_rect,
CornerRadius::same((rounding + metrics.border_width.points()) as u8),
theme.drop_shadow(),
);
}
painter.rect(
rect,
CornerRadius::same(rounding as u8),
bg_fill,
border_stroke,
StrokeKind::Inside,
);
let bg_style = MacBackgroundStyle::from_color(bg_fill);
let inner_padding = metrics.inner_padding.points();
let content_rect = rect.shrink(inner_padding);
let mut child_ui = ui.new_child(
egui::UiBuilder::new()
.id_salt((resp.id, "mac_card_content"))
.max_rect(content_rect)
.layout(egui::Layout::top_down(egui::Align::Min)),
);
let ret = add_contents(&mut child_ui, bg_style);
(resp, ret)
}
pub fn show_content<R>(
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut Ui, MacBackgroundStyle) -> R,
) -> (Response, R) {
let desired_w = self.width.unwrap_or_else(|| ui.available_width());
let desired_h = self.height.unwrap_or_else(|| {
if let Some(t) = self.theme {
t.popover_metrics().compact_panel_height.points()
} else {
ui.available_height()
}
});
let (rect, _) = ui.allocate_exact_size(Vec2::new(desired_w, desired_h), Sense::hover());
self.show(ui, rect, add_contents)
}
}