use egui::{Align2, Context, InnerResponse, Order, Pos2, Vec2};
use crate::{
containers::frame::StyledFrame, impl_style_builders, style::shared_style::SharedStyle,
};
pub struct StyledArea {
id: Option<egui::Id>,
anchor: Option<(Align2, Vec2)>,
fixed_pos: Option<Pos2>,
fixed_pos_centered: Option<Pos2>,
order: Option<Order>,
interactable: bool,
movable: bool,
fill_screen: bool,
align: Option<egui::Align>,
justify: Option<egui::Align>,
style: SharedStyle,
}
impl Default for StyledArea {
fn default() -> Self {
Self::new()
}
}
impl StyledArea {
pub fn new() -> Self {
Self {
id: None,
anchor: None,
fixed_pos: None,
fixed_pos_centered: None,
order: None,
interactable: true,
movable: false,
fill_screen: false,
align: None,
justify: None,
style: SharedStyle::default(),
}
}
pub fn id(mut self, id: impl std::hash::Hash) -> Self {
self.id = Some(egui::Id::new(id));
self
}
pub fn anchor(mut self, align: Align2, offset: Vec2) -> Self {
self.anchor = Some((align, offset));
self
}
pub fn fixed_pos(mut self, pos: Pos2) -> Self {
self.fixed_pos = Some(pos);
self
}
pub fn fixed_pos_centered(mut self, pos: Pos2) -> Self {
self.fixed_pos_centered = Some(pos);
self
}
pub fn order(mut self, order: Order) -> Self {
self.order = Some(order);
self
}
pub fn interactable(mut self, interactable: bool) -> Self {
self.interactable = interactable;
self
}
pub fn movable(mut self, movable: bool) -> Self {
self.movable = movable;
self
}
pub fn fill_screen(mut self) -> Self {
self.fill_screen = true;
self
}
pub fn align(mut self, align: egui::Align) -> Self {
self.align = Some(align);
self
}
pub fn justify(mut self, justify: egui::Align) -> Self {
self.justify = Some(justify);
self
}
pub fn show<R>(self, ctx: &Context, body: impl FnOnce(&mut egui::Ui) -> R) -> InnerResponse<R> {
let id = self.id.unwrap_or_else(|| egui::Id::new("styled_area"));
let mut area = egui::Area::new(id)
.interactable(self.interactable)
.movable(self.movable);
if let Some(order) = self.order {
area = area.order(order);
}
let size_cache_id = id.with("__centered_size");
if let Some(center) = self.fixed_pos_centered {
let last_size = ctx.memory(|mem| {
mem.data
.get_temp::<Vec2>(size_cache_id)
.unwrap_or(Vec2::ZERO)
});
area = area.fixed_pos(center - last_size / 2.0);
} else if self.fill_screen {
area = area.fixed_pos(ctx.content_rect().min);
} else if let Some(pos) = self.fixed_pos {
area = area.fixed_pos(pos);
} else if let Some((align, offset)) = self.anchor {
area = area.anchor(align, offset);
}
let visible = self.style.visible;
let frame = StyledFrame {
style: self.style,
align: self.align,
justify: self.justify,
};
let fill_screen = self.fill_screen;
let screen_size = ctx.content_rect().size();
let needs_size_cache = self.fixed_pos_centered.is_some();
let response = area.show(ctx, |ui| {
if visible == Some(false) {
ui.set_invisible();
}
if fill_screen {
ui.set_min_size(screen_size);
}
frame.show(ui, body).inner
});
if needs_size_cache {
let new_size = response.response.rect.size();
ctx.memory_mut(|mem| mem.data.insert_temp(size_cache_id, new_size));
}
response
}
}
impl_style_builders!(StyledArea);