#[derive(Clone, Debug)]
pub struct FlexBox {
reverse: bool,
vertical: bool,
size_i: usize,
pos_i: usize,
size2_i: usize,
pos2_i: usize,
grows: usize,
shrinks: usize,
}
#[derive(Clone, Debug)]
pub struct FlexItem {
width: usize,
height: usize,
direction: Direction,
children: Vec<Box<FlexItem>>,
frame: Vec<usize>,
grow: usize,
shrink: usize,
align_self: Align,
align_items: Align,
basis: usize,
justify_content: Align,
}
#[derive(Clone, Debug)]
pub enum Direction {
Row,
RowReverse,
Column,
ColumnReverse,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Align {
Auto,
Center,
FlexStart,
FlexEnd,
Stretch,
Between,
Around,
}
impl FlexBox {
pub fn new() -> FlexBox {
FlexBox {
reverse: false,
vertical: false,
grows: 0,
shrinks: 0,
pos_i: 0,
size_i: 0,
size2_i: 0,
pos2_i: 0,
}
}
pub fn layout(&mut self, item: &mut FlexItem) {
let mut flex_dim = 0;
let mut align_dim = 0;
let mut size = 0;
match &item.direction {
Direction::Row => {
flex_dim = item.width;
align_dim = item.height;
self.pos_i = 0;
self.pos2_i = 1;
self.size_i = 2;
self.size2_i = 3;
}
Direction::RowReverse => {
self.reverse = true;
}
Direction::Column => {
flex_dim = item.height;
align_dim = item.width;
self.pos_i = 1;
self.pos2_i = 0;
self.size_i = 3;
self.size2_i = 2;
}
Direction::ColumnReverse => self.reverse = false,
}
let mut pos = if self.reverse { flex_dim } else { 0 };
for child in item.children.iter_mut() {
child.frame[0] = 0;
child.frame[1] = 0;
child.frame[2] = child.width;
child.frame[3] = child.height;
flex_dim -= child.frame[self.size_i];
self.grows += child.grow;
self.shrinks += child.shrink;
if child.basis > 0 {
child.frame[self.size_i] = child.basis;
}
}
for child in item.children.iter_mut() {
if flex_dim > 0 {
if child.grow != 0 {
size = (flex_dim / (self.grows as usize)) * child.grow as usize;
}
} else {
if child.shrink != 0 {
size = (flex_dim / (self.shrinks as usize)) * (child.shrink as usize);
}
}
child.frame[self.size_i] += size;
let mut spacing = 0;
match child.justify_content {
Align::FlexEnd => {
pos = flex_dim;
}
Align::Center => {
pos = flex_dim / 2;
}
Align::Between => {
if child.children.len() > 0 {
spacing = flex_dim / (child.children.len() - 1);
}
}
Align::Around => {
if child.children.len() > 0 {
spacing = flex_dim / child.children.len();
pos = spacing / 2;
}
}
_ => {}
}
let a_pos = child.frame[self.size_i] + spacing;
if self.reverse {
pos -= a_pos;
child.frame[self.pos_i] = pos;
} else {
child.frame[self.pos_i] = pos;
pos += a_pos;
}
let mut align = 0;
let mut align_type = &child.align_self;
if align_type == &Align::Auto {
align_type = &child.align_items;
}
match align_type {
Align::Auto => {}
Align::FlexStart => {}
Align::Center => {
align = (align_dim / 2) - (child.frame[self.size2_i] / 2);
}
Align::FlexEnd => {
align = align_dim - child.frame[self.size2_i];
}
Align::Stretch => {
align = 0;
child.frame[self.size2_i] = align_dim;
}
_ => {}
}
child.frame[self.pos2_i] = align;
}
}
pub fn flex_layout(&mut self, root: &mut FlexItem) {
self.layout(root)
}
}
impl FlexItem {
pub fn add(&mut self, child: FlexItem) {
self.children.push(Box::new(child))
}
pub fn delete(&mut self, index: usize) {
self.children.remove(index);
()
}
pub fn new(width: usize, height: usize) -> FlexItem {
FlexItem {
width,
height,
direction: Direction::Row,
children: vec![],
frame: vec![0, 0, 0, 0],
grow: 0,
shrink: 0,
basis: 0,
align_self: Align::Auto,
align_items: Align::Auto,
justify_content: Align::Auto,
}
}
pub fn default() -> FlexItem {
FlexItem {
width: 0,
height: 0,
direction: Direction::Row,
children: vec![],
frame: vec![0, 0, 0, 0],
grow: 0,
shrink: 0,
basis: 0,
align_self: Align::Auto,
align_items: Align::Auto,
justify_content: Align::Auto,
}
}
pub fn set_width(&mut self, width: usize) {
self.width = width;
}
pub fn set_height(&mut self, height: usize) {
self.height = height;
}
pub fn set_grow(&mut self, grow: usize) {
self.grow = grow;
}
pub fn set_direction(&mut self, direction: Direction) {
self.direction = direction;
}
pub fn set_align_self(&mut self, align: &str) {
let align_type = match align {
"center" => Align::Center,
"flex-start" => Align::FlexStart,
"flex-end" => Align::FlexEnd,
"stretch" => Align::Stretch,
_ => Align::Auto,
};
self.align_self = align_type
}
pub fn set_align_items(&mut self, align: &str) {
let align_type = match align {
"center" => Align::Center,
"flex-start" => Align::FlexStart,
"flex-end" => Align::FlexEnd,
"stretch" => Align::Stretch,
_ => Align::Auto,
};
self.align_items = align_type
}
}