widgetry/tools/
warper.rs
1use instant::Instant;
2
3use geom::{Line, Pt2D};
4
5use crate::{EventCtx, UpdateType};
6
7pub struct Warper {
8 started: Instant,
9 line: Option<Line>,
10 cam_zoom: (f64, f64),
11}
12
13impl Warper {
14 pub fn new(ctx: &EventCtx, pt: Pt2D, target_cam_zoom: Option<f64>) -> Warper {
15 let z = ctx.canvas.cam_zoom;
16 Warper {
17 started: Instant::now(),
18 line: Line::new(ctx.canvas.center_to_map_pt(), pt).ok(),
19 cam_zoom: (z, target_cam_zoom.unwrap_or(z)),
20 }
21 }
22
23 pub fn event(&self, ctx: &mut EventCtx) -> bool {
25 #[allow(clippy::float_cmp)]
27 if self.line.is_none() && self.cam_zoom.0 == self.cam_zoom.1 {
28 return false;
29 }
30
31 if ctx.input.nonblocking_is_update_event().is_none() {
33 ctx.request_update(UpdateType::Game);
34 return true;
35 }
36 ctx.input.use_update_event();
37
38 const MAX_ANIMATION_TIME_S: f64 = 0.5;
39 const ANIMATION_SPEED: f64 = 200.0;
40 let total_time = if let Some(ref line) = self.line {
41 (line.length().inner_meters() / ANIMATION_SPEED).min(MAX_ANIMATION_TIME_S)
42 } else {
43 MAX_ANIMATION_TIME_S
44 };
45 let percent = abstutil::elapsed_seconds(self.started) / total_time;
46
47 let orig_center = ctx.canvas.center_to_map_pt();
48 if percent >= 1.0 || ctx.input.any_pressed().is_some() {
49 ctx.canvas.cam_zoom = self.cam_zoom.1;
50 if let Some(ref line) = self.line {
51 ctx.canvas.center_on_map_pt(line.pt2());
52 } else {
53 ctx.canvas.center_on_map_pt(orig_center);
54 }
55 false
56 } else {
57 ctx.canvas.cam_zoom = self.cam_zoom.0 + percent * (self.cam_zoom.1 - self.cam_zoom.0);
58 if let Some(ref line) = self.line {
59 ctx.canvas
60 .center_on_map_pt(line.percent_along(percent).unwrap());
61 } else {
62 ctx.canvas.center_on_map_pt(orig_center);
63 }
64 ctx.request_update(UpdateType::Game);
65 true
66 }
67 }
68}