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    // false means done
24    pub fn event(&self, ctx: &mut EventCtx) -> bool {
25        // Actually nothing for us to do
26        #[allow(clippy::float_cmp)]
27        if self.line.is_none() && self.cam_zoom.0 == self.cam_zoom.1 {
28            return false;
29        }
30
31        // Weird to do stuff for any event?
32        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}