stress.rs raw

//! The backend-profiling stress tree: a themed grid of text cells inside a
//! scroll area, with live bindings — the shared workload for the render
//! paint- and backend-caching benchmarks and correctness gates.

use guiduck_core::signals::Signal;
use guiduck_core::{Container, ScrollArea, Text, Theme, WidgetTree, taffy};
use guiduck_scene::paint::color::palette::css;
use taffy::prelude::{length, percent};

use crate::{SAMPLE_FONT_FAMILY, sample_text_context};

/// The stress theme: themed cells with a hover rule, so pointer motion
/// exercises the style pass.
pub const STRESS_THEME: &str = r##"
(theme Stress
  (tokens (ink "#20304a") (cell "#eef1f7") (hot "#cfdcf5"))
  (rule container :background "#ffffff")
  (rule (container .cell) :background cell :corner-radius 3)
  (rule (container .cell :hover) :background hot)
  (rule text :color ink :font-size 11 :font-family "DejaVu Sans"))
"##;

/// Build a `rows` × `cols` grid of themed text cells inside a scroll area.
/// The first cell of each row binds its label to the returned signal, so
/// signal churn has something real to update.
pub fn stress_tree(rows: usize, cols: usize) -> (WidgetTree, Signal<i32>) {
    let mut tree = WidgetTree::with_text_context(sample_text_context());
    tree.set_theme(Some(Theme::parse(STRESS_THEME).expect("theme parses")));
    let scroll = tree.insert(
        ScrollArea::new(),
        taffy::Style {
            size: taffy::Size {
                width: percent(1.0_f32),
                height: percent(1.0_f32),
            },
            flex_direction: taffy::FlexDirection::Column,
            ..Default::default()
        },
        None,
    );
    let tick = Signal::new(0);
    for r in 0..rows {
        let row = tree.insert(
            Container::new(),
            taffy::Style {
                size: taffy::Size {
                    width: percent(1.0_f32),
                    height: length(28.0_f32),
                },
                flex_shrink: 0.0,
                gap: taffy::Size {
                    width: length(4.0_f32),
                    height: length(0.0_f32),
                },
                padding: taffy::Rect::length(2.0_f32),
                ..Default::default()
            },
            Some(scroll),
        );
        for c in 0..cols {
            let cell = tree.insert(
                Container::new(),
                taffy::Style {
                    size: taffy::Size {
                        width: length(112.0_f32),
                        height: percent(1.0_f32),
                    },
                    padding: taffy::Rect::length(4.0_f32),
                    ..Default::default()
                },
                Some(row),
            );
            tree.set_classes(cell, [String::from("cell")]);
            let label = tree.insert(
                Text::new(format!("r{r}c{c}"))
                    .font_size(11.0)
                    .family(SAMPLE_FONT_FAMILY)
                    .brush(css::DARK_SLATE_GRAY),
                taffy::Style::default(),
                Some(cell),
            );
            if c == 0 {
                let tick = tick;
                tree.bind::<Text, _>(
                    label,
                    move || format!("r{r} t{}", tick.get()),
                    |w, v| w.set_text(v),
                );
            }
        }
    }
    (tree, tick)
}