use thunderdome::Index as TdIndex;
use crate::{Alignment, NodeCache, Rect, UiNode, UiTree};
pub struct Margin {
pub left: f32,
pub right: f32,
pub top: f32,
pub bottom: f32,
align: (Alignment, Alignment),
child: Option<TdIndex>,
}
impl Margin {
pub fn new() -> Self {
Self {
left: 0.0,
right: 0.0,
top: 0.0,
bottom: 0.0,
align: (Alignment::Begin, Alignment::Begin),
child: None,
}
}
pub fn with_child(mut self, child: impl UiNode, tree: &mut UiTree) -> Self {
assert!(self.child.is_none());
self.child = Some(tree.add_node(child));
self
}
pub fn with_align(mut self, align: (Alignment, Alignment)) -> Self {
self.align = align;
self
}
pub fn with_margins(mut self, left: f32, right: f32, top: f32, bottom: f32) -> Self {
self.left = left;
self.right = right;
self.top = top;
self.bottom = bottom;
self
}
pub fn with_equal_x(mut self, lr: f32) -> Self {
self.left = lr;
self.right = lr;
self
}
pub fn with_equal_y(mut self, tb: f32) -> Self {
self.top = tb;
self.bottom = tb;
self
}
pub fn with_equal_xy(mut self, lr: f32, tb: f32) -> Self {
self.left = lr;
self.right = lr;
self.top = tb;
self.bottom = tb;
self
}
pub fn with_equal(mut self, margin: f32) -> Self {
self.left = margin;
self.right = margin;
self.top = margin;
self.bottom = margin;
self
}
pub fn with_left(mut self, left: f32) -> Self {
self.left = left;
self
}
pub fn with_right(mut self, right: f32) -> Self {
self.right = right;
self
}
pub fn with_top(mut self, top: f32) -> Self {
self.top = top;
self
}
pub fn with_bottom(mut self, bottom: f32) -> Self {
self.bottom = bottom;
self
}
}
impl Default for Margin {
fn default() -> Self {
Self::new()
}
}
impl UiNode for Margin {
fn get_align(&self) -> (Alignment, Alignment) {
self.align
}
fn get_align_mut(&mut self) -> (&mut Alignment, &mut Alignment) {
(&mut self.align.0, &mut self.align.1)
}
fn calculate_min_size(&self, tree: &UiTree) -> (f32, f32) {
let left = self.left.abs();
let right = self.right.abs();
let top = self.top.abs();
let bottom = self.bottom.abs();
if let Some(child) = self.child {
let child = tree.get_cache(child).expect("Child not in cache");
let (w, h) = child.min_size;
(w + left + right, h + top + bottom)
} else {
(left + right, top + bottom)
}
}
fn calculate_rects(&self, cache: &NodeCache, tree: &UiTree) -> Vec<Rect> {
let Some(child_idx) = self.child else {
return vec![];
};
let left = self.left.max(0.0);
let right = self.right.max(0.0);
let top = self.top.max(0.0);
let bottom = self.bottom.max(0.0);
let child_min = tree
.get_cache(child_idx)
.expect("Child not in cache")
.min_size;
let child = tree.get_node(child_idx).expect("Child not in cache");
let space = Rect::new(
cache.rect.x + left,
cache.rect.y + top,
cache.rect.w - left - right,
cache.rect.h - top - bottom,
)
.align(child.get_align(), child_min);
vec![space]
}
fn get_children(&self) -> Vec<TdIndex> {
self.child.into_iter().collect()
}
}
pub struct Minimum {
pub min_override: (f32, f32),
child: Option<TdIndex>,
align: (Alignment, Alignment),
}
impl Minimum {
pub fn new() -> Self {
Self {
min_override: (0.0, 0.0),
child: None,
align: (Alignment::Begin, Alignment::Begin),
}
}
pub fn with_child(mut self, child: impl UiNode, tree: &mut UiTree) -> Self {
assert!(self.child.is_none());
self.child = Some(tree.add_node(child));
self
}
pub fn with_align(mut self, align: (Alignment, Alignment)) -> Self {
self.align = align;
self
}
pub fn with_min(mut self, min: (f32, f32)) -> Self {
self.min_override = min;
self
}
}
impl Default for Minimum {
fn default() -> Self {
Self::new()
}
}
impl UiNode for Minimum {
fn get_align(&self) -> (Alignment, Alignment) {
self.align
}
fn get_align_mut(&mut self) -> (&mut Alignment, &mut Alignment) {
(&mut self.align.0, &mut self.align.1)
}
fn calculate_min_size(&self, tree: &UiTree) -> (f32, f32) {
if let Some(child) = self.child {
let child = tree.get_cache(child).expect("Child not in cache");
let (w, h) = child.min_size;
(w.max(self.min_override.0), h.max(self.min_override.1))
} else {
self.min_override
}
}
fn calculate_rects(&self, cache: &NodeCache, tree: &UiTree) -> Vec<Rect> {
if let Some(child) = self.child {
let child_min = tree.get_cache(child).expect("Child not in cache").min_size;
let child = tree.get_node(child).expect("Child not in cache");
let space = cache.rect.align(child.get_align(), child_min);
vec![space]
} else {
vec![]
}
}
fn get_children(&self) -> Vec<TdIndex> {
self.child.into_iter().collect()
}
}
pub struct Spacer {
size: (f32, f32),
align: (Alignment, Alignment),
}
impl Spacer {
pub fn new() -> Self {
Self {
size: (0.0, 0.0),
align: (Alignment::Begin, Alignment::Begin),
}
}
pub fn with_align(mut self, align: (Alignment, Alignment)) -> Self {
self.align = align;
self
}
pub fn with_size(mut self, size: (f32, f32)) -> Self {
assert!(size.0 >= 0.0 && size.1 >= 0.0);
self.size = size;
self
}
pub fn set_size(&mut self, size: (f32, f32)) {
assert!(size.0 >= 0.0 && size.1 >= 0.0);
self.size = size;
}
pub fn get_size(&self) -> (f32, f32) {
self.size
}
}
impl Default for Spacer {
fn default() -> Self {
Self::new()
}
}
impl UiNode for Spacer {
fn get_align(&self) -> (Alignment, Alignment) {
self.align
}
fn get_align_mut(&mut self) -> (&mut Alignment, &mut Alignment) {
(&mut self.align.0, &mut self.align.1)
}
fn calculate_min_size(&self, _tree: &UiTree) -> (f32, f32) {
self.size
}
}