paddle 0.1.0-beta.1

2D Game Engine for Rust on the Web
Documentation
use crate::*;
use crate::{error::NutsCheck, quicksilver_compat::*};
use chrono::*;

const ERROR_COLOR: Color = Color {
    r: 0.8,
    g: 0.2,
    b: 0.2,
    a: 0.75,
};

struct TextMessage {
    float: FloatingText,
    show_until: NaiveDateTime,
}

#[derive(Default)]
pub struct TextBoard {
    messages: Vec<TextMessage>,
    region: Rectangle,
}

impl TextBoard {
    pub(crate) fn init(region: Rectangle) {
        let tb = TextBoard {
            messages: vec![],
            region,
        };
        let tb_id = nuts::new_activity(tb);
        tb_id.private_channel(|tb, msg: TextMessage| {
            tb.messages.push(msg);
        });
        tb_id.subscribe(|tb, _msg: &DrawWorld| {
            tb.draw().nuts_check();
        });
    }
    pub fn display_error_message(msg: String) -> PaddleResult<()> {
        Self::display_message(msg, ERROR_COLOR, 3_000_000)
    }
    pub fn display_custom_message(msg: String, col: Color, time_ms: i64) -> PaddleResult<()> {
        Self::display_message(msg, col, time_ms * 1000)
    }
    #[allow(dead_code)]
    pub fn display_debug_message(msg: String) -> PaddleResult<()> {
        Self::display_message(msg, PADDLE_GREY, 8_000_000)
    }
    fn display_message(msg: String, col: Color, time_us: i64) -> PaddleResult<()> {
        let show_until = crate::utc_now() + Duration::microseconds(time_us);
        let float = Self::new_float(msg, col)?;
        nuts::send_to::<TextBoard, _>(TextMessage { float, show_until });
        Ok(())
    }
    fn draw(&mut self) -> PaddleResult<()> {
        self.remove_old_messages();
        let mut area = self.region;
        for msg in self.messages.iter_mut() {
            let (line, rest) = area.cut_horizontal(60.0);
            let (_padding, rest) = rest.cut_horizontal(15.0);
            area = rest;
            msg.float.update_position(&line, 0)?;
            msg.float.draw();
        }
        Ok(())
    }
    fn remove_old_messages(&mut self) {
        let now = crate::utc_now();
        self.messages.retain(|msg| msg.show_until > now);
    }
    fn new_float(s: String, col: Color) -> PaddleResult<FloatingText> {
        let col_str = color_string(&col);
        FloatingText::new_styled(
            &Rectangle::default(),
            s,
            &[
                ("background-color", &col_str),
                ("color", "white"),
                ("padding", "5px"),
                ("text-align", "center"),
            ],
            &[],
        )
    }
}

fn color_string(col: &Color) -> String {
    format!(
        "rgba({},{},{},{})",
        col.r * 255.0,
        col.g * 255.0,
        col.b * 255.0,
        col.a,
    )
}

pub const PADDLE_GREY: Color = Color {
    r: 0.75,
    g: 0.75,
    b: 0.75,
    a: 1.0,
};