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