text.rs

  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}