1use crate::{
2 element::{Element, IntoElement, Layout},
3 ViewContext,
4};
5use anyhow::Result;
6use gpui::{
7 geometry::{vector::Vector2F, Size},
8 text_layout::LineLayout,
9 LayoutId,
10};
11use parking_lot::Mutex;
12use std::sync::Arc;
13use util::arc_cow::ArcCow;
14
15impl<V: 'static> IntoElement<V> for ArcCow<'static, str> {
16 type Element = Text;
17
18 fn into_element(self) -> Self::Element {
19 Text { text: self }
20 }
21}
22
23impl<V: 'static> IntoElement<V> for &'static str {
24 type Element = Text;
25
26 fn into_element(self) -> Self::Element {
27 Text {
28 text: ArcCow::from(self),
29 }
30 }
31}
32
33pub struct Text {
34 text: ArcCow<'static, str>,
35}
36
37impl<V: 'static> Element<V> for Text {
38 type PaintState = Arc<Mutex<Option<TextLayout>>>;
39
40 fn layout(
41 &mut self,
42 _view: &mut V,
43 cx: &mut ViewContext<V>,
44 ) -> Result<(LayoutId, Self::PaintState)> {
45 let fonts = cx.platform().fonts();
46 let text_style = cx.text_style();
47 let line_height = cx.font_cache().line_height(text_style.font_size);
48 let text = self.text.clone();
49 let paint_state = Arc::new(Mutex::new(None));
50
51 let layout_id = cx.add_measured_layout_node(Default::default(), {
52 let paint_state = paint_state.clone();
53 move |_params| {
54 let line_layout = fonts.layout_line(
55 text.as_ref(),
56 text_style.font_size,
57 &[(text.len(), text_style.to_run())],
58 );
59
60 let size = Size {
61 width: line_layout.width,
62 height: line_height,
63 };
64
65 paint_state.lock().replace(TextLayout {
66 line_layout: Arc::new(line_layout),
67 line_height,
68 });
69
70 size
71 }
72 });
73
74 Ok((layout_id?, paint_state))
75 }
76
77 fn paint<'a>(
78 &mut self,
79 _view: &mut V,
80 parent_origin: Vector2F,
81 layout: &Layout,
82 paint_state: &mut Self::PaintState,
83 cx: &mut ViewContext<V>,
84 ) {
85 let bounds = layout.bounds + parent_origin;
86
87 let line_layout;
88 let line_height;
89 {
90 let paint_state = paint_state.lock();
91 let paint_state = paint_state
92 .as_ref()
93 .expect("measurement has not been performed");
94 line_layout = paint_state.line_layout.clone();
95 line_height = paint_state.line_height;
96 }
97
98 let text_style = cx.text_style();
99 let line =
100 gpui::text_layout::Line::new(line_layout, &[(self.text.len(), text_style.to_run())]);
101
102 // TODO: We haven't added visible bounds to the new element system yet, so this is a placeholder.
103 let visible_bounds = bounds;
104 line.paint(bounds.origin(), visible_bounds, line_height, cx.legacy_cx);
105 }
106}
107
108impl<V: 'static> IntoElement<V> for Text {
109 type Element = Self;
110
111 fn into_element(self) -> Self::Element {
112 self
113 }
114}
115
116pub struct TextLayout {
117 line_layout: Arc<LineLayout>,
118 line_height: f32,
119}