nightshade 0.8.2

A cross-platform data-oriented game engine.
Documentation
use std::collections::VecDeque;

use crate::prelude::*;

pub struct EventLogEntry {
    pub time: f32,
    pub message: String,
    pub category: String,
}

pub struct EventLog {
    entries: VecDeque<EventLogEntry>,
    max_entries: usize,
    elapsed_time: f32,
}

impl EventLog {
    pub fn new(max_entries: usize) -> Self {
        Self {
            entries: VecDeque::new(),
            max_entries,
            elapsed_time: 0.0,
        }
    }

    pub fn log(&mut self, category: impl Into<String>, message: impl Into<String>) {
        self.entries.push_back(EventLogEntry {
            time: self.elapsed_time,
            message: message.into(),
            category: category.into(),
        });
        if self.entries.len() > self.max_entries {
            self.entries.pop_front();
        }
    }

    pub fn tick(&mut self, delta_time: f32) {
        self.elapsed_time += delta_time;
    }

    pub fn elapsed_time(&self) -> f32 {
        self.elapsed_time
    }

    pub fn entries(&self) -> &VecDeque<EventLogEntry> {
        &self.entries
    }

    pub fn len(&self) -> usize {
        self.entries.len()
    }

    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    pub fn clear(&mut self) {
        self.entries.clear();
    }

    pub fn render(&self, ui: &mut egui::Ui, category_color: impl Fn(&str) -> egui::Color32) {
        ui.vertical(|ui| {
            ui.add_space(4.0);

            ui.horizontal(|ui| {
                ui.strong("Event Log");
                ui.label(format!("({})", self.entries.len()));
            });

            ui.separator();

            egui::ScrollArea::vertical()
                .stick_to_bottom(true)
                .show(ui, |ui| {
                    if self.entries.is_empty() {
                        ui.label("No events recorded");
                        return;
                    }

                    for entry in &self.entries {
                        let total_seconds = entry.time as u64;
                        let minutes = total_seconds / 60;
                        let seconds = total_seconds % 60;
                        let tenths = ((entry.time - entry.time.floor()) * 10.0) as u32;
                        let timestamp = format!("{:02}:{:02}.{}", minutes, seconds, tenths);

                        let color = category_color(&entry.category);

                        ui.horizontal(|ui| {
                            ui.monospace(
                                egui::RichText::new(format!("[{}]", timestamp))
                                    .color(egui::Color32::from_rgb(120, 120, 120)),
                            );
                            ui.monospace(egui::RichText::new(&entry.category).color(color));
                            ui.label(&entry.message);
                        });
                    }
                });
        });
    }
}