1use crate::{
2 AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Size, ViewContext,
3};
4use parking_lot::Mutex;
5use std::{marker::PhantomData, sync::Arc};
6use util::{arc_cow::ArcCow, ResultExt};
7
8impl<S: 'static + Send + Sync> IntoAnyElement<S> for ArcCow<'static, str> {
9 fn into_any(self) -> AnyElement<S> {
10 Text {
11 text: self,
12 state_type: PhantomData,
13 }
14 .into_any()
15 }
16}
17
18impl<V: 'static + Send + Sync> IntoAnyElement<V> for &'static str {
19 fn into_any(self) -> AnyElement<V> {
20 Text {
21 text: ArcCow::from(self),
22 state_type: PhantomData,
23 }
24 .into_any()
25 }
26}
27
28pub struct Text<S> {
29 text: ArcCow<'static, str>,
30 state_type: PhantomData<S>,
31}
32
33impl<S: 'static + Send + Sync> Element for Text<S> {
34 type ViewState = S;
35 type ElementState = Arc<Mutex<Option<TextElementState>>>;
36
37 fn element_id(&self) -> Option<crate::ElementId> {
38 None
39 }
40
41 fn layout(
42 &mut self,
43 _view: &mut S,
44 _element_state: Option<Self::ElementState>,
45 cx: &mut ViewContext<S>,
46 ) -> (LayoutId, Self::ElementState) {
47 let text_system = cx.text_system().clone();
48 let text_style = cx.text_style();
49 let font_size = text_style.font_size * cx.rem_size();
50 let line_height = text_style
51 .line_height
52 .to_pixels(font_size.into(), cx.rem_size());
53 let text = self.text.clone();
54 let element_state = Arc::new(Mutex::new(None));
55
56 let rem_size = cx.rem_size();
57 let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
58 let element_state = element_state.clone();
59 move |_, _| {
60 let Some(line_layout) = text_system
61 .layout_line(
62 text.as_ref(),
63 font_size,
64 &[(text.len(), text_style.to_run())],
65 )
66 .log_err()
67 else {
68 return Size::default();
69 };
70
71 let size = Size {
72 width: line_layout.width(),
73 height: line_height,
74 };
75
76 element_state.lock().replace(TextElementState {
77 line: Arc::new(line_layout),
78 line_height,
79 });
80
81 size
82 }
83 });
84
85 (layout_id, element_state)
86 }
87
88 fn paint<'a>(
89 &mut self,
90 bounds: Bounds<Pixels>,
91 _: &mut Self::ViewState,
92 element_state: &mut Self::ElementState,
93 cx: &mut ViewContext<S>,
94 ) {
95 let line;
96 let line_height;
97 {
98 let element_state = element_state.lock();
99 let element_state = element_state
100 .as_ref()
101 .expect("measurement has not been performed");
102 line = element_state.line.clone();
103 line_height = element_state.line_height;
104 }
105
106 line.paint(bounds, bounds, line_height, cx).log_err();
107 }
108}
109
110pub struct TextElementState {
111 line: Arc<Line>,
112 line_height: Pixels,
113}