1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::fmt::Debug;

use rvimage_domain::{BbF, BbI, ShapeI};

use crate::{
    events::{Events, KeyCode},
    history::History,
    make_tool_transform,
    tools::core::Manipulate,
    world::World,
};

use super::{core::Mover, zoom::move_zoom_box};

fn event_move_zoom_box(events: &Events) -> bool {
    events.held_ctrl() && (events.pressed(KeyCode::MouseLeft) || events.held(KeyCode::MouseLeft))
}
fn zoom_box_mouse_wheel(zoom_box: Option<BbF>, shape_orig: ShapeI, y_delta: f64) -> Option<BbF> {
    let current_zb = if let Some(zb) = zoom_box {
        zb
    } else {
        BbI::from_arr(&[0, 0, shape_orig.w, shape_orig.h]).into()
    };
    let clip_val = 1.0;
    let y_delta_clipped = if y_delta > 0.0 {
        y_delta.min(clip_val)
    } else {
        y_delta.max(-clip_val)
    };
    let factor = 1.0 - y_delta_clipped * 0.1;

    Some(current_zb.center_scale(factor, shape_orig))
}

#[derive(Clone, Debug)]
pub struct AlwaysActiveZoom {
    mover: Mover,
}
impl AlwaysActiveZoom {
    fn mouse_pressed(
        &mut self,
        events: &Events,
        world: World,
        history: History,
    ) -> (World, History) {
        if event_move_zoom_box(events) {
            self.mover.move_mouse_pressed(events.mouse_pos_on_view);
        }
        (world, history)
    }

    fn mouse_held(
        &mut self,
        events: &Events,
        mut world: World,
        history: History,
    ) -> (World, History) {
        if event_move_zoom_box(events) {
            (self.mover, world) = move_zoom_box(self.mover, world, events.mouse_pos_on_view);
            (world, history)
        } else {
            (world, history)
        }
    }

    fn key_released(
        &mut self,
        events: &Events,
        mut world: World,
        history: History,
    ) -> (World, History) {
        if events.held_ctrl() {
            let zb = if events.released(KeyCode::Key0) {
                None
            } else if events.released(KeyCode::PlusEquals) {
                zoom_box_mouse_wheel(*world.zoom_box(), world.shape_orig(), 1.0)
            } else if events.released(KeyCode::Minus) {
                zoom_box_mouse_wheel(*world.zoom_box(), world.shape_orig(), -1.0)
            } else {
                *world.zoom_box()
            };
            world.set_zoom_box(zb);
        }
        (world, history)
    }
}
impl Manipulate for AlwaysActiveZoom {
    fn new() -> AlwaysActiveZoom {
        AlwaysActiveZoom {
            mover: Mover::new(),
        }
    }
    fn has_been_used(&self, events: &Events) -> Option<bool> {
        let zoomed = events.held_ctrl()
            && (events.released(KeyCode::Key0)
                || events.released(KeyCode::PlusEquals)
                || events.released(KeyCode::Minus));
        Some(zoomed || event_move_zoom_box(events))
    }
    fn events_tf(&mut self, world: World, history: History, events: &Events) -> (World, History) {
        make_tool_transform!(
            self,
            world,
            history,
            events,
            [
                (pressed, KeyCode::MouseLeft, mouse_pressed),
                (held, KeyCode::MouseLeft, mouse_held),
                (released, KeyCode::Key0, key_released),
                (released, KeyCode::PlusEquals, key_released), // Plus is equals
                (released, KeyCode::Minus, key_released)
            ]
        )
    }
}

#[test]
fn test_zb() {
    fn test(zb: Option<BbF>, y_delta: f64, reference_coords: &[u32; 4]) {
        println!("y_delta {}", y_delta);
        let shape = ShapeI::new(200, 100);
        let zb_new = zoom_box_mouse_wheel(zb, shape, y_delta);
        assert_eq!(zb_new, Some(BbI::from_arr(reference_coords).into()));
    }
    test(None, 1.0, &[10, 5, 180, 90]);
    test(None, -1.0, &[0, 0, 200, 100]);
}