use std::borrow::Cow;
use crcbl_core::input::{KeyCode, PointerButton};
use crate::{Binding, PadButton, PadKind, PointerAxis, Stick, Trigger};
pub trait HintLabels {
fn key(&self, key: KeyCode) -> Cow<'static, str> {
key_label(key).into()
}
fn mouse_button(&self, button: PointerButton) -> Cow<'static, str> {
match button {
PointerButton::Left => "LMB".into(),
PointerButton::Right => "RMB".into(),
PointerButton::Middle => "MMB".into(),
PointerButton::Back => "Mouse 4".into(),
PointerButton::Forward => "Mouse 5".into(),
PointerButton::Other(index) => format!("Mouse {index}").into(),
}
}
fn mouse_motion(&self) -> Cow<'static, str> {
"Mouse".into()
}
fn wheel(&self) -> Cow<'static, str> {
"Wheel".into()
}
fn pointer_position(&self, axis: PointerAxis) -> Cow<'static, str> {
let _ = axis;
"Pointer".into()
}
fn control(&self, id: &str) -> Cow<'static, str> {
id.to_owned().into()
}
fn pad_button(&self, kind: PadKind, button: PadButton) -> Cow<'static, str> {
pad_button_label(kind, button).into()
}
fn dpad(&self, kind: PadKind) -> Cow<'static, str> {
let _ = kind;
"D-pad".into()
}
fn stick(&self, kind: PadKind, stick: Stick) -> Cow<'static, str> {
let _ = kind;
match stick {
Stick::Left => "Left stick".into(),
Stick::Right => "Right stick".into(),
}
}
fn trigger(&self, kind: PadKind, trigger: Trigger) -> Cow<'static, str> {
trigger_label(kind, trigger).into()
}
fn label(&self, binding: &Binding, kind: PadKind) -> String {
match binding {
Binding::Key(key) => self.key(*key).into_owned(),
Binding::Chord { modifier, key } => {
format!("{}+{}", self.key(modifier.keys()[0]), self.key(*key))
}
Binding::KeyAxis { negative, positive } => {
format!("{}/{}", self.key(*negative), self.key(*positive))
}
Binding::Wasd {
up,
down,
left,
right,
} => {
let keys = [*up, *left, *down, *right].map(|key| self.key(key));
let separator = if keys.iter().all(|key| key.chars().count() == 1) {
""
} else {
"/"
};
keys.join(separator)
}
Binding::ScrollChord { held } => format!("{}+{}", self.key(*held), self.wheel()),
Binding::MouseButton(button) => self.mouse_button(*button).into_owned(),
Binding::ButtonChord { modifier, button } => format!(
"{}+{}",
self.key(modifier.keys()[0]),
self.mouse_button(*button)
),
Binding::MouseMotion => self.mouse_motion().into_owned(),
Binding::MouseScroll => self.wheel().into_owned(),
Binding::PointerPosition { axis } => self.pointer_position(*axis).into_owned(),
Binding::Virtual(id) => self.control(id).into_owned(),
Binding::PadButton(button) => self.pad_button(kind, *button).into_owned(),
Binding::PadChord { modifier, button } => format!(
"{}+{}",
self.pad_button(kind, *modifier),
self.pad_button(kind, *button)
),
Binding::PadDpad => self.dpad(kind).into_owned(),
Binding::PadStick { stick, .. } => self.stick(kind, *stick).into_owned(),
Binding::PadTrigger { trigger, .. } => self.trigger(kind, *trigger).into_owned(),
}
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct DefaultLabels;
impl HintLabels for DefaultLabels {}
fn key_label(key: KeyCode) -> &'static str {
match key {
KeyCode::Backquote => "`",
KeyCode::Minus => "-",
KeyCode::Equal => "=",
KeyCode::BracketLeft => "[",
KeyCode::BracketRight => "]",
KeyCode::Backslash => "\\",
KeyCode::Semicolon => ";",
KeyCode::Quote => "'",
KeyCode::Comma => ",",
KeyCode::Period => ".",
KeyCode::Slash => "/",
KeyCode::Escape => "Esc",
KeyCode::ShiftLeft | KeyCode::ShiftRight => "Shift",
KeyCode::ControlLeft | KeyCode::ControlRight => "Ctrl",
KeyCode::AltLeft | KeyCode::AltRight => "Alt",
KeyCode::SuperLeft | KeyCode::SuperRight => "Super",
KeyCode::ContextMenu => "Menu",
KeyCode::ArrowUp => "Up",
KeyCode::ArrowDown => "Down",
KeyCode::ArrowLeft => "Left",
KeyCode::ArrowRight => "Right",
KeyCode::Numpad0 => "Num 0",
KeyCode::Numpad1 => "Num 1",
KeyCode::Numpad2 => "Num 2",
KeyCode::Numpad3 => "Num 3",
KeyCode::Numpad4 => "Num 4",
KeyCode::Numpad5 => "Num 5",
KeyCode::Numpad6 => "Num 6",
KeyCode::Numpad7 => "Num 7",
KeyCode::Numpad8 => "Num 8",
KeyCode::Numpad9 => "Num 9",
KeyCode::NumpadDivide => "Num /",
KeyCode::NumpadMultiply => "Num *",
KeyCode::NumpadSubtract => "Num -",
KeyCode::NumpadAdd => "Num +",
KeyCode::NumpadEnter => "Num Enter",
KeyCode::NumpadDecimal => "Num .",
other => {
let name = other.as_str();
name.strip_prefix("Key")
.or_else(|| name.strip_prefix("Digit"))
.unwrap_or(name)
}
}
}
const fn pad_button_label(kind: PadKind, button: PadButton) -> &'static str {
use PadKind::{Generic, PlayStation, SteamDeck, Switch, Xbox};
match button {
PadButton::South => match kind {
Xbox | SteamDeck => "A",
PlayStation => "Cross",
Switch => "B",
Generic => "South",
},
PadButton::East => match kind {
Xbox | SteamDeck => "B",
PlayStation => "Circle",
Switch => "A",
Generic => "East",
},
PadButton::West => match kind {
Xbox | SteamDeck => "X",
PlayStation => "Square",
Switch => "Y",
Generic => "West",
},
PadButton::North => match kind {
Xbox | SteamDeck => "Y",
PlayStation => "Triangle",
Switch => "X",
Generic => "North",
},
PadButton::LeftShoulder => match kind {
Xbox => "LB",
PlayStation | SteamDeck => "L1",
Switch => "L",
Generic => "Left bumper",
},
PadButton::RightShoulder => match kind {
Xbox => "RB",
PlayStation | SteamDeck => "R1",
Switch => "R",
Generic => "Right bumper",
},
PadButton::LeftStick => match kind {
Xbox | Switch => "LS",
PlayStation | SteamDeck => "L3",
Generic => "Left stick button",
},
PadButton::RightStick => match kind {
Xbox | Switch => "RS",
PlayStation | SteamDeck => "R3",
Generic => "Right stick button",
},
PadButton::Start => match kind {
Xbox | SteamDeck => "Menu",
PlayStation => "Options",
Switch => "+",
Generic => "Start",
},
PadButton::Select => match kind {
Xbox | SteamDeck => "View",
PlayStation => "Share",
Switch => "-",
Generic => "Select",
},
PadButton::Guide => match kind {
Xbox => "Xbox",
PlayStation => "PS",
Switch => "Home",
SteamDeck => "Steam",
Generic => "Guide",
},
PadButton::DpadUp => "D-pad up",
PadButton::DpadDown => "D-pad down",
PadButton::DpadLeft => "D-pad left",
PadButton::DpadRight => "D-pad right",
}
}
const fn trigger_label(kind: PadKind, trigger: Trigger) -> &'static str {
match (kind, trigger) {
(PadKind::Xbox, Trigger::Left) => "LT",
(PadKind::Xbox, Trigger::Right) => "RT",
(PadKind::PlayStation | PadKind::SteamDeck, Trigger::Left) => "L2",
(PadKind::PlayStation | PadKind::SteamDeck, Trigger::Right) => "R2",
(PadKind::Switch, Trigger::Left) => "ZL",
(PadKind::Switch, Trigger::Right) => "ZR",
(PadKind::Generic, Trigger::Left) => "Left trigger",
(PadKind::Generic, Trigger::Right) => "Right trigger",
}
}