Skip to content
Snippets Groups Projects
text.rs 3.33 KiB
Newer Older
use kayak_core::{styles::Units, Binding, Bound, CursorIcon};
StarArawn's avatar
StarArawn committed
use kayak_font::{CoordinateSystem, KayakFont};

StarArawn's avatar
StarArawn committed
    render_command::RenderCommand,
    styles::{Style, StyleProp},
MrGVSV's avatar
MrGVSV committed
    widget, OnEvent, WidgetProps,
StarArawn's avatar
StarArawn committed
};

MrGVSV's avatar
MrGVSV committed
/// PRops used by the [`Text`] widget
#[derive(WidgetProps, Default, Debug, PartialEq, Clone)]
pub struct TextProps {
MrGVSV's avatar
MrGVSV committed
    /// The string to display
    pub content: String,
MrGVSV's avatar
MrGVSV committed
    /// The name of the font to use
    ///
    /// The given font must already be loaded into the [`KayakContext`](kayak_core::KayakContext)
    pub font: Option<String>,
MrGVSV's avatar
MrGVSV committed
    /// The height of a line of text (currently in pixels)
    pub line_height: Option<f32>,
MrGVSV's avatar
MrGVSV committed
    /// The font size (in pixels)
    pub size: f32,
    #[prop_field(Styles)]
    pub styles: Option<Style>,
    #[prop_field(OnEvent)]
    pub on_event: Option<OnEvent>,
    #[prop_field(Focusable)]
    pub focusable: Option<bool>,
}

StarArawn's avatar
StarArawn committed
#[widget]
MrGVSV's avatar
MrGVSV committed
/// A widget that renders plain text
///
/// # Props
///
/// __Type:__ [`TextProps`]
///
/// | Common Prop | Accepted |
/// | :---------: | :------: |
/// | `children`  | ❌        |
/// | `styles`    | ✅        |
/// | `on_event`  | ✅        |
/// | `focusable` | ✅        |
///
pub fn Text(props: TextProps) {
MrGVSV's avatar
MrGVSV committed
    let TextProps {
        content,
        font,
        line_height,
        size,
        ..
    } = props.clone();
StarArawn's avatar
StarArawn committed
    let font_name = font;
    let font: Binding<Option<KayakFont>> =
        context.get_asset(font_name.clone().unwrap_or("Roboto".into()));

    context.bind(&font);

StarArawn's avatar
StarArawn committed
    let mut should_render = true;

StarArawn's avatar
StarArawn committed
    // TODO: It might be worth caching the measurement here until content changes.
    let (layout_size, parent_size) =
        if let Some(parent_id) = context.get_valid_parent(parent_id.unwrap()) {
            if let Some(layout) = context.get_layout(&parent_id) {
StarArawn's avatar
StarArawn committed
                if let Some(font) = font.get() {
                    let measurement = font.measure(
                        CoordinateSystem::PositiveYDown,
                        &content,
                        size,
StarArawn's avatar
StarArawn committed
                        line_height.unwrap_or(size * 1.2),
StarArawn's avatar
StarArawn committed
                        (layout.width, layout.height),
                    );
                    (measurement, (layout.width, layout.height))
                } else {
StarArawn's avatar
StarArawn committed
                    should_render = false;
StarArawn's avatar
StarArawn committed
                    ((0.0, 0.0), (layout.width, layout.height))
                }
            } else {
StarArawn's avatar
StarArawn committed
                should_render = false;
StarArawn's avatar
StarArawn committed
                ((0.0, 0.0), (0.0, 0.0))
            }
        } else {
StarArawn's avatar
StarArawn committed
            should_render = false;
StarArawn's avatar
StarArawn committed
            ((0.0, 0.0), (0.0, 0.0))
        };

StarArawn's avatar
StarArawn committed
    if should_render {
        let render_command = RenderCommand::Text {
            content: content.clone(),
            size,
            parent_size,
            line_height: line_height.unwrap_or(size * 1.2),
            font: font_name.clone().unwrap_or("Roboto".into()),
        };
StarArawn's avatar
StarArawn committed

        let styles = props.styles.clone().unwrap_or_default();
StarArawn's avatar
StarArawn committed
        props.styles = Some(Style {
            render_command: StyleProp::Value(render_command),
            width: StyleProp::Value(Units::Pixels(layout_size.0)),
            height: StyleProp::Value(Units::Pixels(layout_size.1)),
MrGVSV's avatar
MrGVSV committed
            cursor: StyleProp::select(&[&styles.cursor, &StyleProp::Value(CursorIcon::Text)])
                .clone(),
            ..styles
StarArawn's avatar
StarArawn committed
        });
    } else {
        context.mark_dirty();
StarArawn's avatar
StarArawn committed
    }
StarArawn's avatar
StarArawn committed
}