#[cfg(feature = "egui21")]
use egui21 as egui;
#[cfg(feature = "egui22")]
use egui22 as egui;
#[cfg(feature = "egui23")]
use egui23 as egui;
#[cfg(feature = "egui24")]
use egui24 as egui;
#[cfg(feature = "egui25")]
use egui25 as egui;
#[cfg(feature = "egui26")]
use egui26 as egui;
#[cfg(feature = "egui27")]
use egui27 as egui;
use egui::layers::ShapeIdx;
use egui::*;
mod exui;
mod ui_wrapper;
pub use exui::*;
#[derive(Clone, Debug, Default, PartialEq)]
pub enum GridMode {
#[default]
CompactWidth,
Traditional,
}
#[must_use = "You should call .show()"]
pub struct ExGrid {
grid: Grid,
mode: GridMode,
}
impl ExGrid {
pub fn new(id_source: impl std::hash::Hash) -> Self {
Self {
grid: Grid::new(id_source),
mode: Default::default(),
}
}
#[inline]
pub fn with_row_color<F>(mut self, color_picker: F) -> Self
where
F: Send + Sync + Fn(usize, &Style) -> Option<Color32> + 'static,
{
self.grid = self.grid.with_row_color(color_picker);
self
}
#[inline]
pub fn num_columns(mut self, num_columns: usize) -> Self {
self.grid = self.grid.num_columns(num_columns);
self
}
pub fn striped(mut self, striped: bool) -> Self {
self.grid = self.grid.striped(striped);
self
}
#[inline]
pub fn min_col_width(mut self, min_col_width: f32) -> Self {
self.grid = self.grid.min_col_width(min_col_width);
self
}
#[inline]
pub fn min_row_height(mut self, min_row_height: f32) -> Self {
self.grid = self.grid.min_row_height(min_row_height);
self
}
#[inline]
pub fn max_col_width(mut self, max_col_width: f32) -> Self {
self.grid = self.grid.max_col_width(max_col_width);
self
}
#[inline]
pub fn spacing(mut self, spacing: impl Into<Vec2>) -> Self {
self.grid = self.grid.spacing(spacing);
self
}
#[inline]
pub fn start_row(mut self, start_row: usize) -> Self {
self.grid = self.grid.start_row(start_row);
self
}
}
impl ExGrid {
#[inline]
pub fn mode(mut self, mode: GridMode) -> Self {
self.mode = mode;
self
}
}
impl ExGrid {
pub fn show<R>(
self,
ui: &mut Ui,
add_contents: impl FnOnce(&mut ExUi) -> R,
) -> InnerResponse<R> {
if self.mode == GridMode::Traditional {
let add_contents = |ui: &mut Ui| {
let id = ui.id();
let mut ex = ui.into();
let ret = add_contents(&mut ex);
ex.data_mut(|d| d.insert_temp(id, ex.1.width_max));
ret
};
self.grid.show(ui, add_contents)
} else {
let add_contents = |ui: &mut Ui| {
let id = ui.id();
let mut ex: ExUi<'_, '_> = ui.into();
ex.1.mode = ExUiMode::Compact {
ui_row: vec![FrameRun::begin(Frame::group(ex.0.style()), 0, &mut ex.0)],
ui_columns: None,
};
let ret = add_contents(&mut ex);
if ex.1.column != 0 {
ex.end_row()
}
ex.data_mut(|d| d.insert_temp(id, ex.min_rect().width()));
ret
};
self.grid.num_columns(1).show(ui, add_contents)
}
}
}
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub trait ExWidget {
fn ui_ex(self, ex_ui: &mut ExUi) -> Response;
}
impl<T: Widget> ExWidget for T {
fn ui_ex(self, ex: &mut ExUi) -> Response {
ex.add(self)
}
}
#[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub trait ExWidgetConvinence {
fn ui(self, ex_ui: &mut ExUi) -> Response;
}
impl<T: ExWidget> ExWidgetConvinence for T {
fn ui(self, ex: &mut ExUi) -> Response {
self.ui_ex(ex)
}
}
pub(crate) struct FrameRun {
empty: bool,
pub frame: Frame,
where_to_put_background: ShapeIdx,
indent: usize,
pub content_ui: Ui,
pub parrent_width: f32,
}
impl FrameRun {
pub fn begin(frame: Frame, indent: usize, ui: &mut Ui) -> FrameRun {
let where_to_put_background = ui.painter().add(Shape::Noop);
let outer_rect_bounds = ui.available_rect_before_wrap();
let mut inner_rect =
(frame.inner_margin + frame.outer_margin).shrink_rect(outer_rect_bounds);
if indent > 1 {
inner_rect.min.x += ui.style().spacing.indent;
}
inner_rect.max.x = inner_rect.max.x.max(inner_rect.min.x);
inner_rect.max.y = inner_rect.max.y.max(inner_rect.min.y);
let content_ui = ui.child_ui(inner_rect, Layout::top_down_justified(Align::LEFT));
FrameRun {
empty: true,
frame,
where_to_put_background,
indent,
content_ui,
parrent_width: ui.min_rect().max.y,
}
}
fn paint_rect(&self) -> Rect {
let mut rect = self.content_ui.min_rect();
rect.max.x = rect.max.x.max(self.parrent_width);
self.frame.inner_margin.expand_rect(rect)
}
fn content_with_margin(&self) -> Rect {
(self.frame.total_margin() + egui::Margin::same(self.frame.stroke.width))
.expand_rect(self.content_ui.min_rect())
}
pub fn end(&mut self, max_x: f32, advance_before: Rect) {
let width_from_previous = max_x
- ((self.indent.wrapping_sub(1)) as f32
* (self.frame.total_margin().right + self.frame.stroke.width));
self.content_ui.advance_cursor_after_rect(advance_before);
self.content_ui
.expand_to_include_rect(self.content_ui.min_rect().with_max_x(width_from_previous));
if !self.empty {
let paint_rect = self.paint_rect();
let FrameRun {
frame,
where_to_put_background,
..
} = self;
if self.content_ui.is_rect_visible(paint_rect) {
let shape = frame.paint(paint_rect);
self.content_ui
.painter()
.set(*where_to_put_background, shape);
}
self.content_ui
.advance_cursor_after_rect(self.content_with_margin());
}
}
pub fn ui(&mut self) -> &mut Ui {
self.empty = false;
&mut self.content_ui
}
}