cranpose_ui/widgets/
clickable_text.rs1#![expect(non_snake_case)]
7
8use std::rc::Rc;
9
10use cranpose_core::NodeId;
11
12use crate::{
13 modifier::Modifier,
14 text::{AnnotatedString, TextOverflow, TextStyle},
15 widgets::BasicText,
16};
17
18#[doc(hidden)]
19pub trait IntoSharedAnnotatedString {
20 fn into_shared(self) -> Rc<AnnotatedString>;
21}
22
23impl IntoSharedAnnotatedString for AnnotatedString {
24 fn into_shared(self) -> Rc<AnnotatedString> {
25 Rc::new(self)
26 }
27}
28
29impl IntoSharedAnnotatedString for Rc<AnnotatedString> {
30 fn into_shared(self) -> Rc<AnnotatedString> {
31 self
32 }
33}
34
35pub fn ClickableText<T>(
54 text: T,
55 modifier: Modifier,
56 style: TextStyle,
57 on_click: impl Fn(usize) + 'static,
58) -> NodeId
59where
60 T: IntoSharedAnnotatedString,
61{
62 let text = text.into_shared();
63 let text_for_click = text.clone();
64 let style_for_click = style.clone();
65 let on_click: Rc<dyn Fn(usize)> = Rc::new(on_click);
66
67 let clickable_modifier = modifier.clickable(move |point| {
68 let offset = crate::text::get_offset_for_position(
69 &text_for_click,
70 &style_for_click,
71 point.x,
72 point.y,
73 );
74 on_click(offset);
75 });
76
77 BasicText(
78 text,
79 clickable_modifier,
80 style,
81 TextOverflow::Clip,
82 true,
83 usize::MAX,
84 1,
85 )
86}
87
88#[cfg(test)]
89#[path = "tests/clickable_text_tests.rs"]
90mod tests;