1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
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,
};