use kui_core::testing::{edit_key, press, release};
use kui_core::{
Core, DevtoolsDock, EditKey, EditOptions, InputEvent, Key, Mods, NodeSpec, Role, Size,
TextStyle, Value, Vec2,
};
const VIEW: Size = Size { w: 400.0, h: 200.0 };
const CENTRE: Vec2 = Vec2 { x: 120.0, y: 40.0 };
fn drawn(upright: Vec2) -> Vec2 {
Vec2::new(2.0 * CENTRE.x - upright.x, 2.0 * CENTRE.y - upright.y)
}
fn card(turn: f32) -> NodeSpec {
NodeSpec::column().size(200.0, 40.0).pad(8.0).rotate(turn)
}
fn field(core: &mut Core, turn: f32) -> Key {
let mut ui = core.frame(VIEW, 1.0);
ui.configure_root(NodeSpec::column().pad(20.0));
let mut key = Key(0);
ui.with(card(turn), |ui| {
key = ui.text_edit(
"field",
"mmmmmmmmmm",
&EditOptions::default(),
NodeSpec::column().grow_width(),
);
});
ui.finish();
key
}
fn typed_at(turn: f32, at: Vec2) -> String {
let mut core = Core::new();
let key = field(&mut core, turn);
field(&mut core, turn);
press(&mut core, at);
release(&mut core);
core.handle_input(InputEvent::Text("X".into()));
core.edit_text(key).unwrap()
}
#[test]
fn a_click_places_the_caret_where_the_text_is_drawn() {
let start = Vec2::new(30.0, 40.0);
assert!(typed_at(0.0, start).starts_with('X'));
let t = typed_at(0.5, drawn(start));
assert!(t.starts_with('X'), "the caret at the drawn start: {t}");
}
#[test]
fn the_ime_anchor_is_where_the_caret_is_drawn() {
let mut core = Core::new();
let key = field(&mut core, 0.5);
field(&mut core, 0.5);
core.set_focus(Some(key));
edit_key(&mut core, EditKey::Home, Mods::default());
field(&mut core, 0.5);
let ime = core.ime_rect().expect("an IME anchor");
assert!(ime.x > CENTRE.x + 50.0, "and so is the IME's: {ime:?}");
}
fn paragraph(core: &mut Core, turn: f32) -> Key {
let mut ui = core.frame(VIEW, 1.0);
ui.configure_root(NodeSpec::column().pad(20.0));
let mut key = Key(0);
ui.with(card(turn).selectable(), |ui| {
key = ui.text_in_keyed(
"p",
NodeSpec::row(),
"alpha beta gamma",
TextStyle::new(14.0),
);
});
ui.finish();
key
}
#[test]
fn text_hit_and_a_selection_drag_read_the_drawn_text() {
let mut core = Core::new();
let p = paragraph(&mut core, 0.5);
paragraph(&mut core, 0.5);
let left = Vec2::new(29.0, 36.0);
let hit = core.text_hit(p, drawn(left)).expect("a hit");
assert!(hit.byte <= 1, "the drawn start is byte 0: {hit:?}");
let r = core.caret_rect(p, 0).expect("a caret rect");
assert!(r.x > CENTRE.x + 50.0, "byte 0 is drawn at the right: {r:?}");
let end = core.caret_rect(p, 5).expect("the end of alpha");
let to = Vec2::new(end.x + end.w / 2.0, end.y + end.h / 2.0);
press(&mut core, drawn(left));
core.handle_input(InputEvent::CursorMoved(to));
release(&mut core);
let got = core.selection_text().unwrap_or_default();
assert_eq!(got.trim(), "alpha", "the drawn first word");
}
#[test]
fn text_hit_and_caret_rect_agree_with_a_dock_open() {
let read = |dock: bool| {
let mut core = Core::new();
if dock {
core.set_devtools(true);
core.set_devtools_dock(DevtoolsDock::Left);
}
let mut p = Key(0);
for _ in 0..3 {
p = paragraph(&mut core, 0.5);
}
let hit = core
.text_hit(p, drawn(Vec2::new(29.0, 36.0)))
.map(|h| h.byte);
let x = core.caret_rect(p, 0).map(|r| r.x);
(hit, x)
};
let (hit, x) = read(false);
assert!(hit.is_some_and(|b| b <= 1), "{hit:?}");
assert_eq!(read(true), (hit, x), "the dock open");
}
#[test]
fn a_sinks_line_and_byte_read_through_a_turn_below_it() {
const LH: f32 = 20.0;
let frame = |core: &mut Core, outer: f32, inner: f32| {
let mut ui = core.frame(Size::new(400.0, 300.0), 1.0);
ui.configure_root(NodeSpec::column().pad(10.0));
let style = TextStyle::new(14.0).mono().line_height(LH);
let sink = ui.with_keyed(
"editor",
NodeSpec::row()
.size(300.0, 60.0)
.key_sink()
.rotate(outer)
.on_drag("sel")
.on_click(Value::map([("kind", Value::str("hit"))]))
.role(Role::MultilineTextInput),
|ui| {
ui.with(NodeSpec::column().size(300.0, 60.0).rotate(inner), |ui| {
for line in ["hello world", "second line", "third"] {
ui.with(NodeSpec::row().height(LH).role(Role::Line), |ui| {
ui.text(line, style);
});
}
});
},
);
ui.take_key_focus(sink);
ui.finish();
};
let read = |outer: f32, inner: f32| {
let mut core = Core::new();
for _ in 0..3 {
frame(&mut core, outer, inner);
}
let start = Vec2::new(12.0, 15.0);
let at = if outer + inner == 0.5 {
Vec2::new(320.0 - start.x, 80.0 - start.y)
} else {
start
};
let evs = press(&mut core, at);
let d = evs
.iter()
.find(|e| e.payload.get_str("kind") == Some("drag"))
.expect("a drag event");
(
d.payload.get("line").cloned(),
d.payload.get("byte").cloned(),
)
};
let upright = read(0.0, 0.0);
assert_eq!(upright, (Some(Value::Int(0)), Some(Value::Int(0))));
assert_eq!(read(0.5, 0.0), upright, "the sink turned");
assert_eq!(read(0.0, 0.5), upright, "a column inside it turned");
}