nightshade 0.8.0

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

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct KeyBinding {
    pub key: egui::Key,
    pub modifiers: egui::Modifiers,
}

impl KeyBinding {
    pub fn new(key: egui::Key) -> Self {
        Self {
            key,
            modifiers: egui::Modifiers::NONE,
        }
    }

    pub fn ctrl(key: egui::Key) -> Self {
        Self {
            key,
            modifiers: egui::Modifiers::CTRL,
        }
    }

    pub fn shift(key: egui::Key) -> Self {
        Self {
            key,
            modifiers: egui::Modifiers::SHIFT,
        }
    }

    pub fn ctrl_shift(key: egui::Key) -> Self {
        Self {
            key,
            modifiers: egui::Modifiers {
                ctrl: true,
                shift: true,
                ..Default::default()
            },
        }
    }

    pub fn alt(key: egui::Key) -> Self {
        Self {
            key,
            modifiers: egui::Modifiers::ALT,
        }
    }

    pub fn display_name(&self) -> String {
        let mut parts = Vec::new();
        if self.modifiers.ctrl {
            parts.push("Ctrl");
        }
        if self.modifiers.shift {
            parts.push("Shift");
        }
        if self.modifiers.alt {
            parts.push("Alt");
        }
        parts.push(key_display_name(self.key));
        parts.join("+")
    }

    pub fn is_pressed(&self, ui_context: &egui::Context) -> bool {
        ui_context.input(|input| {
            input.key_pressed(self.key) && input.modifiers.matches_exact(self.modifiers)
        })
    }
}

pub struct ShortcutEntry {
    pub name: String,
    pub binding: KeyBinding,
    pub action: Box<dyn FnMut() + Send>,
}

pub struct ShortcutManager {
    shortcuts: Vec<ShortcutEntry>,
}

impl ShortcutManager {
    pub fn new() -> Self {
        Self {
            shortcuts: Vec::new(),
        }
    }

    pub fn register(
        &mut self,
        name: impl Into<String>,
        binding: KeyBinding,
        action: impl FnMut() + Send + 'static,
    ) {
        self.shortcuts.push(ShortcutEntry {
            name: name.into(),
            binding,
            action: Box::new(action),
        });
    }

    pub fn process(&mut self, ui_context: &egui::Context) {
        for entry in &mut self.shortcuts {
            if entry.binding.is_pressed(ui_context) {
                (entry.action)();
            }
        }
    }

    pub fn shortcuts(&self) -> &[ShortcutEntry] {
        &self.shortcuts
    }
}

impl Default for ShortcutManager {
    fn default() -> Self {
        Self::new()
    }
}

fn key_display_name(key: egui::Key) -> &'static str {
    match key {
        egui::Key::A => "A",
        egui::Key::B => "B",
        egui::Key::C => "C",
        egui::Key::D => "D",
        egui::Key::E => "E",
        egui::Key::F => "F",
        egui::Key::G => "G",
        egui::Key::H => "H",
        egui::Key::I => "I",
        egui::Key::J => "J",
        egui::Key::K => "K",
        egui::Key::L => "L",
        egui::Key::M => "M",
        egui::Key::N => "N",
        egui::Key::O => "O",
        egui::Key::P => "P",
        egui::Key::Q => "Q",
        egui::Key::R => "R",
        egui::Key::S => "S",
        egui::Key::T => "T",
        egui::Key::U => "U",
        egui::Key::V => "V",
        egui::Key::W => "W",
        egui::Key::X => "X",
        egui::Key::Y => "Y",
        egui::Key::Z => "Z",
        egui::Key::Num0 => "0",
        egui::Key::Num1 => "1",
        egui::Key::Num2 => "2",
        egui::Key::Num3 => "3",
        egui::Key::Num4 => "4",
        egui::Key::Num5 => "5",
        egui::Key::Num6 => "6",
        egui::Key::Num7 => "7",
        egui::Key::Num8 => "8",
        egui::Key::Num9 => "9",
        egui::Key::Escape => "Esc",
        egui::Key::Tab => "Tab",
        egui::Key::Space => "Space",
        egui::Key::Enter => "Enter",
        egui::Key::Backspace => "Backspace",
        egui::Key::Delete => "Delete",
        egui::Key::Home => "Home",
        egui::Key::End => "End",
        egui::Key::PageUp => "PageUp",
        egui::Key::PageDown => "PageDown",
        egui::Key::ArrowUp => "Up",
        egui::Key::ArrowDown => "Down",
        egui::Key::ArrowLeft => "Left",
        egui::Key::ArrowRight => "Right",
        egui::Key::F1 => "F1",
        egui::Key::F2 => "F2",
        egui::Key::F3 => "F3",
        egui::Key::F4 => "F4",
        egui::Key::F5 => "F5",
        egui::Key::F6 => "F6",
        egui::Key::F7 => "F7",
        egui::Key::F8 => "F8",
        egui::Key::F9 => "F9",
        egui::Key::F10 => "F10",
        egui::Key::F11 => "F11",
        egui::Key::F12 => "F12",
        _ => "?",
    }
}