1use eframe::egui::Vec2;
2
3#[derive(Debug, Clone, Copy, PartialEq)]
4pub enum FitMode {
5 OneToOne,
6 FitLonger,
7 FitShorter,
8 Custom,
9}
10
11pub struct ZoomHandler {
12 zoom_level: f64,
13 pan_offset: Vec2,
14 fit_mode: FitMode,
15 default_fit_mode: FitMode,
16 manual_zoom_applied: bool,
17 min_zoom: f64,
18 max_zoom: f64,
19}
20
21impl ZoomHandler {
22 pub fn new(default_zoom: f64) -> Self {
23 Self {
24 zoom_level: default_zoom,
25 pan_offset: Vec2::ZERO,
26 fit_mode: FitMode::FitLonger,
27 default_fit_mode: FitMode::FitLonger,
28 manual_zoom_applied: false,
29 min_zoom: 0.1,
30 max_zoom: 10.0,
31 }
32 }
33
34 pub fn update_for_new_image(
35 &mut self,
36 image_size: Vec2,
37 window_size: Vec2,
38 ) {
39 self.manual_zoom_applied = false;
40 self.fit_mode = self.default_fit_mode;
41 let new_zoom = self.calculate_fit_zoom(image_size, window_size);
42 self.zoom_level = new_zoom;
43 self.pan_offset = Vec2::ZERO;
44 }
45
46 pub fn update_for_window_resize(
47 &mut self,
48 image_size: Vec2,
49 window_size: Vec2,
50 ) {
51 if !self.manual_zoom_applied {
52 self.zoom_level = self.calculate_fit_zoom(image_size, window_size);
53 }
54 }
55
56 pub fn calculate_fit_zoom(
57 &self,
58 image_size: Vec2,
59 window_size: Vec2,
60 ) -> f64 {
61 let scale_x = (window_size.x / image_size.x) as f64;
62 let scale_y = (window_size.y / image_size.y) as f64;
63
64 let zoom = match if self.manual_zoom_applied {
65 FitMode::Custom
66 } else {
67 self.fit_mode
68 } {
69 FitMode::OneToOne => 1.0,
70 FitMode::FitLonger => scale_x.min(scale_y),
71 FitMode::FitShorter => scale_x.max(scale_y),
72 FitMode::Custom => self.zoom_level,
73 };
74
75 zoom.clamp(self.min_zoom, self.max_zoom)
76 }
77
78 pub fn set_default_fit_mode(&mut self, mode: FitMode) {
79 self.default_fit_mode = mode;
80 if !self.manual_zoom_applied {
81 self.fit_mode = mode;
82 }
83 }
84
85 pub fn reset_view_position(&mut self) {
86 self.pan_offset = Vec2::ZERO;
87 }
88
89 pub fn set_zoom(&mut self, new_zoom: f64) {
90 self.zoom_level = new_zoom.clamp(self.min_zoom, self.max_zoom);
91 self.manual_zoom_applied = true;
92 self.fit_mode = FitMode::Custom;
93 }
94
95 pub fn add_offset(&mut self, delta: Vec2) {
96 self.pan_offset += delta;
97 self.manual_zoom_applied = true;
98 self.fit_mode = FitMode::Custom;
99 }
100
101 pub fn reset(&mut self) {
102 self.manual_zoom_applied = false;
103 self.fit_mode = self.default_fit_mode;
104 self.zoom_level = 1.0;
105 self.pan_offset = Vec2::ZERO;
106 }
107
108 pub fn reset_to_default_fit_mode(&mut self) {
109 self.manual_zoom_applied = false;
110 self.fit_mode = self.default_fit_mode;
111 self.pan_offset = Vec2::ZERO;
112 }
113
114 pub fn zoom_level(&self) -> f64 {
115 self.zoom_level
116 }
117
118 pub fn zoom_percentage(&self) -> f64 {
119 self.zoom_level * 100.0
120 }
121
122 pub fn offset(&self) -> Vec2 {
123 self.pan_offset
124 }
125
126 pub fn get_fit_mode(&self) -> FitMode {
127 self.fit_mode
128 }
129}