ferrite_ui/
zoom.rs

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}