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