agg-gui 0.3.0

Immediate-mode Rust GUI library with AGG rendering, Y-up layout, widgets, text, SVG, and native/WASM adapters
Documentation
//! Double-click word / triple-click line selection tests for [`TextField`].
//!
//! Exercises the real `MouseDown` event path (so the shared multi-click counter
//! and the word/line selection wiring are covered end to end) against the
//! production widget — no logic copies.

use std::sync::Arc;

use super::*;
use crate::event::{Event, Modifiers, MouseButton};
use crate::geometry::Point;
use crate::widget::Widget;

const FONT_BYTES: &[u8] = include_bytes!("../../../../demo/assets/CascadiaCode.ttf");

fn font() -> Arc<Font> {
    Arc::new(Font::from_slice(FONT_BYTES).expect("font"))
}

fn laid_out(text: &str) -> TextField {
    let mut f = TextField::new(font()).with_text(text);
    f.layout(Size::new(400.0, 32.0));
    f.on_event(&Event::FocusGained);
    f
}

/// Widget-local x for the left edge of byte `off` (scroll_x is 0 fresh).
fn x_for_offset(f: &TextField, text: &str, off: usize) -> f64 {
    f.padding + measure_advance(&f.active_font(), &text[..off], f.font_size)
}

fn press(f: &mut TextField, x: f64) {
    f.on_event(&Event::MouseDown {
        pos: Point::new(x, 16.0),
        button: MouseButton::Left,
        modifiers: Modifiers::default(),
    });
    f.on_event(&Event::MouseUp {
        pos: Point::new(x, 16.0),
        button: MouseButton::Left,
        modifiers: Modifiers::default(),
    });
}

#[test]
fn double_click_selects_word() {
    let text = "hello world";
    let mut f = laid_out(text);
    let x = x_for_offset(&f, text, 8); // inside "world"
    press(&mut f, x);
    press(&mut f, x);
    assert_eq!(f.selection(), "world");
}

#[test]
fn double_click_stops_at_punctuation() {
    let text = "foo.bar";
    let mut f = laid_out(text);
    let x_foo = x_for_offset(&f, text, 1);
    press(&mut f, x_foo);
    press(&mut f, x_foo);
    assert_eq!(f.selection(), "foo");

    let mut f = laid_out(text);
    let x_bar = x_for_offset(&f, text, 5);
    press(&mut f, x_bar);
    press(&mut f, x_bar);
    assert_eq!(f.selection(), "bar");
}

#[test]
fn triple_click_selects_whole_field() {
    let text = "select all of this";
    let mut f = laid_out(text);
    let x = x_for_offset(&f, text, 4);
    press(&mut f, x);
    press(&mut f, x);
    press(&mut f, x);
    assert_eq!(f.selection(), text);
}

/// A double-click landing on the last glyph of a word (near its right edge)
/// still selects the whole word, not the following whitespace.
#[test]
fn double_click_near_word_edge() {
    let text = "cat dog";
    let mut f = laid_out(text);
    // A couple of pixels into the last glyph of "cat" ('t' starts at byte 2).
    let x = x_for_offset(&f, text, 2) + 2.0;
    press(&mut f, x);
    press(&mut f, x);
    assert_eq!(f.selection(), "cat");
}