use blinc_core::layer::Point;
use crate::viewport::CanvasViewport;
#[derive(Clone, Debug)]
pub struct ZoomController {
pub scroll_sensitivity: f32,
pub pinch_sensitivity: f32,
}
impl Default for ZoomController {
fn default() -> Self {
Self::new()
}
}
impl ZoomController {
pub fn new() -> Self {
Self {
scroll_sensitivity: 0.001,
pinch_sensitivity: 1.0,
}
}
pub fn with_scroll_sensitivity(mut self, sensitivity: f32) -> Self {
self.scroll_sensitivity = sensitivity;
self
}
pub fn with_pinch_sensitivity(mut self, sensitivity: f32) -> Self {
self.pinch_sensitivity = sensitivity;
self
}
pub fn on_scroll(&self, viewport: &mut CanvasViewport, scroll_delta_y: f32, cursor: Point) {
let factor = 1.0 - scroll_delta_y * self.scroll_sensitivity;
let factor = factor.clamp(0.5, 2.0); viewport.zoom_at(cursor, factor);
}
pub fn on_pinch(&self, viewport: &mut CanvasViewport, pinch_scale: f32, pinch_center: Point) {
let factor = 1.0 + (pinch_scale - 1.0) * self.pinch_sensitivity;
viewport.zoom_at(pinch_center, factor);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_zoom_controller_default() {
let zc = ZoomController::new();
assert!((zc.scroll_sensitivity - 0.001).abs() < 1e-6);
assert!((zc.pinch_sensitivity - 1.0).abs() < 1e-6);
}
#[test]
fn test_scroll_zoom_in() {
let zc = ZoomController::new();
let mut vp = CanvasViewport::new();
let cursor = Point::new(400.0, 300.0);
let zoom_before = vp.zoom;
zc.on_scroll(&mut vp, -100.0, cursor);
assert!(vp.zoom > zoom_before);
}
#[test]
fn test_scroll_zoom_out() {
let zc = ZoomController::new();
let mut vp = CanvasViewport::new();
let cursor = Point::new(400.0, 300.0);
let zoom_before = vp.zoom;
zc.on_scroll(&mut vp, 100.0, cursor);
assert!(vp.zoom < zoom_before);
}
#[test]
fn test_pinch_zoom_in() {
let zc = ZoomController::new();
let mut vp = CanvasViewport::new();
let center = Point::new(400.0, 300.0);
let zoom_before = vp.zoom;
zc.on_pinch(&mut vp, 1.5, center);
assert!(vp.zoom > zoom_before);
}
#[test]
fn test_zoom_respects_bounds() {
let zc = ZoomController::new();
let mut vp = CanvasViewport::new();
vp.min_zoom = 0.5;
vp.max_zoom = 3.0;
let cursor = Point::new(0.0, 0.0);
for _ in 0..100 {
zc.on_scroll(&mut vp, -200.0, cursor);
}
assert!(vp.zoom <= vp.max_zoom);
for _ in 0..100 {
zc.on_scroll(&mut vp, 200.0, cursor);
}
assert!(vp.zoom >= vp.min_zoom);
}
}