macroquad 0.4.14

Simple and easy to use graphics library
Documentation
use crate::{
    math::{vec2, Vec2},
    ui::{widgets::Editbox, ElementState, Id, Layout, Ui, UiContent},
};

pub struct InputText<'a> {
    id: Id,
    label: &'a str,
    size: Option<Vec2>,
    password: bool,
    numbers: bool,
    ratio: f32,
    pos: Option<Vec2>,
    margin: Option<Vec2>,
}

impl<'a> InputText<'a> {
    pub const fn new(id: Id) -> InputText<'a> {
        InputText {
            id,
            size: None,
            label: "",
            numbers: false,
            password: false,
            ratio: 0.5,
            pos: None,
            margin: None,
        }
    }

    pub const fn label<'b>(self, label: &'b str) -> InputText<'b> {
        InputText {
            id: self.id,
            size: self.size,
            label,
            numbers: self.numbers,
            password: self.password,
            ratio: self.ratio,
            pos: self.pos,
            margin: self.margin,
        }
    }

    pub const fn size(self, size: Vec2) -> Self {
        Self {
            size: Some(size),
            ..self
        }
    }

    pub const fn position(self, pos: Vec2) -> Self {
        Self {
            pos: Some(pos),
            ..self
        }
    }

    pub const fn password(self, password: bool) -> Self {
        Self { password, ..self }
    }

    pub const fn ratio(self, ratio: f32) -> Self {
        Self { ratio, ..self }
    }

    pub const fn filter_numbers(self) -> Self {
        Self {
            numbers: true,
            ..self
        }
    }

    pub const fn margin(self, margin: Vec2) -> Self {
        Self {
            margin: Some(margin),
            ..self
        }
    }

    pub fn ui(self, ui: &mut Ui, data: &mut String) {
        let context = ui.get_active_window_context();

        let label_size = context.window.painter.content_with_margins_size(
            &context.style.editbox_style,
            &UiContent::Label((&*data).into()),
        );

        let size = self.size.unwrap_or(vec2(
            context.window.cursor.area.w - context.style.margin * 2. - context.window.cursor.ident,
            label_size.y.max(19.),
        ));

        let pos = self
            .pos
            .map(|pos| pos + context.window.cursor.fit(size, Layout::Vertical))
            .unwrap_or_else(|| context.window.cursor.fit(size, Layout::Vertical));

        let editbox_area_w = if self.label.is_empty() {
            size.x
        } else {
            size.x * self.ratio - 15.
        };
        let mut editbox = Editbox::new(self.id, Vec2::new(editbox_area_w, size.y))
            .password(self.password)
            .position(pos)
            .multiline(false);

        if let Some(margin) = self.margin {
            editbox = editbox.margin(margin);
        }

        if self.numbers {
            editbox = editbox.filter(&|character| {
                character.is_digit(10) || character == '.' || character == '-'
            });
        }
        editbox.ui(ui, data);

        let context = ui.get_active_window_context();

        if self.label.is_empty() == false {
            context.window.painter.draw_element_label(
                &context.style.label_style,
                Vec2::new(pos.x + size.x * self.ratio, pos.y),
                self.label,
                ElementState {
                    focused: context.focused,
                    ..Default::default()
                },
            );
        }
    }
}

impl Ui {
    pub fn input_text(&mut self, id: Id, label: &str, data: &mut String) {
        InputText::new(id).label(label).ui(self, data);
    }

    pub fn input_password(&mut self, id: Id, label: &str, data: &mut String) {
        InputText::new(id)
            .label(label)
            .password(true)
            .ui(self, data);
    }
}