use crate::{grid, vec2, Layout, Painter, Pos2, Rect, Region, Vec2};
#[cfg(debug_assertions)]
use crate::{Align2, Color32, Stroke};
pub(crate) struct Placer {
grid: Option<grid::GridLayout>,
layout: Layout,
region: Region,
}
impl Placer {
pub(crate) fn new(max_rect: Rect, layout: Layout) -> Self {
let region = layout.region_from_max_rect(max_rect);
Self {
grid: None,
layout,
region,
}
}
#[inline(always)]
pub(crate) fn set_grid(&mut self, grid: grid::GridLayout) {
self.grid = Some(grid);
}
pub(crate) fn save_grid(&mut self) {
if let Some(grid) = &mut self.grid {
grid.save();
}
}
#[inline(always)]
pub(crate) fn grid(&self) -> Option<&grid::GridLayout> {
self.grid.as_ref()
}
#[inline(always)]
pub(crate) fn is_grid(&self) -> bool {
self.grid.is_some()
}
#[inline(always)]
pub(crate) fn layout(&self) -> &Layout {
&self.layout
}
#[inline(always)]
pub(crate) fn prefer_right_to_left(&self) -> bool {
self.layout.prefer_right_to_left()
}
#[inline(always)]
pub(crate) fn min_rect(&self) -> Rect {
self.region.min_rect
}
#[inline(always)]
pub(crate) fn max_rect(&self) -> Rect {
self.region.max_rect
}
#[inline(always)]
pub(crate) fn force_set_min_rect(&mut self, min_rect: Rect) {
self.region.min_rect = min_rect;
}
#[inline(always)]
pub(crate) fn cursor(&self) -> Rect {
self.region.cursor
}
#[inline(always)]
pub(crate) fn set_cursor(&mut self, cursor: Rect) {
self.region.cursor = cursor;
}
}
impl Placer {
pub(crate) fn align_size_within_rect(&self, size: Vec2, outer: Rect) -> Rect {
if let Some(grid) = &self.grid {
grid.align_size_within_rect(size, outer)
} else {
self.layout.align_size_within_rect(size, outer)
}
}
pub(crate) fn available_rect_before_wrap(&self) -> Rect {
if let Some(grid) = &self.grid {
grid.available_rect(&self.region)
} else {
self.layout.available_rect_before_wrap(&self.region)
}
}
pub(crate) fn available_size(&self) -> Vec2 {
if let Some(grid) = &self.grid {
grid.available_rect(&self.region).size()
} else {
self.layout.available_size(&self.region)
}
}
pub(crate) fn next_space(&self, child_size: Vec2, item_spacing: Vec2) -> Rect {
debug_assert!(
0.0 <= child_size.x && 0.0 <= child_size.y,
"Negative child size: {child_size:?}"
);
self.region.sanity_check();
if let Some(grid) = &self.grid {
grid.next_cell(self.region.cursor, child_size)
} else {
self.layout
.next_frame(&self.region, child_size, item_spacing)
}
}
pub(crate) fn next_widget_position(&self) -> Pos2 {
if let Some(grid) = &self.grid {
grid.next_cell(self.region.cursor, Vec2::ZERO).center()
} else {
self.layout.next_widget_position(&self.region)
}
}
pub(crate) fn justify_and_align(&self, rect: Rect, child_size: Vec2) -> Rect {
debug_assert!(!rect.any_nan());
debug_assert!(!child_size.any_nan());
if let Some(grid) = &self.grid {
grid.justify_and_align(rect, child_size)
} else {
self.layout.justify_and_align(rect, child_size)
}
}
pub(crate) fn advance_cursor(&mut self, amount: f32) {
debug_assert!(
self.grid.is_none(),
"You cannot advance the cursor when in a grid layout"
);
self.layout.advance_cursor(&mut self.region, amount);
}
pub(crate) fn advance_after_rects(
&mut self,
frame_rect: Rect,
widget_rect: Rect,
item_spacing: Vec2,
) {
debug_assert!(!frame_rect.any_nan());
debug_assert!(!widget_rect.any_nan());
self.region.sanity_check();
if let Some(grid) = &mut self.grid {
grid.advance(&mut self.region.cursor, frame_rect, widget_rect);
} else {
self.layout.advance_after_rects(
&mut self.region.cursor,
frame_rect,
widget_rect,
item_spacing,
);
}
self.expand_to_include_rect(frame_rect); self.region.sanity_check();
}
pub(crate) fn end_row(&mut self, item_spacing: Vec2, painter: &Painter) {
if let Some(grid) = &mut self.grid {
grid.end_row(&mut self.region.cursor, painter);
} else {
self.layout.end_row(&mut self.region, item_spacing);
}
}
pub(crate) fn set_row_height(&mut self, height: f32) {
self.layout.set_row_height(&mut self.region, height);
}
}
impl Placer {
pub(crate) fn expand_to_include_rect(&mut self, rect: Rect) {
self.region.expand_to_include_rect(rect);
}
pub(crate) fn expand_to_include_x(&mut self, x: f32) {
self.region.expand_to_include_x(x);
}
pub(crate) fn expand_to_include_y(&mut self, y: f32) {
self.region.expand_to_include_y(y);
}
fn next_widget_space_ignore_wrap_justify(&self, size: Vec2) -> Rect {
self.layout
.next_widget_space_ignore_wrap_justify(&self.region, size)
}
pub(crate) fn set_max_width(&mut self, width: f32) {
let rect = self.next_widget_space_ignore_wrap_justify(vec2(width, 0.0));
let region = &mut self.region;
region.max_rect.min.x = rect.min.x;
region.max_rect.max.x = rect.max.x;
region.max_rect = region.max_rect.union(region.min_rect); region.cursor.min.x = region.max_rect.min.x;
region.cursor.max.x = region.max_rect.max.x;
region.sanity_check();
}
pub(crate) fn set_max_height(&mut self, height: f32) {
let rect = self.next_widget_space_ignore_wrap_justify(vec2(0.0, height));
let region = &mut self.region;
region.max_rect.min.y = rect.min.y;
region.max_rect.max.y = rect.max.y;
region.max_rect = region.max_rect.union(region.min_rect); region.cursor.min.y = region.max_rect.min.y;
region.cursor.max.y = region.max_rect.max.y;
region.sanity_check();
}
pub(crate) fn set_min_width(&mut self, width: f32) {
if width <= 0.0 {
return;
}
let rect = self.next_widget_space_ignore_wrap_justify(vec2(width, 0.0));
self.region.expand_to_include_x(rect.min.x);
self.region.expand_to_include_x(rect.max.x);
}
pub(crate) fn set_min_height(&mut self, height: f32) {
if height <= 0.0 {
return;
}
let rect = self.next_widget_space_ignore_wrap_justify(vec2(0.0, height));
self.region.expand_to_include_y(rect.min.y);
self.region.expand_to_include_y(rect.max.y);
}
}
impl Placer {
#[cfg(debug_assertions)]
pub(crate) fn debug_paint_cursor(&self, painter: &crate::Painter, text: impl ToString) {
let stroke = Stroke::new(1.0, Color32::DEBUG_COLOR);
if let Some(grid) = &self.grid {
let rect = grid.next_cell(self.cursor(), Vec2::splat(0.0));
painter.rect_stroke(rect, 1.0, stroke);
let align = Align2::CENTER_CENTER;
painter.debug_text(align.pos_in_rect(&rect), align, stroke.color, text);
} else {
self.layout
.paint_text_at_cursor(painter, &self.region, stroke, text);
}
}
}