mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-19 17:44:18 +01:00
122
crates/notedeck_columns/src/gif.rs
Normal file
122
crates/notedeck_columns/src/gif.rs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
use std::{
|
||||||
|
sync::mpsc::TryRecvError,
|
||||||
|
time::{Instant, SystemTime},
|
||||||
|
};
|
||||||
|
|
||||||
|
use egui::TextureHandle;
|
||||||
|
use notedeck::{GifState, GifStateMap, TexturedImage};
|
||||||
|
|
||||||
|
pub struct LatextTexture<'a> {
|
||||||
|
pub texture: &'a TextureHandle,
|
||||||
|
pub request_next_repaint: Option<SystemTime>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is necessary because other repaint calls can effectively steal our repaint request.
|
||||||
|
/// So we must keep on requesting to repaint at our desired time to ensure our repaint goes through.
|
||||||
|
/// See [`egui::Context::request_repaint_after`]
|
||||||
|
pub fn handle_repaint<'a>(ui: &egui::Ui, latest: LatextTexture<'a>) -> &'a TextureHandle {
|
||||||
|
if let Some(repaint) = latest.request_next_repaint {
|
||||||
|
if let Ok(dur) = repaint.duration_since(SystemTime::now()) {
|
||||||
|
ui.ctx().request_repaint_after(dur);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
latest.texture
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use = "caller should pass the return value to `gif::handle_repaint`"]
|
||||||
|
pub fn retrieve_latest_texture<'a>(
|
||||||
|
url: &str,
|
||||||
|
gifs: &'a mut GifStateMap,
|
||||||
|
cached_image: &'a mut TexturedImage,
|
||||||
|
) -> LatextTexture<'a> {
|
||||||
|
match cached_image {
|
||||||
|
TexturedImage::Static(texture) => LatextTexture {
|
||||||
|
texture,
|
||||||
|
request_next_repaint: None,
|
||||||
|
},
|
||||||
|
TexturedImage::Animated(animation) => {
|
||||||
|
if let Some(receiver) = &animation.receiver {
|
||||||
|
loop {
|
||||||
|
match receiver.try_recv() {
|
||||||
|
Ok(frame) => animation.other_frames.push(frame),
|
||||||
|
Err(TryRecvError::Empty) => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(TryRecvError::Disconnected) => {
|
||||||
|
animation.receiver = None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let now = Instant::now();
|
||||||
|
let (texture, maybe_new_state, request_next_repaint) = match gifs.get(url) {
|
||||||
|
Some(prev_state) => {
|
||||||
|
let should_advance =
|
||||||
|
now - prev_state.last_frame_rendered >= prev_state.last_frame_duration;
|
||||||
|
|
||||||
|
if should_advance {
|
||||||
|
let maybe_new_index = if animation.receiver.is_some()
|
||||||
|
|| prev_state.last_frame_index < animation.num_frames() - 1
|
||||||
|
{
|
||||||
|
prev_state.last_frame_index + 1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
match animation.get_frame(maybe_new_index) {
|
||||||
|
Some(frame) => {
|
||||||
|
let next_frame_time = SystemTime::now().checked_add(frame.delay);
|
||||||
|
(
|
||||||
|
&frame.texture,
|
||||||
|
Some(GifState {
|
||||||
|
last_frame_rendered: now,
|
||||||
|
last_frame_duration: frame.delay,
|
||||||
|
next_frame_time,
|
||||||
|
last_frame_index: maybe_new_index,
|
||||||
|
}),
|
||||||
|
next_frame_time,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let (tex, state) =
|
||||||
|
match animation.get_frame(prev_state.last_frame_index) {
|
||||||
|
Some(frame) => (&frame.texture, None),
|
||||||
|
None => (&animation.first_frame.texture, None),
|
||||||
|
};
|
||||||
|
|
||||||
|
(tex, state, prev_state.next_frame_time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (tex, state) = match animation.get_frame(prev_state.last_frame_index) {
|
||||||
|
Some(frame) => (&frame.texture, None),
|
||||||
|
None => (&animation.first_frame.texture, None),
|
||||||
|
};
|
||||||
|
(tex, state, prev_state.next_frame_time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => (
|
||||||
|
&animation.first_frame.texture,
|
||||||
|
Some(GifState {
|
||||||
|
last_frame_rendered: now,
|
||||||
|
last_frame_duration: animation.first_frame.delay,
|
||||||
|
next_frame_time: None,
|
||||||
|
last_frame_index: 0,
|
||||||
|
}),
|
||||||
|
None,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(new_state) = maybe_new_state {
|
||||||
|
gifs.insert(url.to_owned(), new_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
LatextTexture {
|
||||||
|
texture,
|
||||||
|
request_next_repaint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,6 +15,7 @@ mod deck_state;
|
|||||||
mod decks;
|
mod decks;
|
||||||
mod draft;
|
mod draft;
|
||||||
mod frame_history;
|
mod frame_history;
|
||||||
|
mod gif;
|
||||||
mod images;
|
mod images;
|
||||||
mod key_parsing;
|
mod key_parsing;
|
||||||
pub mod login_manager;
|
pub mod login_manager;
|
||||||
|
|||||||
Reference in New Issue
Block a user