notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

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 }