cranpose-ui 0.1.164

UI primitives for Cranpose
Documentation
use super::*;
use crate::text_selection::HANDLE_RADIUS;

const LINE_HEIGHT: f32 = 20.0;

#[test]
fn cursor_handle_touch_box_sits_at_or_below_the_line_bottom() {
    let shape = handle_shape(HandleKind::Cursor, HANDLE_RADIUS, LINE_HEIGHT);
    assert!(
        shape.tip_in_box.y.abs() < 0.01,
        "cursor handle anchor must sit at the top edge of its touch box \
         (tip_in_box.y = {}), so it never overlaps the text line above",
        shape.tip_in_box.y
    );
    assert!(
        shape.box_size.height >= 2.0 * HANDLE_RADIUS,
        "cursor handle box must extend below the anchor so the dot is grabbable"
    );
    assert!(
        !shape.path_data.contains('L'),
        "cursor handle must draw only its dot (no stem rectangle): {}",
        shape.path_data
    );
}

#[test]
fn grab_region_is_finger_sized() {
    for kind in [
        HandleKind::Cursor,
        HandleKind::SelectionStart,
        HandleKind::SelectionEnd,
    ] {
        let rect = handle_grab_rect(
            kind,
            Point { x: 100.0, y: 100.0 },
            HANDLE_RADIUS,
            LINE_HEIGHT,
        );
        assert!(
            rect.width >= 48.0,
            "{kind:?}: grab region must be at least a fingertip wide, got {}",
            rect.width
        );
        assert!(
            rect.height >= 32.0,
            "{kind:?}: grab region must be at least a fingertip tall, got {}",
            rect.height
        );
    }
}

#[test]
fn start_and_end_grab_regions_mirror_about_the_line() {
    let tip = Point { x: 100.0, y: 100.0 };
    let line_top = tip.y - LINE_HEIGHT;
    let start = handle_grab_rect(HandleKind::SelectionStart, tip, HANDLE_RADIUS, LINE_HEIGHT);
    let end = handle_grab_rect(HandleKind::SelectionEnd, tip, HANDLE_RADIUS, LINE_HEIGHT);

    assert!(
        (start.width - end.width).abs() < 0.01 && (start.height - end.height).abs() < 0.01,
        "start {start:?} and end {end:?} grab boxes must be the same size"
    );
    let start_above = line_top - start.y;
    let end_below = (end.y + end.height) - tip.y;
    assert!(
        (start_above - end_below).abs() < 0.01,
        "start reach above the line ({start_above}) must equal end reach below ({end_below})"
    );
    assert!(
        ((start.y + start.height) - tip.y).abs() < 0.01,
        "start grab box must stop at the line bottom (no slop below)"
    );
    assert!(
        (end.y - line_top).abs() < 0.01,
        "end grab box must start at the line top (no slop above)"
    );
}

#[test]
fn grab_regions_cover_the_dot_and_stem_but_not_neighbouring_lines() {
    let tip = Point { x: 100.0, y: 100.0 };
    let line_top = tip.y - LINE_HEIGHT;
    let contains =
        |r: Rect, x: f32, y: f32| x >= r.x && x <= r.x + r.width && y >= r.y && y <= r.y + r.height;

    let cursor = handle_grab_rect(HandleKind::Cursor, tip, HANDLE_RADIUS, LINE_HEIGHT);
    assert!(contains(cursor, tip.x - 16.0, tip.y + 12.0));
    assert!(contains(cursor, tip.x + 16.0, tip.y + 12.0));
    assert!(
        !contains(cursor, tip.x, tip.y - 2.0),
        "cursor: a press on the glyph line belongs to the field"
    );

    let start = handle_grab_rect(HandleKind::SelectionStart, tip, HANDLE_RADIUS, LINE_HEIGHT);
    assert!(
        contains(start, tip.x, line_top - HANDLE_RADIUS),
        "start: a press on the dot above the line must grab the handle"
    );
    assert!(
        contains(start, tip.x, tip.y - LINE_HEIGHT * 0.5),
        "start: a press on the stem column (on the line) must grab the handle"
    );
    assert!(
        !contains(start, tip.x, tip.y + 4.0),
        "start: a press below the line belongs to the field"
    );

    let end = handle_grab_rect(HandleKind::SelectionEnd, tip, HANDLE_RADIUS, LINE_HEIGHT);
    assert!(
        contains(end, tip.x, tip.y + HANDLE_RADIUS),
        "end: a press on the dot below the line must grab the handle"
    );
    assert!(
        contains(end, tip.x, tip.y - LINE_HEIGHT * 0.5),
        "end: a press on the stem column (on the line) must grab the handle"
    );
    assert!(
        !contains(end, tip.x, line_top - 4.0),
        "end: a press above the line belongs to the field"
    );
}