use crate::{
Size,
layout::{CellDirection, CellSize, StripLayout, StripLayoutFlags},
sizing::Sizing,
};
use egui::{Response, Ui};
pub struct StripBuilder<'a> {
ui: &'a mut Ui,
sizing: Sizing,
clip: bool,
cell_layout: egui::Layout,
sense: egui::Sense,
}
impl<'a> StripBuilder<'a> {
pub fn new(ui: &'a mut Ui) -> Self {
let cell_layout = *ui.layout();
Self {
ui,
sizing: Default::default(),
clip: false,
cell_layout,
sense: egui::Sense::hover(),
}
}
#[inline]
pub fn clip(mut self, clip: bool) -> Self {
self.clip = clip;
self
}
#[inline]
pub fn cell_layout(mut self, cell_layout: egui::Layout) -> Self {
self.cell_layout = cell_layout;
self
}
#[inline]
pub fn sense(mut self, sense: egui::Sense) -> Self {
self.sense = sense;
self
}
#[inline]
pub fn size(mut self, size: Size) -> Self {
self.sizing.add(size);
self
}
#[inline]
pub fn sizes(mut self, size: Size, count: usize) -> Self {
for _ in 0..count {
self.sizing.add(size);
}
self
}
pub fn horizontal<F>(self, strip: F) -> Response
where
F: for<'b> FnOnce(Strip<'a, 'b>),
{
let widths = self.sizing.to_lengths(
self.ui.available_rect_before_wrap().width(),
self.ui.spacing().item_spacing.x,
);
let mut layout = StripLayout::new(
self.ui,
CellDirection::Horizontal,
self.cell_layout,
self.sense,
);
strip(Strip {
layout: &mut layout,
direction: CellDirection::Horizontal,
clip: self.clip,
sizes: widths,
size_index: 0,
});
layout.allocate_rect()
}
pub fn vertical<F>(self, strip: F) -> Response
where
F: for<'b> FnOnce(Strip<'a, 'b>),
{
let heights = self.sizing.to_lengths(
self.ui.available_rect_before_wrap().height(),
self.ui.spacing().item_spacing.y,
);
let mut layout = StripLayout::new(
self.ui,
CellDirection::Vertical,
self.cell_layout,
self.sense,
);
strip(Strip {
layout: &mut layout,
direction: CellDirection::Vertical,
clip: self.clip,
sizes: heights,
size_index: 0,
});
layout.allocate_rect()
}
}
pub struct Strip<'a, 'b> {
layout: &'b mut StripLayout<'a>,
direction: CellDirection,
clip: bool,
sizes: Vec<f32>,
size_index: usize,
}
impl Strip<'_, '_> {
#[cfg_attr(debug_assertions, track_caller)]
fn next_cell_size(&mut self) -> (CellSize, CellSize) {
let size = if let Some(size) = self.sizes.get(self.size_index) {
self.size_index += 1;
*size
} else {
crate::log_or_panic!(
"Added more `Strip` cells than were pre-allocated ({} pre-allocated)",
self.sizes.len()
);
8.0 };
match self.direction {
CellDirection::Horizontal => (CellSize::Absolute(size), CellSize::Remainder),
CellDirection::Vertical => (CellSize::Remainder, CellSize::Absolute(size)),
}
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn cell(&mut self, add_contents: impl FnOnce(&mut Ui)) {
let (width, height) = self.next_cell_size();
let flags = StripLayoutFlags {
clip: self.clip,
..Default::default()
};
self.layout.add(
flags,
width,
height,
egui::Id::new(self.size_index),
add_contents,
);
}
#[cfg_attr(debug_assertions, track_caller)]
pub fn empty(&mut self) {
let (width, height) = self.next_cell_size();
self.layout.empty(width, height);
}
pub fn strip(&mut self, strip_builder: impl FnOnce(StripBuilder<'_>)) {
let clip = self.clip;
self.cell(|ui| {
strip_builder(StripBuilder::new(ui).clip(clip));
});
}
}
impl Drop for Strip<'_, '_> {
fn drop(&mut self) {
while self.size_index < self.sizes.len() {
self.empty();
}
}
}