use crate::mapping::action::InputAction;
use crate::mapping::resolver::InputMap;
use crate::state::advanced::AdvancedInputState;
use crate::types::GamepadId;
#[derive(Clone)]
pub struct InputContext {
pub priority: i32,
pub mappings: InputMap,
pub active: bool,
pub blocks_lower_priority: bool,
pub blocks_equal_priority: bool, }
impl InputContext {
pub fn new(priority: i32, mappings: InputMap) -> Self {
Self {
priority,
mappings,
active: true,
blocks_lower_priority: false,
blocks_equal_priority: false,
}
}
pub fn with_blocking(mut self, lower: bool, equal: bool) -> Self {
self.blocks_lower_priority = lower;
self.blocks_equal_priority = equal;
self
}
}
pub struct ContextStack {
contexts: Vec<InputContext>,
allow_multiple_handlers: bool, }
impl Default for ContextStack {
fn default() -> Self {
Self::new()
}
}
impl ContextStack {
pub fn new() -> Self {
Self {
contexts: Vec::new(),
allow_multiple_handlers: false,
}
}
pub fn set_allow_multiple_handlers(&mut self, allow: bool) {
self.allow_multiple_handlers = allow;
}
pub fn push(&mut self, context: InputContext) {
self.contexts.push(context);
self.sort();
}
fn sort(&mut self) {
self.contexts.sort_by(|a, b| b.priority.cmp(&a.priority));
}
pub fn resolve(
&self,
action: InputAction,
input: &AdvancedInputState,
gamepad_id: Option<GamepadId>,
) -> f32 {
if self.allow_multiple_handlers {
let mut total = 0.0;
let mut blocked_by_higher = false;
let mut last_priority = i32::MAX;
for context in &self.contexts {
if !context.active {
continue;
}
if blocked_by_higher {
if context.priority < last_priority {
break;
}
if context.priority == last_priority && context.blocks_equal_priority {
continue;
}
}
let val = context.mappings.resolve(action, input, gamepad_id);
total += val;
if context.blocks_lower_priority || context.blocks_equal_priority {
blocked_by_higher = true;
last_priority = context.priority;
}
}
total.clamp(-1.0, 1.0)
} else {
for context in &self.contexts {
if !context.active {
continue;
}
let val = context.mappings.resolve(action, input, gamepad_id);
if val.abs() > 0.0 {
return val;
}
if context.blocks_lower_priority {
break;
}
}
0.0
}
}
}