nightshade 0.8.0

A cross-platform data-oriented game engine.
Documentation
use crate::prelude::*;

pub struct DroppedFile {
    pub path: Option<std::path::PathBuf>,
    pub name: String,
    pub bytes: Option<std::sync::Arc<[u8]>>,
}

pub fn get_dropped_files(ui_context: &egui::Context) -> Vec<DroppedFile> {
    ui_context.input(|input| {
        input
            .raw
            .dropped_files
            .iter()
            .map(|file| DroppedFile {
                path: file.path.clone(),
                name: file.name.clone(),
                bytes: file.bytes.clone(),
            })
            .collect()
    })
}

pub fn is_file_hovering(ui_context: &egui::Context) -> bool {
    ui_context.input(|input| !input.raw.hovered_files.is_empty())
}

pub fn render_drop_overlay(ui_context: &egui::Context, message: &str) {
    if !is_file_hovering(ui_context) {
        return;
    }

    let screen_rect = ui_context.content_rect();
    egui::Area::new(egui::Id::new("drop_overlay"))
        .fixed_pos(screen_rect.min)
        .order(egui::Order::Foreground)
        .show(ui_context, |ui| {
            let painter = ui.painter();
            painter.rect_filled(screen_rect, 0.0, egui::Color32::from_black_alpha(160));

            painter.text(
                screen_rect.center(),
                egui::Align2::CENTER_CENTER,
                message,
                egui::FontId::proportional(24.0),
                egui::Color32::WHITE,
            );
        });
}

pub struct FileCategory {
    pub extensions: &'static [&'static str],
    pub suffixes: &'static [&'static str],
    pub name: &'static str,
}

pub fn categorize_file<'a>(
    path: &std::path::Path,
    categories: &'a [FileCategory],
) -> Option<&'a str> {
    let extension = path
        .extension()
        .and_then(|extension| extension.to_str())
        .map(|extension| extension.to_lowercase());
    let filename_lower = path.to_string_lossy().to_lowercase();

    for category in categories {
        for suffix in category.suffixes {
            if filename_lower.ends_with(suffix) {
                return Some(category.name);
            }
        }
        if let Some(ref extension) = extension {
            for category_extension in category.extensions {
                if extension == *category_extension {
                    return Some(category.name);
                }
            }
        }
    }
    None
}

pub fn render_drop_overlay_with_category(
    ui_context: &egui::Context,
    category: Option<&str>,
    messages: &[(&str, &str)],
    default_message: &str,
) {
    let message = category
        .and_then(|category| {
            messages
                .iter()
                .find(|(name, _)| *name == category)
                .map(|(_, message)| *message)
        })
        .unwrap_or(default_message);

    egui::Area::new(egui::Id::new("drop_indicator"))
        .anchor(egui::Align2::CENTER_CENTER, [0.0, 0.0])
        .show(ui_context, |ui| {
            ui.with_layout(egui::Layout::top_down(egui::Align::Center), |ui| {
                let frame = egui::Frame::default()
                    .fill(egui::Color32::from_rgba_premultiplied(30, 30, 30, 200))
                    .corner_radius(10.0)
                    .stroke(egui::Stroke::new(
                        2.0,
                        egui::Color32::from_rgb(100, 150, 250),
                    ))
                    .inner_margin(30.0);

                frame.show(ui, |ui| {
                    ui.heading(message);
                });
            });
        });
}