anim.rs (5712B)
1 use egui::{Pos2, Rect, Response, Sense}; 2 3 pub fn hover_expand( 4 ui: &mut egui::Ui, 5 id: egui::Id, 6 size: f32, 7 expand_size: f32, 8 anim_speed: f32, 9 ) -> (egui::Rect, f32, egui::Response) { 10 // Allocate space for the profile picture with a fixed size 11 let default_size = size + expand_size; 12 let (rect, response) = 13 ui.allocate_exact_size(egui::vec2(default_size, default_size), egui::Sense::click()); 14 15 let val = ui 16 .ctx() 17 .animate_bool_with_time(id, response.hovered(), anim_speed); 18 19 let size = size + val * expand_size; 20 (rect, size, response) 21 } 22 23 #[inline] 24 pub fn hover_small_size() -> f32 { 25 14.0 26 } 27 28 pub fn hover_expand_small(ui: &mut egui::Ui, id: egui::Id) -> (egui::Rect, f32, egui::Response) { 29 let size = hover_small_size(); 30 let expand_size = 5.0; 31 let anim_speed = 0.05; 32 33 hover_expand(ui, id, size, expand_size, anim_speed) 34 } 35 36 pub static ICON_EXPANSION_MULTIPLE: f32 = 1.2; 37 pub static ANIM_SPEED: f32 = 0.05; 38 pub struct AnimationHelper { 39 rect: Rect, 40 center: Pos2, 41 response: Response, 42 animation_progress: f32, 43 expansion_multiple: f32, 44 } 45 46 impl AnimationHelper { 47 pub fn new( 48 ui: &mut egui::Ui, 49 animation_name: impl std::hash::Hash, 50 max_size: egui::Vec2, 51 ) -> Self { 52 let id = ui.id().with(animation_name); 53 let (rect, response) = ui.allocate_exact_size(max_size, Sense::click()); 54 55 let animation_progress = 56 ui.ctx() 57 .animate_bool_with_time(id, response.hovered(), ANIM_SPEED); 58 59 Self { 60 rect, 61 center: rect.center(), 62 response, 63 animation_progress, 64 expansion_multiple: ICON_EXPANSION_MULTIPLE, 65 } 66 } 67 68 pub fn no_animation(ui: &mut egui::Ui, size: egui::Vec2, sense: Sense) -> Self { 69 let (rect, response) = ui.allocate_exact_size(size, sense); 70 71 Self { 72 rect, 73 center: rect.center(), 74 response, 75 animation_progress: 0.0, 76 expansion_multiple: ICON_EXPANSION_MULTIPLE, 77 } 78 } 79 80 pub fn new_from_rect( 81 ui: &mut egui::Ui, 82 animation_name: impl std::hash::Hash, 83 animation_rect: egui::Rect, 84 ) -> Self { 85 let id = ui.id().with(animation_name); 86 let response = ui.allocate_rect(animation_rect, Sense::click()); 87 88 let animation_progress = 89 ui.ctx() 90 .animate_bool_with_time(id, response.hovered(), ANIM_SPEED); 91 92 Self { 93 rect: animation_rect, 94 center: animation_rect.center(), 95 response, 96 animation_progress, 97 expansion_multiple: ICON_EXPANSION_MULTIPLE, 98 } 99 } 100 101 pub fn scale_1d_pos(&self, min_object_size: f32) -> f32 { 102 let max_object_size = min_object_size * self.expansion_multiple; 103 104 if self.response.is_pointer_button_down_on() { 105 min_object_size 106 } else { 107 min_object_size + ((max_object_size - min_object_size) * self.animation_progress) 108 } 109 } 110 111 pub fn scale_radius(&self, min_diameter: f32) -> f32 { 112 self.scale_1d_pos((min_diameter - 1.0) / 2.0) 113 } 114 115 pub fn get_animation_rect(&self) -> egui::Rect { 116 self.rect 117 } 118 119 pub fn center(&self) -> Pos2 { 120 self.rect.center() 121 } 122 123 pub fn take_animation_response(self) -> egui::Response { 124 self.response 125 } 126 127 // Scale a minimum position from center to the current animation position 128 pub fn scale_from_center(&self, x_min: f32, y_min: f32) -> Pos2 { 129 Pos2::new( 130 self.center.x + self.scale_1d_pos(x_min), 131 self.center.y + self.scale_1d_pos(y_min), 132 ) 133 } 134 135 pub fn scale_pos_from_center(&self, min_pos: Pos2) -> Pos2 { 136 self.scale_from_center(min_pos.x, min_pos.y) 137 } 138 139 /// New method for min/max scaling when needed 140 pub fn scale_1d_pos_min_max(&self, min_object_size: f32, max_object_size: f32) -> f32 { 141 min_object_size + ((max_object_size - min_object_size) * self.animation_progress) 142 } 143 } 144 145 pub struct PulseAlpha<'a> { 146 ctx: &'a egui::Context, 147 id: egui::Id, 148 alpha_min: u8, 149 alpha_max: u8, 150 animation_speed: f32, 151 start_max_alpha: bool, 152 } 153 154 impl<'a> PulseAlpha<'a> { 155 pub fn new(ctx: &'a egui::Context, id: egui::Id, alpha_min: u8, alpha_max: u8) -> Self { 156 Self { 157 ctx, 158 id, 159 alpha_min, 160 alpha_max, 161 animation_speed: ANIM_SPEED, 162 start_max_alpha: false, 163 } 164 } 165 166 pub fn with_speed(mut self, speed: f32) -> Self { 167 self.animation_speed = speed; 168 self 169 } 170 171 pub fn start_max_alpha(mut self) -> Self { 172 self.start_max_alpha = true; 173 self 174 } 175 176 // returns the current alpha value for the frame 177 pub fn animate(self) -> u8 { 178 let pulse_direction = if let Some(pulse_dir) = self.ctx.data(|d| d.get_temp(self.id)) { 179 pulse_dir 180 } else { 181 self.ctx 182 .data_mut(|d| d.insert_temp(self.id, self.start_max_alpha)); 183 self.start_max_alpha 184 }; 185 186 let alpha_min_f32 = self.alpha_min as f32; 187 let target = if pulse_direction { 188 self.alpha_max as f32 - alpha_min_f32 189 } else { 190 0.0 191 }; 192 193 let cur_val = self 194 .ctx 195 .animate_value_with_time(self.id, target, self.animation_speed); 196 197 if (target - cur_val).abs() < 0.5 { 198 self.ctx 199 .data_mut(|d| d.insert_temp(self.id, !pulse_direction)); 200 } 201 202 (cur_val + alpha_min_f32).clamp(self.alpha_min as f32, self.alpha_max as f32) as u8 203 } 204 }