use azul_core::{
dom::{Dom, DomId, DomNodeId, IdOrClass, NodeId},
geom::LogicalSize,
resources::RendererResources,
styled_dom::{NodeHierarchyItemId, StyledDom},
};
use azul_css::css::Css;
use azul_layout::{
callbacks::ExternalSystemCallbacks, window::LayoutWindow, window_state::FullWindowState,
};
use rust_fontconfig::FcFontCache;
fn create_layout_window() -> LayoutWindow {
let font_cache = FcFontCache::build();
LayoutWindow::new(font_cache).unwrap()
}
fn create_window_state(width: f32, height: f32) -> FullWindowState {
let mut window_state = FullWindowState::default();
window_state.size.dimensions = LogicalSize::new(width, height);
window_state
}
fn layout_dom(dom: Dom, css_str: &str, width: f32, height: f32) -> LayoutWindow {
let (css, _) = azul_css::parser2::new_from_str(css_str);
let mut dom = dom;
let styled_dom = StyledDom::create(&mut dom, css);
let mut layout_window = create_layout_window();
let window_state = create_window_state(width, height);
let renderer_resources = RendererResources::default();
let system_callbacks = ExternalSystemCallbacks::rust_internal();
let mut debug_messages = Some(Vec::new());
layout_window
.layout_and_generate_display_list(
styled_dom,
&window_state,
&renderer_resources,
&system_callbacks,
&mut debug_messages,
)
.unwrap();
layout_window
}
fn get_root_id() -> DomNodeId {
DomNodeId {
dom: DomId::ROOT_ID,
node: NodeHierarchyItemId::from_crate_internal(Some(NodeId::ZERO)),
}
}
#[test]
fn test_flexbox_row_direction() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
flex-direction: row;
width: 300px;
height: 100px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let container_rect = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
assert!(
(container_rect.size.width - 300.0).abs() < 1.0,
"Container width should be 300px, got {}",
container_rect.size.width
);
}
#[test]
fn test_flexbox_column_direction() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
flex-direction: column;
width: 100px;
height: 200px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let container_rect = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
assert!(
(container_rect.size.height - 200.0).abs() < 1.0,
"Container height should be 200px, got {}",
container_rect.size.height
);
}
#[test]
fn test_flexbox_justify_content_center() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
justify-content: center;
width: 300px;
height: 100px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_justify_content_space_between() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
justify-content: space-between;
width: 400px;
height: 100px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_align_items_center() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
align-items: center;
width: 300px;
height: 200px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_flex_grow() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("grow".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("fixed".into())].into()),
);
let css = r#"
.container {
display: flex;
width: 300px;
height: 100px;
}
.grow {
flex-grow: 1;
height: 50px;
}
.fixed {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_flex_shrink() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
width: 200px;
height: 100px;
}
.item {
flex-shrink: 1;
width: 150px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_flex_wrap() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
flex-wrap: wrap;
width: 200px;
height: 200px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_gap() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
gap: 10px;
width: 400px;
height: 100px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_order() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("first".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("second".into())].into()),
);
let css = r#"
.container {
display: flex;
width: 200px;
height: 100px;
}
.first {
order: 2;
width: 50px;
height: 50px;
}
.second {
order: 1;
width: 50px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_nested() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("outer".into())].into())
.with_child(
Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("inner".into())].into())
.with_child(
Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
),
);
let css = r#"
.outer {
display: flex;
flex-direction: column;
width: 300px;
height: 300px;
}
.inner {
display: flex;
flex-direction: row;
height: 100px;
}
.item {
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("outer rect");
}
#[test]
fn test_flexbox_min_max_size() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
width: 400px;
height: 100px;
}
.item {
flex-grow: 1;
min-width: 100px;
max-width: 200px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_auto_margin() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
width: 300px;
height: 100px;
}
.item {
margin: auto;
width: 100px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_align_self() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("start".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("end".into())].into()),
);
let css = r#"
.container {
display: flex;
align-items: flex-start;
width: 200px;
height: 200px;
}
.start {
width: 50px;
height: 50px;
}
.end {
align-self: flex-end;
width: 50px;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_empty_container() {
let dom =
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("container".into())].into());
let css = r#"
.container {
display: flex;
width: 300px;
height: 100px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let container_rect = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
assert!(
(container_rect.size.width - 300.0).abs() < 1.0,
"Empty flex container width should be 300px, got {}",
container_rect.size.width
);
}
#[test]
fn test_flexbox_single_child() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
justify-content: center;
align-items: center;
width: 300px;
height: 300px;
}
.item {
width: 100px;
height: 100px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_percentage_width() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
width: 400px;
height: 100px;
}
.item {
width: 50%;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_flex_basis_auto() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("item".into())].into())
.with_child(Dom::create_text("Content")),
);
let css = r#"
.container {
display: flex;
width: 400px;
height: 100px;
}
.item {
flex-basis: auto;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}
#[test]
fn test_flexbox_flex_basis_zero() {
let dom = Dom::create_div()
.with_ids_and_classes(vec![IdOrClass::Class("container".into())].into())
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
)
.with_child(
Dom::create_div().with_ids_and_classes(vec![IdOrClass::Class("item".into())].into()),
);
let css = r#"
.container {
display: flex;
width: 400px;
height: 100px;
}
.item {
flex: 1 1 0;
height: 50px;
}
"#;
let layout_window = layout_dom(dom, css, 1024.0, 768.0);
let root_id = get_root_id();
let _ = layout_window
.get_node_layout_rect(root_id)
.expect("container rect");
}