use crate::preludes::widget_creation::*;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Orientation {
Horizontal,
Vertical,
}
fn get_single_position(position: Position, orien: Orientation) -> (i16, i16) {
match orien {
Orientation::Horizontal => (position.col, position.row),
Orientation::Vertical => (position.row, position.col),
}
}
fn get_single_size(size: Size, orien: Orientation) -> (u16, u16) {
match orien {
Orientation::Horizontal => (size.cols, size.rows),
Orientation::Vertical => (size.rows, size.cols),
}
}
fn from_single_position(single: i16, opposite: i16, orien: Orientation) -> Position {
return Position {
col: match orien {
Orientation::Horizontal => single,
Orientation::Vertical => opposite,
},
row: match orien {
Orientation::Horizontal => opposite,
Orientation::Vertical => single,
},
};
}
fn from_single_size(single: u16, opposite: u16, orien: Orientation) -> Size {
return Size {
cols: match orien {
Orientation::Horizontal => single,
Orientation::Vertical => opposite,
},
rows: match orien {
Orientation::Horizontal => opposite,
Orientation::Vertical => single,
},
};
}
fn is_single_col(orien: Orientation) -> bool {
return orien == Orientation::Horizontal;
}
pub struct BoxContainer<W: Widget> {
pub orientation: Orientation,
pub widgets: Vec<W>,
widget_data: WidgetData,
}
impl<W: Widget> BoxContainer<W> {
pub fn new(orientation: Orientation, widgets: Vec<W>) -> Self {
Self {
orientation,
widgets,
widget_data: WidgetData::new(),
}
}
}
impl<W: Widget> Widget for BoxContainer<W> {
fn draw(&mut self, canvas: &mut Canvas, state_frame: Option<&EventStateFrame>) {
if canvas.is_visible() == false {
return;
}
let count = self.widgets.len();
let (mut empty_space, canvas_single_opposite) = get_single_size(canvas.transform.size, self.orientation);
let default_size: u16 = empty_space / (count as u16);
let mut canvas_vec: Vec<Canvas> = Vec::new();
let mut can_be_increased: Vec<usize> = Vec::new();
for (widget_index, widget) in self.widgets.iter().enumerate() {
let widget_info = widget.widget_info();
let mut inner = canvas.new_child(Transform::new(
Position::zero(),
from_single_size(default_size, canvas_single_opposite, self.orientation),
));
inner.transform.size = widget_info.size_info.correct_size(inner.transform.size);
empty_space = empty_space.saturating_sub(get_single_size(inner.transform.size, self.orientation).0);
for change_potential in widget_info.size_info.can_change_size(inner.transform.size) {
if let WidgetSizeInfoCanChange::CanGrow { cols, rows } = change_potential {
let check = match is_single_col(self.orientation) {
true => cols,
false => rows,
};
if check {
can_be_increased.push(widget_index);
break;
}
}
}
canvas_vec.push(inner);
}
let mut prev_empty: Option<u16> = None;
loop {
if empty_space > 0 {
let mut to_be_removed: Vec<usize> = Vec::new();
let increase = empty_space / can_be_increased.len() as u16;
for (cbi, widget_index) in can_be_increased.iter().enumerate() {
let widget_index = *widget_index;
let widget_info = self.widgets[widget_index].widget_info();
let inner = &mut canvas_vec[widget_index];
let (mut single, opposite) = get_single_size(inner.transform.size, self.orientation);
let original_single = single;
single += increase;
inner.transform.size = from_single_size(single, opposite, self.orientation);
inner.transform.size = self.widgets[widget_index]
.widget_info()
.size_info
.correct_size(inner.transform.size);
let single = get_single_size(inner.transform.size, self.orientation).0;
let mut increased_by = single - original_single;
if empty_space.overflowing_sub(increased_by).1 {
let increased_by_original = increased_by;
increased_by = empty_space;
let diff = increased_by_original - increased_by;
let (mut s, o) = get_single_size(inner.transform.size, self.orientation);
s -= diff;
let corrected_size = from_single_size(s, o, self.orientation);
inner.transform.size = corrected_size;
}
empty_space = empty_space.saturating_sub(increased_by);
for change_potential in widget_info.size_info.can_change_size(inner.transform.size) {
if let WidgetSizeInfoCanChange::CanGrow { cols, rows } = change_potential {
let check = match is_single_col(self.orientation) {
true => cols,
false => rows,
};
if check == false {
to_be_removed.push(cbi);
break;
}
}
}
if empty_space == 0 {
break;
}
}
for tbr in to_be_removed {
can_be_increased.remove(tbr);
}
}
if let Some(prev_empty) = prev_empty {
if empty_space == prev_empty {
break;
}
}
prev_empty = Some(empty_space);
}
if empty_space > 0 {
let canvas_vec_len = canvas_vec.len(); let inner = &mut canvas_vec[canvas_vec_len - 1];
let (mut single, opposite) = get_single_size(inner.transform.size, self.orientation);
single += empty_space;
inner.transform.size = from_single_size(single, opposite, self.orientation);
}
let mut offset: i16 = 0;
for inner in canvas_vec.iter_mut() {
let single_size = get_single_size(inner.transform.size, self.orientation).0;
let opposite_position = get_single_position(inner.transform.position, self.orientation).1;
inner.transform.position = from_single_position(offset, opposite_position, self.orientation);
offset += single_size as i16;
}
for i in 0..self.widgets.len() {
self.widgets[i].draw(&mut canvas_vec[i], state_frame);
}
}
fn widget_info(&self) -> WidgetInfo {
let mut size_min: Option<Size> = None;
for widget in self.widgets.iter() {
let sm = size_min.unwrap_or(Size::new(0, 0));
match widget.widget_info().size_info {
WidgetSizeInfo::Fixed(fixed_size) => {
size_min = Some(sm + fixed_size);
},
WidgetSizeInfo::Dynamic { min, max: _ } => {
size_min = Some(sm + min.unwrap_or(Size::new(0, 0)));
},
};
}
return WidgetInfo {
size_info: WidgetSizeInfo::Dynamic {
min: size_min,
max: None,
},
};
}
fn widget_data(&mut self) -> &mut WidgetData {
return &mut self.widget_data;
}
}