text.rs

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