use super::super::*;
pub(super) fn to_winit_cursor(c: Option<llimphi_compositor::Cursor>) -> llimphi_hal::winit::window::CursorIcon {
use llimphi_compositor::Cursor as C;
use llimphi_hal::winit::window::CursorIcon as I;
match c {
None | Some(C::Default) => I::Default,
Some(C::Pointer) => I::Pointer,
Some(C::Text) => I::Text,
Some(C::Crosshair) => I::Crosshair,
Some(C::Move) => I::Move,
Some(C::Grab) => I::Grab,
Some(C::Grabbing) => I::Grabbing,
Some(C::NotAllowed) => I::NotAllowed,
Some(C::Wait) => I::Wait,
Some(C::Progress) => I::Progress,
Some(C::Help) => I::Help,
Some(C::ColResize) => I::ColResize,
Some(C::RowResize) => I::RowResize,
Some(C::EwResize) => I::EwResize,
Some(C::NsResize) => I::NsResize,
Some(C::NeswResize) => I::NeswResize,
Some(C::NwseResize) => I::NwseResize,
Some(C::ZoomIn) => I::ZoomIn,
Some(C::ZoomOut) => I::ZoomOut,
}
}
pub(super) fn scale_hit_from_cache<Msg: Clone>(
cache: &RenderCache<Msg>,
x: f32,
y: f32,
) -> Option<(ScaleFn<Msg>, f32, f32)> {
let (m, c) = match cache.overlay.as_ref() {
Some(ov) => (&ov.mounted, &ov.computed),
None => (&cache.mounted, &cache.computed),
};
hit_test_scale(m, c, x, y).and_then(|i| {
let node = &m.nodes[i];
node.on_scale.clone().map(|h| {
let (fx, fy) = c
.get(node.id)
.map(|r| (x - r.x, y - r.y))
.unwrap_or((0.0, 0.0));
(h, fx, fy)
})
})
}
pub(super) fn rotate_hit_from_cache<Msg: Clone>(
cache: &RenderCache<Msg>,
x: f32,
y: f32,
) -> Option<(RotateFn<Msg>, f32, f32)> {
let (m, c) = match cache.overlay.as_ref() {
Some(ov) => (&ov.mounted, &ov.computed),
None => (&cache.mounted, &cache.computed),
};
hit_test_rotate(m, c, x, y).and_then(|i| {
let node = &m.nodes[i];
node.on_rotate.clone().map(|h| {
let (fx, fy) = c
.get(node.id)
.map(|r| (x - r.x, y - r.y))
.unwrap_or((0.0, 0.0));
(h, fx, fy)
})
})
}
pub(super) fn double_tap_hit_from_cache<Msg: Clone>(
cache: &RenderCache<Msg>,
x: f32,
y: f32,
) -> Option<GestureResolved<Msg>> {
let (m, c) = match cache.overlay.as_ref() {
Some(ov) => (&ov.mounted, &ov.computed),
None => (&cache.mounted, &cache.computed),
};
hit_test_double_tap(m, c, x, y).and_then(|i| {
let node = &m.nodes[i];
let (rx, ry, rw, rh) = c.get(node.id).map(|r| (r.x, r.y, r.w, r.h)).unwrap_or_default();
if let Some(h) = node.on_double_tap_at.clone() {
Some(GestureResolved::At(h, x - rx, y - ry, rw, rh))
} else {
node.on_double_tap.clone().map(GestureResolved::Direct)
}
})
}
pub(super) fn long_press_hit_from_cache<Msg: Clone>(
cache: &RenderCache<Msg>,
x: f32,
y: f32,
) -> Option<GestureResolved<Msg>> {
let (m, c) = match cache.overlay.as_ref() {
Some(ov) => (&ov.mounted, &ov.computed),
None => (&cache.mounted, &cache.computed),
};
hit_test_long_press(m, c, x, y).and_then(|i| {
let node = &m.nodes[i];
let (rx, ry, rw, rh) = c.get(node.id).map(|r| (r.x, r.y, r.w, r.h)).unwrap_or_default();
if let Some(h) = node.on_long_press_at.clone() {
Some(GestureResolved::At(h, x - rx, y - ry, rw, rh))
} else {
node.on_long_press.clone().map(GestureResolved::Direct)
}
})
}
pub(super) fn ripple_hit_from_cache<Msg: Clone>(
cache: &RenderCache<Msg>,
x: f32,
y: f32,
) -> Option<(llimphi_compositor::Ripple, f32, f32)> {
let (m, c) = match cache.overlay.as_ref() {
Some(ov) => (&ov.mounted, &ov.computed),
None => (&cache.mounted, &cache.computed),
};
hit_test_ripple(m, c, x, y).and_then(|i| {
let node = &m.nodes[i];
node.ripple.map(|rp| {
let (rx, ry) = c.get(node.id).map(|r| (r.x, r.y)).unwrap_or_default();
(rp, x - rx, y - ry)
})
})
}
pub(super) type AbsRect = (f32, f32, f32, f32);
pub(super) fn spec_is_uniform(spec: &llimphi_compositor::TextSpec) -> bool {
spec.runs.is_none() && spec.spans.is_none()
}
pub(super) fn selectable_hit_from_cache<Msg: Clone>(
cache: &RenderCache<Msg>,
x: f32,
y: f32,
) -> Option<(u64, llimphi_compositor::TextSpec, AbsRect)> {
let (m, c) = match cache.overlay.as_ref() {
Some(ov) => (&ov.mounted, &ov.computed),
None => (&cache.mounted, &cache.computed),
};
let i = hit_test_selectable(m, c, x, y)?;
let node = &m.nodes[i];
let key = node.text_select_key?;
let spec = node.text.as_ref()?;
if !spec_is_uniform(spec) {
return None;
}
let r = c.get(node.id)?;
Some((key, spec.clone(), (r.x, r.y, r.w, r.h)))
}
pub(super) fn selectable_by_key<Msg>(
cache: &RenderCache<Msg>,
key: u64,
) -> Option<(llimphi_compositor::TextSpec, AbsRect)> {
let trees = [
cache.overlay.as_ref().map(|ov| (&ov.mounted, &ov.computed)),
Some((&cache.mounted, &cache.computed)),
];
trees
.into_iter()
.flatten()
.find_map(|(m, c)| selectable_node_in(m, c, key))
}
pub(super) fn selectable_node_in<Msg>(
m: &Mounted<Msg>,
c: &ComputedLayout,
key: u64,
) -> Option<(llimphi_compositor::TextSpec, AbsRect)> {
for node in &m.nodes {
if node.text_select_key == Some(key) {
let spec = node.text.as_ref()?;
if !spec_is_uniform(spec) {
return None;
}
let r = c.get(node.id)?;
return Some((spec.clone(), (r.x, r.y, r.w, r.h)));
}
}
None
}
pub(super) fn build_selectable_layout(
ts: &mut llimphi_text::Typesetter,
spec: &llimphi_compositor::TextSpec,
width: f32,
) -> llimphi_text::parley::Layout<()> {
ts.layout(
&spec.content,
spec.size_px,
Some(width),
spec.alignment,
spec.line_height,
spec.italic,
spec.font_family.as_deref(),
spec.weight,
spec.underline,
spec.strikethrough,
spec.letter_spacing,
spec.word_spacing,
)
}
pub(super) fn key_is_char(key: &Key, c: char) -> bool {
matches!(
key,
Key::Character(s) if s.chars().next().map(|k| k.eq_ignore_ascii_case(&c)).unwrap_or(false)
)
}
#[cfg(feature = "clipboard")]
pub(super) fn copy_to_clipboard(text: &str) {
if let Ok(mut cb) = arboard::Clipboard::new() {
let _ = cb.set_text(text.to_string());
}
}
#[cfg(not(feature = "clipboard"))]
pub(super) fn copy_to_clipboard(_text: &str) {}
pub(super) fn resolve_layout_builders<A: App>(
model: &A::Model,
viewport: (f32, f32),
ts: &mut llimphi_text::Typesetter,
) -> View<A::Msg> {
let view = A::view(model);
if !has_layout_builder(&view) {
return view;
}
let mut l1 = LayoutTree::new();
let m1: Mounted<A::Msg> = mount(&mut l1, view);
let c1 = {
let tmap = &m1.text_measures;
l1.compute_with_measure(m1.root, viewport, |nid, known, avail| {
match tmap.get(&nid) {
Some(tm) => measure_text_node(ts, tm, known, avail),
None => llimphi_layout::taffy::Size::ZERO,
}
})
.expect("layout layout_builder pasada 1")
};
let cons = collect_builder_constraints(&m1, &c1);
expand_layout_builders(A::view(model), &cons)
}