text.rs

  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}