mirror of
https://codeberg.org/unspeaker/tengri.git
synced 2025-12-06 11:46:42 +01:00
76 lines
2.9 KiB
Rust
76 lines
2.9 KiB
Rust
use crate::*;
|
|
use std::{sync::Arc, collections::BTreeMap, path::PathBuf};
|
|
/// A collection of input bindings.
|
|
///
|
|
/// Each contained layer defines a mapping from input event to command invocation
|
|
/// over a given state. Furthermore, each layer may have an associated cond,
|
|
/// so that only certain layers are active at a given time depending on state.
|
|
///
|
|
/// When a key is pressed, the bindings for it are checked in sequence.
|
|
/// When the first non-conditional or true conditional binding is executed,
|
|
/// that .event()binding's value is returned.
|
|
#[derive(Debug)]
|
|
pub struct EventMap<E, C>(
|
|
/// Map of each event (e.g. key combination) to
|
|
/// all command expressions bound to it by
|
|
/// all loaded input layers.
|
|
pub BTreeMap<E, Vec<Binding<C>>>
|
|
);
|
|
/// An input binding.
|
|
#[derive(Debug, Clone)]
|
|
pub struct Binding<C> {
|
|
pub commands: Arc<[C]>,
|
|
pub condition: Option<Condition>,
|
|
pub description: Option<Arc<str>>,
|
|
pub source: Option<Arc<PathBuf>>,
|
|
}
|
|
impl<C> Binding<C> {
|
|
pub fn from_dsl (dsl: impl Dsl) -> Usually<Self> {
|
|
let command: Option<C> = None;
|
|
let condition: Option<Condition> = None;
|
|
let description: Option<Arc<str>> = None;
|
|
let source: Option<Arc<PathBuf>> = None;
|
|
if let Some(command) = command {
|
|
Ok(Self { commands: [command].into(), condition, description, source })
|
|
} else {
|
|
Err(format!("no command in {dsl:?}").into())
|
|
}
|
|
}
|
|
}
|
|
/// Input bindings are only returned if this evaluates to true
|
|
#[derive(Clone)]
|
|
pub struct Condition(Arc<Box<dyn Fn()->bool + Send + Sync>>);
|
|
impl_debug!(Condition |self, w| { write!(w, "*") });
|
|
/// Default is always empty map regardless if `E` and `C` implement [Default].
|
|
impl<E, C> Default for EventMap<E, C> {
|
|
fn default () -> Self { Self(Default::default()) }
|
|
}
|
|
impl<E: Clone + Ord, C> EventMap<E, C> {
|
|
/// Create a new event map
|
|
pub fn new () -> Self {
|
|
Default::default()
|
|
}
|
|
/// Add a binding to an owned event map.
|
|
pub fn def (mut self, event: E, binding: Binding<C>) -> Self {
|
|
self.add(event, binding);
|
|
self
|
|
}
|
|
/// Add a binding to an event map.
|
|
pub fn add (&mut self, event: E, binding: Binding<C>) -> &mut Self {
|
|
if !self.0.contains_key(&event) {
|
|
self.0.insert(event.clone(), Default::default());
|
|
}
|
|
self.0.get_mut(&event).unwrap().push(binding);
|
|
self
|
|
}
|
|
/// Return the binding(s) that correspond to an event.
|
|
pub fn query (&self, event: &E) -> Option<&[Binding<C>]> {
|
|
self.0.get(event).map(|x|x.as_slice())
|
|
}
|
|
/// Return the first binding that corresponds to an event, considering conditions.
|
|
pub fn dispatch (&self, event: &E) -> Option<&Binding<C>> {
|
|
self.query(event)
|
|
.map(|bb|bb.iter().filter(|b|b.condition.as_ref().map(|c|(c.0)()).unwrap_or(true)).next())
|
|
.flatten()
|
|
}
|
|
}
|