From bfbe387afa159f17562e242bf0fc780c8c69a69d Mon Sep 17 00:00:00 2001 From: Isaac Mills Date: Mon, 18 Mar 2024 23:25:49 -0400 Subject: [PATCH] Add image zooming --- src/app.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 111 insertions(+), 15 deletions(-) diff --git a/src/app.rs b/src/app.rs index f51eaca..d40bb82 100644 --- a/src/app.rs +++ b/src/app.rs @@ -7,8 +7,8 @@ use cosmic_jotdown::jotdown::{self, Event, ListKind}; use cosmic_jotdown::{Indent, INDENT_AMOUNT}; use eframe::egui::mutex::{Mutex, RwLock}; use eframe::egui::{ - self, lerp, Align2, Image, ImageSize, ImageSource, OpenUrl, Pos2, Rect, Rounding, Sense, - Stroke, Vec2, + self, lerp, Align2, Id, Image, ImageSize, ImageSource, LayerId, OpenUrl, Pos2, Rect, Rounding, + Sense, Stroke, Vec2, }; use eframe::egui_wgpu::{self, wgpu}; use egui::{Color32, Frame}; @@ -26,6 +26,8 @@ use wgpu::util::DeviceExt; pub struct Portfolio { custom: Custom3d, zoomed: bool, + image_zoomed: bool, + last_image_zoomed: Id, hovered: bool, click_time_offset: f64, hover_time_offset: f64, @@ -284,7 +286,7 @@ impl ContextWindow { ); self.size.y += new_size.y + paragraph_height; } else { - last_image_size = Some(size); + last_image_size = Some(size + Vec2::new(IMAGE_PADDING, 0.0)); } } res @@ -405,6 +407,8 @@ impl Portfolio { Self { custom: Custom3d::new(cc).unwrap(), zoomed: false, + image_zoomed: false, + last_image_zoomed: Id::NULL, hovered: false, click_time_offset: 0.0, hover_time_offset: 0.0, @@ -437,7 +441,6 @@ impl Portfolio { self.to_pos = point.into(); } self.zoomed = true; - log::info!("{:?}", (self.from_size, self.from_pos)); } } @@ -541,6 +544,7 @@ impl eframe::App for Portfolio { self.name_buffers = name_buffers; } self.max_size = ui.max_rect(); + let time = ui.input(|i| i.time); let mut scroll_area = egui::ScrollArea::vertical().show_viewport(ui, |ui, rect| { let max_rect = ui.max_rect(); ui.allocate_exact_size( @@ -558,16 +562,14 @@ impl eframe::App for Portfolio { functions::EaseOutCubic, if self.zoomed { 1.0 } else { 0.0 }, if self.zoomed { 0.0 } else { 1.0 }, - ui.input(|i| i.time) - - self.click_time_offset - - if self.zoomed { 0.0 } else { 0.5 }, + time - self.click_time_offset - if self.zoomed { 0.0 } else { 0.5 }, 1.0, ); let zoom_view_opacity = keyframe::ease_with_scaled_time( functions::EaseOutCubic, if self.zoomed { 0.0 } else { 1.0 }, if self.zoomed { 1.0 } else { 0.0 }, - ui.input(|i| i.time) - self.click_time_offset, + time - self.click_time_offset, 1.0, ); let mut buffer_offset = 0.0; @@ -684,17 +686,112 @@ impl eframe::App for Portfolio { } } ContextBlock::Image { image, .. } => { - image - .clone() - .tint(Color32::WHITE.gamma_multiply(zoom_view_opacity)) - .paint_at(ui, context_block.0.translate(rect.min.to_vec2())); + let image_rect = context_block.0.translate(rect.min.to_vec2()); + + let image_response = ui.allocate_rect(image_rect, Sense::click()); + + let time_offset = ui.memory_mut(|m| { + let time_offset = + m.data.get_temp_mut_or_default::(image_response.id); + + if image_response.clicked() && !self.image_zoomed { + link_clicked = true; + *time_offset = time; + self.last_image_zoomed = image_response.id; + self.image_zoomed = true; + } + + *time_offset + }); + + if image_response.hovered() && !self.image_zoomed { + ui.ctx().set_cursor_icon(egui::CursorIcon::ZoomIn); + } + + let fs_rect = Align2::CENTER_CENTER.align_size_within_rect( + { + let max_size = self.max_size.shrink(32.0).size(); + ImageSize { + max_size, + ..Default::default() + } + .calc_size(max_size, image_rect.size()) + }, + self.max_size, + ); + + if self.last_image_zoomed == image_response.id { + let ui = egui::Ui::new( + ui.ctx().clone(), + LayerId::debug(), + Id::new("image_zoom"), + self.max_size, + self.max_size, + ); + + let t = keyframe::ease_with_scaled_time( + functions::EaseInOutCubic, + if self.image_zoomed { 0.0 } else { 1.0 }, + if self.image_zoomed { 1.0 } else { 0.0 }, + time - time_offset, + 0.5, + ); + + ui.painter().rect_filled( + ui.max_rect(), + Rounding::default(), + Color32::BLACK.gamma_multiply( + keyframe::ease_with_scaled_time( + functions::EaseInOutCubic, + if self.image_zoomed { 0.0 } else { 0.6 }, + if self.image_zoomed { 0.6 } else { 0.0 }, + time - time_offset, + 0.5, + ), + ), + ); + + image + .clone() + .tint(Color32::WHITE.gamma_multiply(zoom_view_opacity)) + .paint_at(&ui, image_rect.lerp_towards(&fs_rect, t)); + } else { + image + .clone() + .tint(Color32::WHITE.gamma_multiply(zoom_view_opacity)) + .paint_at( + ui, + image_rect.lerp_towards( + &fs_rect, + keyframe::ease_with_scaled_time( + functions::EaseInOutCubic, + 1.0, + 0.0, + time - time_offset, + 0.5, + ), + ), + ); + } } }); } let mut hovered = false; if self.zoomed { - if ui.input(|i| i.pointer.any_click()) && icon_link.is_none() && !link_clicked { - self.click(ui, None); + if ui.input(|i| i.pointer.any_click()) && !link_clicked { + if self.image_zoomed { + ui.memory_mut(|m| { + let time_offset = m + .data + .get_temp_mut_or_default::(self.last_image_zoomed); + + link_clicked = true; + *time_offset = time; + self.image_zoomed = false; + }); + } else if icon_link.is_none() { + self.click(ui, None); + } } } else { if ui.input(|i| i.pointer.secondary_clicked()) { @@ -734,7 +831,6 @@ impl eframe::App for Portfolio { let response = ui.allocate_rect(rect, Sense::click()); let response_hovered = response.hovered(); - let time = ui.input(|i| i.time); let opacity = ui.memory_mut(|m| { let icon_state = m.data.get_temp_mut_or_insert_with(response.id, || {