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
28// TODO: Figure out how to pass `String` to `child` without this.
29// This impl doesn't exist in the `gpui2` crate.
30impl<S: 'static + Send + Sync> IntoAnyElement<S> for String {
31 fn into_any(self) -> AnyElement<S> {
32 Text {
33 text: ArcCow::from(self),
34 state_type: PhantomData,
35 }
36 .into_any()
37 }
38}
39
40pub struct Text<S> {
41 text: ArcCow<'static, str>,
42 state_type: PhantomData<S>,
43}
44
45impl<S: 'static + Send + Sync> IntoAnyElement<S> for Text<S> {
46 fn into_any(self) -> AnyElement<S> {
47 AnyElement::new(self)
48 }
49}
50
51impl<S: 'static + Send + Sync> Element for Text<S> {
52 type ViewState = S;
53 type ElementState = Arc<Mutex<Option<TextElementState>>>;
54
55 fn element_id(&self) -> Option<crate::ElementId> {
56 None
57 }
58
59 fn layout(
60 &mut self,
61 _view: &mut S,
62 _element_state: Option<Self::ElementState>,
63 cx: &mut ViewContext<S>,
64 ) -> (LayoutId, Self::ElementState) {
65 let text_system = cx.text_system().clone();
66 let text_style = cx.text_style();
67 let font_size = text_style.font_size * cx.rem_size();
68 let line_height = text_style
69 .line_height
70 .to_pixels(font_size.into(), cx.rem_size());
71 let text = self.text.clone();
72 let element_state = Arc::new(Mutex::new(None));
73
74 let rem_size = cx.rem_size();
75 let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
76 let element_state = element_state.clone();
77 move |known_dimensions, _| {
78 let Some(line_layout) = text_system
79 .layout_text(
80 text.as_ref(),
81 font_size,
82 &[(text.len(), text_style.to_run())],
83 known_dimensions.width, // Wrap if we know the width.
84 )
85 .log_err()
86 else {
87 return Size::default();
88 };
89
90 let size = Size {
91 width: line_layout.width(),
92 height: line_height,
93 };
94
95 element_state.lock().replace(TextElementState {
96 line: Arc::new(line_layout),
97 line_height,
98 });
99
100 size
101 }
102 });
103
104 (layout_id, element_state)
105 }
106
107 fn paint<'a>(
108 &mut self,
109 bounds: Bounds<Pixels>,
110 _: &mut Self::ViewState,
111 element_state: &mut Self::ElementState,
112 cx: &mut ViewContext<S>,
113 ) {
114 let line;
115 let line_height;
116 {
117 let element_state = element_state.lock();
118 let element_state = element_state
119 .as_ref()
120 .expect("measurement has not been performed");
121 line = element_state.line.clone();
122 line_height = element_state.line_height;
123 }
124
125 line.paint(bounds, bounds, line_height, cx).log_err();
126 }
127}
128
129pub struct TextElementState {
130 line: Arc<Line>,
131 line_height: Pixels,
132}