use crate::widget::Command;
use iced::keyboard::{Key, Modifiers};
#[derive(Debug, Clone, PartialEq)]
pub struct KeyBinding {
pub key: Key,
pub modifiers: Modifiers,
}
impl KeyBinding {
pub fn new(key: Key, modifiers: Modifiers) -> Self {
Self { key, modifiers }
}
pub fn command(character: &str) -> Self {
Self::new(Key::Character(character.into()), Modifiers::COMMAND)
}
pub fn command_shift(character: &str) -> Self {
Self::new(
Key::Character(character.into()),
Modifiers::COMMAND | Modifiers::SHIFT,
)
}
pub fn matches(&self, key: &Key, modified_key: &Key, modifiers: Modifiers) -> bool {
let same_key = |pressed: &Key| match (self.key.as_ref(), pressed.as_ref()) {
(Key::Character(a), Key::Character(b)) => a.eq_ignore_ascii_case(b),
(a, b) => a == b,
};
(same_key(key) || same_key(modified_key))
&& modifiers.control() == self.modifiers.control()
&& modifiers.alt() == self.modifiers.alt()
&& modifiers.logo() == self.modifiers.logo()
&& (!self.modifiers.shift() || modifiers.shift())
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ZoomShortcuts {
pub zoom_in: Vec<KeyBinding>,
pub zoom_out: Vec<KeyBinding>,
pub reset: Vec<KeyBinding>,
}
impl Default for ZoomShortcuts {
fn default() -> Self {
Self {
zoom_in: vec![KeyBinding::command("+"), KeyBinding::command("=")],
zoom_out: vec![KeyBinding::command("-")],
reset: vec![KeyBinding::command("0")],
}
}
}
impl ZoomShortcuts {
pub fn none() -> Self {
Self {
zoom_in: Vec::new(),
zoom_out: Vec::new(),
reset: Vec::new(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct ZoomSettings {
pub enabled: bool,
pub min: f32,
pub max: f32,
pub levels: Vec<f32>,
pub mouse_wheel: bool,
pub controls: bool,
pub shortcuts: ZoomShortcuts,
}
impl Default for ZoomSettings {
fn default() -> Self {
Self {
enabled: true,
min: 0.25,
max: 5.0,
levels: vec![
0.25, 0.33, 0.5, 0.67, 0.75, 0.8, 0.9, 1.0, 1.1, 1.25, 1.5, 1.75, 2.0, 2.5, 3.0,
4.0, 5.0,
],
mouse_wheel: true,
controls: true,
shortcuts: ZoomShortcuts::default(),
}
}
}
impl ZoomSettings {
pub fn disabled() -> Self {
Self {
enabled: false,
..Self::default()
}
}
pub fn clamp(&self, zoom: f32) -> f32 {
let (min, max) = (self.min.min(self.max), self.max.max(self.min));
zoom.clamp(min.max(0.05), max.max(0.05))
}
pub fn step(&self, zoom: f32, direction: i32) -> f32 {
let next = if self.levels.is_empty() {
if direction > 0 {
zoom * 1.1
} else {
zoom / 1.1
}
} else if direction > 0 {
self.levels
.iter()
.copied()
.find(|level| *level > zoom * 1.001)
.unwrap_or(self.max)
} else {
self.levels
.iter()
.rev()
.copied()
.find(|level| *level < zoom * 0.999)
.unwrap_or(self.min)
};
self.clamp(next)
}
pub(crate) fn command_for(
&self,
key: &Key,
modified_key: &Key,
modifiers: Modifiers,
) -> Option<Command> {
if !self.enabled {
return None;
}
let hit = |bindings: &[KeyBinding]| {
bindings
.iter()
.any(|binding| binding.matches(key, modified_key, modifiers))
};
if hit(&self.shortcuts.zoom_in) {
Some(Command::ZoomIn)
} else if hit(&self.shortcuts.zoom_out) {
Some(Command::ZoomOut)
} else if hit(&self.shortcuts.reset) {
Some(Command::ResetZoom)
} else {
None
}
}
}