argui-platform 0.2.0

Native platform integrations for Argui applications
Documentation
#![cfg(all(feature = "desktop-backdrop", not(target_arch = "wasm32")))]
use argui_core::{Affine2D, Point, Rect, Size};
use argui_paint::{ClipChain, ClipRegion, CornerRadii};
use argui_platform::desktop_backdrop::{BackdropError, region_rectangles};

fn rect(x: f32, y: f32, width: f32, height: f32) -> Rect {
    Rect::new(Point::new(x, y), Size::new(width, height))
}
fn shape(bounds: Rect, radius: f32) -> ClipChain {
    ClipChain::from_regions([ClipRegion::rounded(
        bounds,
        Affine2D::IDENTITY,
        CornerRadii::all(radius),
    )])
}

#[test]
fn native_masks_preserve_rounding_clipping_and_disjoint_panels() {
    let rounded = shape(rect(0.0, 0.0, 100.0, 80.0), 14.0).appended(ClipRegion::new(
        rect(0.0, 0.0, 74.0, 65.0),
        Affine2D::IDENTITY,
    ));
    let rectangles = region_rectangles(std::slice::from_ref(&rounded)).unwrap();
    assert!(rectangles.len() < 25);
    for y in 0..80 {
        for x in 0..100 {
            let point = Point::new(x as f32 + 0.5, y as f32 + 0.5);
            assert_eq!(
                rectangles.iter().any(|rect| rect.contains(point)),
                rounded.contains(point)
            );
        }
    }
    let other = rect(200.0, 100.0, 200.0, 120.0);
    let all = region_rectangles(&[rounded, shape(other, 0.0)]).unwrap();
    assert_eq!(all.last(), Some(&other));
}

#[test]
fn rectangular_masks_coalesce_and_invalid_or_empty_shapes_fail_safely() {
    let sidebar = rect(0.0, 64.0, 260.0, 716.0);
    assert_eq!(
        region_rectangles(&[shape(sidebar, 0.0)]).unwrap(),
        vec![sidebar]
    );
    for empty in [
        ClipChain::default(),
        shape(Rect::default(), 4.0),
        shape(rect(0.0, 0.0, 0.5, 0.5), 0.0),
    ] {
        assert!(region_rectangles(&[empty]).unwrap().is_empty());
    }
    for bad in [
        rect(f32::NAN, 0.0, 10.0, 10.0),
        rect(0.0, 0.0, 40_000.0, 10.0),
        rect(0.0, 0.0, 10.0, 40_000.0),
    ] {
        assert_eq!(
            region_rectangles(&[shape(bad, 0.0)]),
            Err(BackdropError::InvalidGeometry)
        );
    }
    let hidden = shape(rect(0.0, 0.0, 10.0, 10.0), 2.0).appended(ClipRegion::new(
        rect(30.0, 30.0, 10.0, 10.0),
        Affine2D::IDENTITY,
    ));
    assert!(region_rectangles(&[hidden]).unwrap().is_empty());
    assert!(
        BackdropError::Unsupported
            .to_string()
            .contains("unavailable")
    );
    assert!(
        BackdropError::InvalidGeometry
            .to_string()
            .contains("geometry")
    );
    assert_eq!(
        BackdropError::Platform("request failed".into()).to_string(),
        "request failed"
    );
}

#[test]
fn rotated_and_singular_shapes_match_the_rendered_clip() {
    for matrix in [[0.8, 0.6, -0.6, 0.8], [0.0; 4]] {
        let shape = ClipChain::from_regions([ClipRegion::rounded(
            rect(0.0, 0.0, 50.0, 30.0),
            Affine2D {
                matrix,
                translation: Point::new(30.0, 10.0),
            },
            CornerRadii::all(3.0),
        )]);
        let regions = region_rectangles(std::slice::from_ref(&shape)).unwrap();
        for y in 10..60 {
            for x in 15..60 {
                let point = Point::new(x as f32 + 0.5, y as f32 + 0.5);
                assert_eq!(
                    regions.iter().any(|region| region.contains(point)),
                    shape.contains(point)
                );
            }
        }
    }
}