1use crate::{
2 AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Result, Size, ViewContext,
3};
4use parking_lot::Mutex;
5use std::{marker::PhantomData, sync::Arc};
6use util::{arc_cow::ArcCow, ResultExt};
7
8impl<S: 'static> 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> 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> 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> Element for Text<S> {
46 type State = S;
47 type FrameState = Arc<Mutex<Option<TextFrameState>>>;
48
49 fn layout(
50 &mut self,
51 _view: &mut S,
52 cx: &mut ViewContext<S>,
53 ) -> Result<(LayoutId, Self::FrameState)> {
54 let text_system = cx.text_system().clone();
55 let text_style = cx.text_style();
56 let font_size = text_style.font_size * cx.rem_size();
57 let line_height = text_style
58 .line_height
59 .to_pixels(font_size.into(), cx.rem_size());
60 let text = self.text.clone();
61 let frame_state = Arc::new(Mutex::new(None));
62
63 let rem_size = cx.rem_size();
64 let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
65 let frame_state = frame_state.clone();
66 move |_, _| {
67 let Some(line_layout) = text_system
68 .layout_line(
69 text.as_ref(),
70 font_size,
71 &[(text.len(), text_style.to_run())],
72 )
73 .log_err()
74 else {
75 return Size::default();
76 };
77
78 let size = Size {
79 width: line_layout.width(),
80 height: line_height,
81 };
82
83 frame_state.lock().replace(TextFrameState {
84 line: Arc::new(line_layout),
85 line_height,
86 });
87
88 size
89 }
90 });
91
92 Ok((layout_id?, frame_state))
93 }
94
95 fn paint<'a>(
96 &mut self,
97 bounds: Bounds<Pixels>,
98 _: &mut Self::State,
99 frame_state: &mut Self::FrameState,
100 cx: &mut ViewContext<S>,
101 ) -> Result<()> {
102 let line;
103 let line_height;
104 {
105 let frame_state = frame_state.lock();
106 let frame_state = frame_state
107 .as_ref()
108 .expect("measurement has not been performed");
109 line = frame_state.line.clone();
110 line_height = frame_state.line_height;
111 }
112
113 // todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder.");
114 line.paint(bounds, bounds, line_height, cx)?;
115
116 Ok(())
117 }
118}
119
120pub struct TextFrameState {
121 line: Arc<Line>,
122 line_height: Pixels,
123}