#![warn(
missing_docs,
future_incompatible,
rust_2018_idioms,
let_underscore,
clippy::missing_docs_in_private_items
)]
mod layout;
#[allow(missing_docs, clippy::missing_docs_in_private_items)]
pub mod prelude;
use std::{
cell::RefCell,
fmt::Display,
rc::{Rc, Weak},
};
use cursive_core::{event::EventResult, view::IntoBoxedView, Rect, Vec2, View, XY};
use layout::{Layout, PlacedElement};
#[derive(Default)]
pub struct Flexbox {
content: Vec<Rc<RefCell<FlexItem>>>,
options: FlexBoxOptions,
focused: Option<usize>,
layout: Option<Layout<Rc<RefCell<FlexItem>>>>,
}
pub struct FlexItem {
view: Box<dyn View>,
flex_grow: u8,
}
#[derive(Default, Clone, Copy)]
struct FlexBoxOptions {
direction: FlexDirection,
justification: JustifyContent,
item_alignment: AlignItems,
axes_alignment: AlignContent,
main_axis_gap: u32,
cross_axis_gap: u32,
wrap: FlexWrap,
}
#[non_exhaustive] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FlexDirection {
#[default]
Row,
Column,
}
impl Display for FlexDirection {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::Row => "row",
Self::Column => "column",
}
)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum FlexWrap {
#[default]
NoWrap,
Wrap,
WrapReverse,
}
impl Display for FlexWrap {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::NoWrap => "nowrap",
Self::Wrap => "wrap",
Self::WrapReverse => "wrap-reverse",
}
)
}
}
#[non_exhaustive] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum JustifyContent {
#[default] FlexStart,
FlexEnd,
Center,
SpaceBetween,
SpaceAround,
SpaceEvenly, }
impl Display for JustifyContent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::FlexStart => "flex-start",
Self::FlexEnd => "flex-end",
Self::Center => "center",
Self::SpaceBetween => "space-between",
Self::SpaceAround => "space-around",
Self::SpaceEvenly => "space-evenly",
}
)
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AlignItems {
FlexStart,
FlexEnd,
Center,
#[default] Stretch,
}
impl Display for AlignItems {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::FlexStart => "flex-start",
Self::FlexEnd => "flex-end",
Self::Center => "center",
Self::Stretch => "stretch",
}
)
}
}
#[non_exhaustive] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AlignContent {
#[default]
FlexStart,
FlexEnd,
Center,
Stretch,
SpaceBetween,
SpaceAround,
}
impl Display for AlignContent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Self::FlexStart => "flex-start",
Self::FlexEnd => "flex-end",
Self::Center => "center",
Self::Stretch => "stretch",
Self::SpaceBetween => "space-between",
Self::SpaceAround => "space-around",
}
)
}
}
#[derive(Default)]
struct FlexboxLayout {
size: XY<usize>,
options: FlexBoxOptions,
main_axes: Vec<MainAxis>,
}
#[derive(Debug)]
enum FlexboxError {
AxisFull,
}
impl FlexboxLayout {
pub fn windows(&mut self) -> Vec<(Rc<RefCell<FlexItem>>, Rect)> {
let mut windows = Vec::new();
let mut cross_offset = 0;
let mut assignable_free_space = self.cross_axis_free_space();
for (axis_index, axis) in self.main_axes.iter().enumerate() {
match self.options.axes_alignment {
AlignContent::FlexEnd => {
if assignable_free_space > 0 {
cross_offset += assignable_free_space;
}
assignable_free_space = 0;
},
AlignContent::Center => {
if assignable_free_space > 0 {
cross_offset += assignable_free_space / 2;
}
assignable_free_space = 0;
},
AlignContent::Stretch => {
let assigned_space =
assignable_free_space / (self.main_axes.len() - axis_index);
if assignable_free_space > 0 {
cross_offset += assigned_space;
}
assignable_free_space -= assigned_space;
},
AlignContent::SpaceAround => {
let assigned_space =
assignable_free_space / (self.main_axes.len() * 2 - axis_index * 2);
if assignable_free_space > 0 {
cross_offset += assigned_space;
}
assignable_free_space -= assigned_space;
},
_ => {},
}
for mut combo in axis.windows(self) {
match self.options.direction {
FlexDirection::Row => combo.1.offset(XY::from((0, cross_offset))),
FlexDirection::Column => combo.1.offset(XY::from((cross_offset, 0))),
}
windows.push(combo);
}
match self.options.axes_alignment {
AlignContent::SpaceBetween => {
if assignable_free_space > 0 {
let assigned_space =
assignable_free_space / (self.main_axes.len() - axis_index - 1);
if assignable_free_space > 0 {
cross_offset += assigned_space;
}
assignable_free_space -= assigned_space;
}
},
AlignContent::SpaceAround => {
let assigned_space =
assignable_free_space / (self.main_axes.len() * 2 - (axis_index * 2 + 1));
if assignable_free_space > 0 {
cross_offset += assigned_space;
}
assignable_free_space -= assigned_space;
},
_ => {},
}
cross_offset += axis.cross_axis_size(self) + self.options.cross_axis_gap as usize;
}
windows
}
pub fn cross_axis_free_space(&self) -> usize {
let mut used_space = 0;
for axis in &self.main_axes {
used_space += axis.cross_axis_size(self);
}
used_space += (self.main_axis_count() - 1) * self.options.cross_axis_gap as usize;
match self.options.direction {
FlexDirection::Row => self.size.y.saturating_sub(used_space),
FlexDirection::Column => self.size.x.saturating_sub(used_space),
}
}
pub fn generate(
content: &[Weak<RefCell<FlexItem>>],
width: usize,
height: usize,
options: FlexBoxOptions,
) -> Rc<RefCell<Self>> {
let layout = Rc::new(RefCell::new(FlexboxLayout {
size: XY::from((width, height)),
options,
main_axes: Vec::new(),
}));
let mut added = 0;
let length = content.len();
while added < length {
let mut main_axis = MainAxis::new(Rc::downgrade(&layout));
loop {
let result =
main_axis.add_item(content[added].clone(), &mut RefCell::borrow_mut(&layout));
if result.is_err() {
break;
} else if added + 1 == length {
added += 1;
break;
} else {
added += 1;
}
}
match options.wrap {
FlexWrap::NoWrap | FlexWrap::Wrap => {
RefCell::borrow_mut(&layout).main_axes.push(main_axis)
},
FlexWrap::WrapReverse => {
RefCell::borrow_mut(&layout).main_axes.insert(0, main_axis)
},
}
}
layout
}
pub fn flexitem_main_axis_size(&self, item: &mut FlexItem) -> usize {
match self.options.direction {
FlexDirection::Row => item.view.required_size(self.size).x,
FlexDirection::Column => item.view.required_size(self.size).y,
}
}
pub fn main_axis_count(&self) -> usize {
self.main_axes.len()
}
}
struct MainAxis {
items: Vec<Weak<RefCell<FlexItem>>>,
free_space: usize,
}
impl MainAxis {
pub fn new(layout: Weak<RefCell<FlexboxLayout>>) -> Self {
let layout_upgraded = layout.upgrade().unwrap();
let free_space = match RefCell::borrow(&layout_upgraded).options.direction {
FlexDirection::Row => RefCell::borrow(&layout_upgraded).size.x,
FlexDirection::Column => RefCell::borrow(&layout_upgraded).size.y,
};
MainAxis {
items: Vec::new(),
free_space,
}
}
pub fn cross_axis_size(&self, layout: &FlexboxLayout) -> usize {
let mut maximum_item_cross_axis_size = 0;
match layout.options.direction {
FlexDirection::Row => {
for item in &self.items {
maximum_item_cross_axis_size = maximum_item_cross_axis_size.max(
RefCell::borrow_mut(&item.upgrade().unwrap())
.view
.required_size(layout.size)
.y,
);
}
},
FlexDirection::Column => {
for item in &self.items {
maximum_item_cross_axis_size = maximum_item_cross_axis_size.max(
RefCell::borrow_mut(&item.upgrade().unwrap())
.view
.required_size(layout.size)
.x,
);
}
},
}
maximum_item_cross_axis_size
}
pub fn windows(&self, layout: &FlexboxLayout) -> Vec<(Rc<RefCell<FlexItem>>, Rect)> {
let mut windows = Vec::new();
let mut offset = 0;
let mut assignable_free_space = self.free_space;
let combined_grow_factor = self.combined_grow_factor();
let mut remaining_grow_factor = combined_grow_factor;
let cross_axis_size = self.cross_axis_size(layout);
for (item_index, item) in self
.items
.iter()
.map(|item| item.upgrade().unwrap())
.enumerate()
{
let mut start_x = 0;
let mut start_y = 0;
let mut width = 1;
let mut height = 1;
if combined_grow_factor > 0 {
let mut added_space = 0;
let item_main_axis_size =
layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item));
if remaining_grow_factor > 0 {
added_space = (RefCell::borrow(&item).flex_grow as usize
/ remaining_grow_factor)
* assignable_free_space;
}
match layout.options.direction {
FlexDirection::Row => {
start_x = offset;
width = item_main_axis_size + added_space;
},
FlexDirection::Column => {
start_y = offset;
height = item_main_axis_size + added_space;
},
}
offset += item_main_axis_size + layout.options.main_axis_gap as usize + added_space;
assignable_free_space -= added_space;
remaining_grow_factor -= RefCell::borrow(&item).flex_grow as usize;
} else {
match layout.options.direction {
FlexDirection::Row => {
width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
},
FlexDirection::Column => {
height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
},
}
match layout.options.justification {
JustifyContent::FlexStart => {
match layout.options.direction {
FlexDirection::Row => {
start_x = offset;
},
FlexDirection::Column => {
start_y = offset;
},
}
offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
+ layout.options.main_axis_gap as usize;
},
JustifyContent::FlexEnd => {
if assignable_free_space > 0 {
offset = assignable_free_space;
assignable_free_space = 0;
}
match layout.options.direction {
FlexDirection::Row => {
start_x = offset;
},
FlexDirection::Column => {
start_y = offset;
},
}
offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
+ layout.options.main_axis_gap as usize;
},
JustifyContent::Center => {
if assignable_free_space > 0 {
offset = assignable_free_space / 2;
assignable_free_space = 0;
}
match layout.options.direction {
FlexDirection::Row => {
start_x = offset;
},
FlexDirection::Column => {
start_y = offset;
},
}
offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
+ layout.options.main_axis_gap as usize;
},
JustifyContent::SpaceBetween => {
match layout.options.direction {
FlexDirection::Row => {
start_x = offset;
},
FlexDirection::Column => {
start_y = offset;
},
}
if assignable_free_space > 0 && item_index + 1 < self.number_of_items() {
let extra_free_space = assignable_free_space
/ (self.number_of_items().saturating_sub(1 + item_index));
assignable_free_space -= extra_free_space;
offset += extra_free_space;
}
offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
+ layout.options.main_axis_gap as usize;
},
JustifyContent::SpaceAround => {
let mut extra_free_space =
assignable_free_space / (self.number_of_items() * 2 - item_index * 2);
if assignable_free_space > 0 {
offset += extra_free_space;
}
assignable_free_space -= extra_free_space;
match layout.options.direction {
FlexDirection::Row => {
start_x = offset;
},
FlexDirection::Column => {
start_y = offset;
},
}
extra_free_space = assignable_free_space
/ (self.number_of_items() * 2 - (item_index * 2 + 1));
if assignable_free_space > 0 {
offset += extra_free_space;
}
assignable_free_space -= extra_free_space;
offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
+ layout.options.main_axis_gap as usize;
},
JustifyContent::SpaceEvenly => {
let extra_free_space =
assignable_free_space / (self.number_of_items() + 1 - item_index);
if assignable_free_space > 0 {
offset += extra_free_space;
}
assignable_free_space -= extra_free_space;
match layout.options.direction {
FlexDirection::Row => {
start_x = offset;
},
FlexDirection::Column => {
start_y = offset;
},
}
offset += layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&item))
+ layout.options.main_axis_gap as usize;
},
}
}
match layout.options.item_alignment {
AlignItems::FlexStart => match layout.options.direction {
FlexDirection::Row => {
start_y = 0;
height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
},
FlexDirection::Column => {
start_x = 0;
width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
},
},
AlignItems::FlexEnd => match layout.options.direction {
FlexDirection::Row => {
height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
start_y = cross_axis_size - height;
},
FlexDirection::Column => {
width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
start_x = cross_axis_size - width;
},
},
AlignItems::Center => match layout.options.direction {
FlexDirection::Row => {
height = RefCell::borrow_mut(&item).view.required_size(layout.size).y;
start_y = (cross_axis_size - height) / 2;
},
FlexDirection::Column => {
width = RefCell::borrow_mut(&item).view.required_size(layout.size).x;
start_x = (cross_axis_size - width) / 2;
},
},
AlignItems::Stretch => match layout.options.direction {
FlexDirection::Row => {
height = cross_axis_size;
start_y = 0;
},
FlexDirection::Column => {
width = cross_axis_size;
start_x = 0;
},
},
}
RefCell::borrow_mut(&item)
.view
.layout((width, height).into());
windows.push((item, Rect::from_size((start_x, start_y), (width, height))));
}
windows
}
pub fn add_item(
&mut self,
item: Weak<RefCell<FlexItem>>,
layout: &mut FlexboxLayout,
) -> Result<(), FlexboxError> {
let upgraded_item = item.upgrade().unwrap();
if self.can_accomodate(&mut RefCell::borrow_mut(&upgraded_item), layout) {
self.free_space = self.free_space.saturating_sub(
layout.flexitem_main_axis_size(&mut RefCell::borrow_mut(&upgraded_item)),
);
if self.number_of_items() >= 1 {
self.free_space = self
.free_space
.saturating_sub(layout.options.main_axis_gap as usize);
}
self.items.push(item);
Ok(())
} else {
Err(FlexboxError::AxisFull)
}
}
pub fn can_accomodate(&self, item: &mut FlexItem, layout: &mut FlexboxLayout) -> bool {
if let FlexWrap::NoWrap = layout.options.wrap {
layout.main_axes.len() == 1
} else if self.items.is_empty() {
true
} else {
let extra_used_space = if self.number_of_items() >= 1 {
layout.flexitem_main_axis_size(item) + layout.options.main_axis_gap as usize
} else {
layout.flexitem_main_axis_size(item)
};
extra_used_space <= self.free_space
}
}
pub fn number_of_items(&self) -> usize {
self.items.len()
}
pub fn combined_grow_factor(&self) -> usize {
let mut total_grow_factor = 0usize;
self.items.iter().for_each(|item| {
total_grow_factor += RefCell::borrow(&item.upgrade().unwrap()).flex_grow as usize;
});
total_grow_factor
}
}
impl<T: Into<FlexItem>> From<Vec<T>> for Flexbox {
fn from(value: Vec<T>) -> Self {
let content: Vec<Rc<RefCell<FlexItem>>> = value
.into_iter()
.map(|item| Rc::new(RefCell::new(item.into())))
.collect();
Self {
content,
..Default::default()
}
}
}
impl Flexbox {
pub fn new() -> Self {
Self::default()
}
pub fn push(&mut self, item: impl Into<FlexItem>) {
self.content.push(Rc::new(RefCell::new(item.into())));
}
pub fn clear(&mut self) {
self.content.clear();
}
pub fn insert(&mut self, index: usize, item: impl Into<FlexItem>) {
self.content
.insert(index, Rc::new(RefCell::new(item.into())));
}
pub fn set_flex_grow(&mut self, index: usize, flex_grow: u8) {
Rc::as_ref(&self.content[index]).borrow_mut().flex_grow = flex_grow;
}
pub fn len(&self) -> usize {
self.content.len()
}
pub fn is_empty(&self) -> bool {
self.content.is_empty()
}
pub fn remove(&mut self, index: usize) {
self.content.remove(index);
}
pub fn main_axis_gap(&self) -> u32 {
self.options.main_axis_gap
}
pub fn set_main_axis_gap(&mut self, gap: u32) {
self.options.main_axis_gap = gap;
}
pub fn cross_axis_gap(&self) -> u32 {
self.options.cross_axis_gap
}
pub fn set_cross_axis_gap(&mut self, gap: u32) {
self.options.cross_axis_gap = gap;
}
pub fn justify_content(&self) -> JustifyContent {
self.options.justification
}
pub fn set_justify_content(&mut self, justify_content: JustifyContent) {
self.options.justification = justify_content;
}
pub fn align_items(&self) -> AlignItems {
self.options.item_alignment
}
pub fn set_align_items(&mut self, item_alignment: AlignItems) {
self.options.item_alignment = item_alignment;
}
pub fn align_content(&self) -> AlignContent {
self.options.axes_alignment
}
pub fn set_align_content(&mut self, axes_alignment: AlignContent) {
self.options.axes_alignment = axes_alignment;
}
pub fn flex_direction(&self) -> FlexDirection {
self.options.direction
}
pub fn set_flex_direction(&mut self, direction: FlexDirection) {
self.options.direction = direction;
}
pub fn flex_wrap(&self) -> FlexWrap {
self.options.wrap
}
pub fn set_flex_wrap(&mut self, wrap: FlexWrap) {
self.options.wrap = wrap;
}
fn generate_layout(&self, constraints: XY<usize>) -> Layout<Rc<RefCell<FlexItem>>> {
let layout = FlexboxLayout::generate(
&self.content.iter().map(Rc::downgrade).collect::<Vec<_>>(),
constraints.x,
constraints.y,
self.options,
);
let mut result = Layout {
elements: Vec::new(),
};
RefCell::borrow_mut(&layout)
.windows()
.into_iter()
.for_each(|item| {
result.elements.push(PlacedElement {
element: item.0,
position: item.1,
})
});
result
}
}
impl View for Flexbox {
fn draw(&self, printer: &cursive_core::Printer<'_, '_>) {
if let Some(ref layout) = self.layout {
for placed_element in layout {
RefCell::borrow(&placed_element.element)
.view
.draw(&printer.windowed(placed_element.position));
}
}
}
fn layout(&mut self, printer_size: Vec2) {
self.layout = Some(self.generate_layout(printer_size));
for placed_element in self.layout.as_ref().unwrap() {
RefCell::borrow_mut(&placed_element.element)
.view
.layout(placed_element.position.size());
}
}
fn needs_relayout(&self) -> bool {
true
}
fn required_size(&mut self, constraint: cursive_core::Vec2) -> cursive_core::Vec2 {
let layout = self.generate_layout(constraint);
layout.size()
}
fn on_event(
&mut self,
mut event: cursive_core::event::Event,
) -> cursive_core::event::EventResult {
if let Some(active_child) = self.focused {
if let cursive_core::event::Event::Mouse {
ref mut offset,
ref mut position,
..
} = event
{
if let Some(ref layout) = self.layout {
if let Some(placed_element) =
layout.element_at(global_to_view_coordinates(*position, *offset))
{
*offset = *offset + placed_element.position.top_left();
RefCell::borrow_mut(&placed_element.element)
.view
.on_event(event)
} else {
EventResult::Ignored
}
} else {
EventResult::Ignored
}
} else {
RefCell::borrow_mut(&self.content[active_child])
.view
.on_event(event)
}
} else {
EventResult::Ignored
}
}
fn focus_view(
&mut self,
selector: &cursive_core::view::Selector<'_>,
) -> Result<EventResult, cursive_core::view::ViewNotFound> {
for (index, view) in self.content.iter_mut().enumerate() {
if let Ok(event_result) = RefCell::borrow_mut(view).view.focus_view(selector) {
self.focused = Some(index);
return Ok(event_result);
}
}
Err(cursive_core::view::ViewNotFound)
}
fn call_on_any(
&mut self,
selector: &cursive_core::view::Selector<'_>,
callback: cursive_core::event::AnyCb<'_>,
) {
for view in self.content.iter_mut() {
RefCell::borrow_mut(view)
.view
.call_on_any(selector, callback);
}
}
fn take_focus(
&mut self,
_source: cursive_core::direction::Direction,
) -> Result<EventResult, cursive_core::view::CannotFocus> {
Ok(EventResult::Consumed(None))
}
fn important_area(&self, _view_size: Vec2) -> Rect {
if let Some(ref layout) = self.layout {
if let Some(focused) = self.focused {
layout.elements[focused].position
} else {
Rect::from_size((0, 0), (1, 1))
}
} else {
Rect::from_size((0, 0), (1, 1))
}
}
}
impl FlexItem {
pub fn with_flex_grow(view: impl IntoBoxedView, flex_grow: u8) -> Self {
Self {
view: view.into_boxed_view(),
flex_grow,
}
}
pub fn set_flex_grow(&mut self, flex_grow: u8) {
self.flex_grow = flex_grow;
}
pub fn flex_grow(&self) -> u8 {
self.flex_grow
}
}
impl<T: IntoBoxedView> From<T> for FlexItem {
fn from(value: T) -> Self {
Self {
view: value.into_boxed_view(),
flex_grow: 0,
}
}
}
fn global_to_view_coordinates(global_coordinates: XY<usize>, view_offset: XY<usize>) -> XY<usize> {
global_coordinates - view_offset
}
#[cfg(test)]
mod test {
use cursive::views::TextView;
use super::*;
#[test]
fn justify_content_single_item() {
let mut flexbox = Flexbox::from(vec![TextView::new("Hello").into_boxed_view()]);
flexbox.set_justify_content(JustifyContent::FlexStart);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
9,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 0);
assert_eq!(windows[0].1.width(), 5);
flexbox.set_justify_content(JustifyContent::FlexEnd);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
9,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 4);
assert_eq!(windows[0].1.width(), 5);
flexbox.set_justify_content(JustifyContent::Center);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
9,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 2);
assert_eq!(windows[0].1.width(), 5);
flexbox.set_justify_content(JustifyContent::SpaceBetween);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
9,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 0);
assert_eq!(windows[0].1.width(), 5);
flexbox.set_justify_content(JustifyContent::SpaceAround);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
9,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 2);
assert_eq!(windows[0].1.width(), 5);
flexbox.set_justify_content(JustifyContent::SpaceEvenly);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
9,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 2);
assert_eq!(windows[0].1.width(), 5);
}
#[test]
fn justify_content_multiple_items() {
let mut flexbox = Flexbox::from(vec![
TextView::new("Hello").into_boxed_view(),
TextView::new("flexbox").into_boxed_view(),
]);
flexbox.set_justify_content(JustifyContent::FlexStart);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
18,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 0);
assert_eq!(windows[0].1.width(), 5);
assert_eq!(windows[1].1.left(), 5);
assert_eq!(windows[1].1.width(), 7);
flexbox.set_justify_content(JustifyContent::FlexEnd);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
18,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 6);
assert_eq!(windows[0].1.width(), 5);
assert_eq!(windows[1].1.left(), 11);
assert_eq!(windows[1].1.width(), 7);
flexbox.set_justify_content(JustifyContent::Center);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
18,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 3);
assert_eq!(windows[0].1.width(), 5);
assert_eq!(windows[1].1.left(), 8);
assert_eq!(windows[1].1.width(), 7);
flexbox.set_justify_content(JustifyContent::SpaceBetween);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
18,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 0);
assert_eq!(windows[0].1.width(), 5);
assert_eq!(windows[1].1.left(), 11);
assert_eq!(windows[1].1.width(), 7);
flexbox.set_justify_content(JustifyContent::SpaceAround);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
16,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 1);
assert_eq!(windows[0].1.width(), 5);
assert_eq!(windows[1].1.left(), 8);
assert_eq!(windows[1].1.width(), 7);
flexbox.set_justify_content(JustifyContent::SpaceEvenly);
let layout = FlexboxLayout::generate(
&flexbox
.content
.iter()
.map(|item| Rc::downgrade(&Rc::clone(item)))
.collect::<Vec<_>>(),
18,
1,
flexbox.options,
);
let mut layout_mut = RefCell::borrow_mut(&layout);
let windows = layout_mut.windows();
assert_eq!(windows[0].1.left(), 2);
assert_eq!(windows[0].1.width(), 5);
assert_eq!(windows[1].1.left(), 9);
assert_eq!(windows[1].1.width(), 7);
}
}