//! The widget demo: a retained widget tree with nested flex layout, //! wrapping text, and an image, shared by the runnable example and the //! golden tests. use guiduck_core::{Container, Image, Text, WidgetId, WidgetTree, taffy}; use guiduck_scene::paint::color::palette::css; use taffy::prelude::{auto, length, percent}; use crate::{SAMPLE_FONT_FAMILY, checkerboard, sample_text_context}; /// Build the demo tree. Returns the tree and the id of the paragraph widget /// (used by tests to check wrapping behavior). pub fn demo_tree() -> (WidgetTree, WidgetId) { let mut tree = WidgetTree::with_text_context(sample_text_context()); let root = tree.insert( Container::new().background(css::WHITE_SMOKE), taffy::Style { size: taffy::Size { width: percent(1.0_f32), height: percent(1.0_f32), }, flex_direction: taffy::FlexDirection::Column, padding: taffy::Rect::length(16.0_f32), gap: taffy::Size { width: length(12.0_f32), height: length(12.0_f32), }, ..Default::default() }, None, ); tree.insert( Text::new("guiduck — widgets, flexbox, wrapping text") .font_size(20.0) .family(SAMPLE_FONT_FAMILY) .brush(css::DARK_SLATE_GRAY), taffy::Style::default(), Some(root), ); // A row of three growing cards. let cards = tree.insert( Container::new(), taffy::Style { flex_direction: taffy::FlexDirection::Row, gap: taffy::Size { width: length(12.0_f32), height: length(12.0_f32), }, ..Default::default() }, Some(root), ); for (label, color) in [ ("First", css::LIGHT_STEEL_BLUE), ("Second", css::NAVAJO_WHITE), ("Third", css::THISTLE), ] { let card = tree.insert( Container::new() .background(color) .corner_radius(10.0) .border(css::SLATE_GRAY, 1.5), taffy::Style { flex_grow: 1.0, flex_basis: length(0.0_f32), padding: taffy::Rect::length(12.0_f32), ..Default::default() }, Some(cards), ); tree.insert( Text::new(label) .font_size(15.0) .family(SAMPLE_FONT_FAMILY) .brush(css::BLACK), taffy::Style::default(), Some(card), ); } // A paragraph that wraps beside a fixed-width image. let body = tree.insert( Container::new(), taffy::Style { flex_direction: taffy::FlexDirection::Row, gap: taffy::Size { width: length(12.0_f32), height: length(12.0_f32), }, align_items: Some(taffy::AlignItems::FLEX_START), ..Default::default() }, Some(root), ); let paragraph = tree.insert( Text::new( "This paragraph lives in a flex row next to an image. When the window \ gets narrower the text wraps to more lines and the row grows taller, \ which is exactly the layout behavior taffy owes us. The quick brown \ fox jumps over the lazy dog.", ) .font_size(14.0) .family(SAMPLE_FONT_FAMILY) .brush(css::BLACK), taffy::Style { flex_grow: 1.0, flex_basis: length(0.0_f32), ..Default::default() }, Some(body), ); tree.insert( Image::new(guiduck_core::graphic::Graphic::Image(checkerboard())), taffy::Style { size: taffy::Size { width: length(96.0_f32), height: auto(), }, flex_shrink: 0.0, ..Default::default() }, Some(body), ); (tree, paragraph) } #[cfg(test)] mod tests { use guiduck_scene::FragmentStore; use guiduck_scene::geom::Size; use super::*; #[test] fn demo_lays_out_and_paints() { let (mut tree, paragraph) = demo_tree(); tree.compute_layout(Size::new(640.0, 420.0)); let wide_height = tree.layout(paragraph).height(); let mut store = FragmentStore::new(); let root = tree.paint_fresh(&mut store).expect("tree has a root"); assert!(store.get(root).unwrap().is_balanced()); let (mut narrow, paragraph2) = demo_tree(); narrow.compute_layout(Size::new(360.0, 420.0)); assert!( narrow.layout(paragraph2).height() > wide_height, "narrower viewport wraps the paragraph to more lines" ); } }