text.rs

  1use crate::{
  2    AnyElement, Bounds, Element, IntoAnyElement, LayoutId, Line, Pixels, Size, ViewContext,
  3};
  4use parking_lot::Mutex;
  5use std::{marker::PhantomData, sync::Arc};
  6use util::{arc_cow::ArcCow, ResultExt};
  7
  8impl<S: 'static + Send + Sync> IntoAnyElement<S> for ArcCow<'static, str> {
  9    fn into_any(self) -> AnyElement<S> {
 10        Text {
 11            text: self,
 12            state_type: PhantomData,
 13        }
 14        .into_any()
 15    }
 16}
 17
 18impl<V: 'static + Send + Sync> IntoAnyElement<V> for &'static str {
 19    fn into_any(self) -> AnyElement<V> {
 20        Text {
 21            text: ArcCow::from(self),
 22            state_type: PhantomData,
 23        }
 24        .into_any()
 25    }
 26}
 27
 28pub struct Text<S> {
 29    text: ArcCow<'static, str>,
 30    state_type: PhantomData<S>,
 31}
 32
 33impl<S: 'static + Send + Sync> Element for Text<S> {
 34    type ViewState = S;
 35    type ElementState = Arc<Mutex<Option<TextElementState>>>;
 36
 37    fn element_id(&self) -> Option<crate::ElementId> {
 38        None
 39    }
 40
 41    fn layout(
 42        &mut self,
 43        _view: &mut S,
 44        _element_state: Option<Self::ElementState>,
 45        cx: &mut ViewContext<S>,
 46    ) -> (LayoutId, Self::ElementState) {
 47        let text_system = cx.text_system().clone();
 48        let text_style = cx.text_style();
 49        let font_size = text_style.font_size * cx.rem_size();
 50        let line_height = text_style
 51            .line_height
 52            .to_pixels(font_size.into(), cx.rem_size());
 53        let text = self.text.clone();
 54        let element_state = Arc::new(Mutex::new(None));
 55
 56        let rem_size = cx.rem_size();
 57        let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
 58            let element_state = element_state.clone();
 59            move |_, _| {
 60                let Some(line_layout) = text_system
 61                    .layout_line(
 62                        text.as_ref(),
 63                        font_size,
 64                        &[(text.len(), text_style.to_run())],
 65                    )
 66                    .log_err()
 67                else {
 68                    return Size::default();
 69                };
 70
 71                let size = Size {
 72                    width: line_layout.width(),
 73                    height: line_height,
 74                };
 75
 76                element_state.lock().replace(TextElementState {
 77                    line: Arc::new(line_layout),
 78                    line_height,
 79                });
 80
 81                size
 82            }
 83        });
 84
 85        (layout_id, element_state)
 86    }
 87
 88    fn paint<'a>(
 89        &mut self,
 90        bounds: Bounds<Pixels>,
 91        _: &mut Self::ViewState,
 92        element_state: &mut Self::ElementState,
 93        cx: &mut ViewContext<S>,
 94    ) {
 95        let line;
 96        let line_height;
 97        {
 98            let element_state = element_state.lock();
 99            let element_state = element_state
100                .as_ref()
101                .expect("measurement has not been performed");
102            line = element_state.line.clone();
103            line_height = element_state.line_height;
104        }
105
106        line.paint(bounds, bounds, line_height, cx).log_err();
107    }
108}
109
110pub struct TextElementState {
111    line: Arc<Line>,
112    line_height: Pixels,
113}