use kui_core::cells::{Cell, CellGrid};
use kui_core::schema::PropsOut;
use kui_core::testing::hover;
use kui_core::{
Color, Content, Core, FillRule, Key, NodeSpec, QuadKind, Rect, Size, Stroke, TextStyle, Vec2,
};
const VIEW: Size = Size { w: 400.0, h: 300.0 };
fn tipped(label: &str, spec: NodeSpec, hint: &str) -> PropsOut {
let mut p = PropsOut::new();
p.spec = spec.on_layout("laid");
p.key = Some(label.into());
p.apply_tooltip(hint);
p
}
fn hint_quad(core: &mut Core) -> Option<(Rect, Rect)> {
let raised = core.theme().raised;
let (dl, _) = core.output();
dl.quads
.iter()
.find(|q| q.kind == QuadKind::Solid && q.color == raised)
.map(|q| (q.rect, dl.clips[q.clip as usize].rect))
}
fn has_glyphs(core: &mut Core) -> bool {
core.output().0.quads.iter().any(|q| {
matches!(
q.kind,
QuadKind::GlyphColor | QuadKind::GlyphSubpixel | QuadKind::GlyphMask
)
})
}
fn assert_below(core: &mut Core, leaf: Key) -> (Rect, Rect) {
let l = core.layout_of(leaf).expect("the leaf is laid out");
let (t, clip) = hint_quad(core).expect("the hint floats");
assert_eq!(t.y, l.y + l.h + 6.0, "below the leaf's box: {l:?} {t:?}");
assert!(
((t.x + t.w / 2.0) - (l.x + l.w / 2.0)).abs() < 0.01,
"centred on the leaf's box: {l:?} {t:?}"
);
assert!(t.w > 0.0 && t.h > 0.0, "sized to its text: {t:?}");
(t, clip)
}
#[test]
fn a_hovered_wedge_floats_its_tooltip_below_its_box() {
let mut core = Core::new();
let pts = [
Vec2::new(100.0, 50.0),
Vec2::new(200.0, 50.0),
Vec2::new(150.0, 150.0),
];
let frame = |core: &mut Core| {
let mut ui = core.frame(VIEW, 1.0);
let p = tipped("wedge", NodeSpec::column().bg(Color::WHITE), "a wedge");
let key = ui.core().open_from(p, Content::Polygon(&pts));
ui.finish();
key
};
let key = frame(&mut core);
assert_eq!(hint_quad(&mut core), None, "not hovered: nothing floats");
assert!(!has_glyphs(&mut core));
hover(&mut core, Vec2::new(150.0, 70.0));
frame(&mut core);
assert_below(&mut core, key);
assert!(has_glyphs(&mut core), "and its text");
hover(&mut core, Vec2::new(105.0, 140.0));
frame(&mut core);
assert_eq!(hint_quad(&mut core), None, "outside the outline");
assert!(!has_glyphs(&mut core));
}
#[test]
fn a_paths_tooltip_escapes_the_clip_it_hangs_from() {
let mut core = Core::new();
let frame = |core: &mut Core| {
let mut ui = core.frame(VIEW, 1.0);
ui.open(NodeSpec::column().size(200.0, 95.0).clip());
let p = tipped("arrow", NodeSpec::column().bg(Color::WHITE), "an arrow");
let key = ui.core().open_from(
p,
Content::PathD("M 20 20 L 120 20 L 70 90 Z", FillRule::NonZero, None, None),
);
ui.close();
ui.finish();
key
};
let key = frame(&mut core);
assert_eq!(hint_quad(&mut core), None, "not hovered: nothing floats");
hover(&mut core, Vec2::new(70.0, 30.0));
frame(&mut core);
let (rect, clip) = assert_below(&mut core, key);
assert!(rect.y >= 95.0, "below the clipping box's edge: {rect:?}");
assert!(
clip.y + clip.h >= rect.y + rect.h,
"and not cut by it: {rect:?} in {clip:?}"
);
}
#[test]
fn a_lines_tooltip_floats_and_its_siblings_keep_their_keys() {
let mut core = Core::new();
let frame = |core: &mut Core| {
let mut ui = core.frame(VIEW, 1.0);
ui.line_keyed(
"link",
Vec2::new(40.0, 40.0),
Vec2::new(240.0, 40.0),
Stroke::new(2.0, Color::WHITE),
NodeSpec::column().tooltip("a link").on_layout("laid"),
);
let after = ui.leaf(NodeSpec::column().size(50.0, 20.0).on_layout("laid"));
ui.finish();
after
};
let after = frame(&mut core);
let line = Key::ROOT.str("link");
let placed = core.layout_of(after);
assert!(placed.is_some());
assert_eq!(hint_quad(&mut core), None, "not hovered: nothing floats");
hover(&mut core, Vec2::new(140.0, 40.0));
assert_eq!(frame(&mut core), after, "the next sibling's key is unmoved");
assert_below(&mut core, line);
assert_eq!(core.layout_of(after), placed, "and so is its place");
hover(&mut core, Vec2::new(140.0, 200.0));
frame(&mut core);
assert_eq!(hint_quad(&mut core), None, "unhovered: gone again");
}
#[test]
fn a_cells_grids_tooltip_floats_below_it() {
let mut core = Core::new();
let cells = vec![Cell::default(); 8 * 2];
let frame = |core: &mut Core| {
let mut ui = core.frame(VIEW, 1.0);
let grid = CellGrid {
rows: 2,
cols: 8,
cells: &cells,
style: TextStyle::new(14.0),
cursor: None,
origin_line: 0,
};
let p = tipped("term", NodeSpec::column(), "a terminal");
let key = ui.core().open_from(p, Content::Cells(&grid));
ui.finish();
key
};
let key = frame(&mut core);
assert_eq!(hint_quad(&mut core), None, "not hovered: nothing floats");
hover(&mut core, Vec2::new(5.0, 5.0));
frame(&mut core);
assert_below(&mut core, key);
}
#[test]
fn a_leafs_tooltip_flips_above_near_the_bottom() {
let mut core = Core::new();
let pts = [
Vec2::new(100.0, 250.0),
Vec2::new(200.0, 250.0),
Vec2::new(150.0, 295.0),
];
let frame = |core: &mut Core| {
let mut ui = core.frame(VIEW, 1.0);
let p = tipped("low", NodeSpec::column().bg(Color::WHITE), "low");
let key = ui.core().open_from(p, Content::Polygon(&pts));
ui.finish();
key
};
let key = frame(&mut core);
hover(&mut core, Vec2::new(150.0, 260.0));
frame(&mut core);
let l = core.layout_of(key).unwrap();
let (t, _) = hint_quad(&mut core).expect("the hint floats");
assert_eq!(t.y + t.h, l.y - 6.0, "above the leaf's box: {l:?} {t:?}");
}