diff --git a/src/app.rs b/src/app.rs index cd63da4..da00223 100644 --- a/src/app.rs +++ b/src/app.rs @@ -69,7 +69,7 @@ impl Default for TemplateApp { text_cache: None, did_fit_start: false, last_cursor_pos: None, - reset_view_requested: false, + reset_view_requested: false } } } @@ -141,8 +141,10 @@ impl eframe::App for TemplateApp { let ( escape_pressed, f3_pressed, + f_pressed, scroll_delta, zoom_delta, + pointer_latest, pointer_pos, frame_time, primary_down, @@ -152,8 +154,10 @@ impl eframe::App for TemplateApp { ( i.key_pressed(egui::Key::Escape), i.key_pressed(egui::Key::F3), + i.key_pressed(egui::Key::F), i.smooth_scroll_delta.y, i.zoom_delta(), + i.pointer.latest_pos(), i.pointer.hover_pos(), i.stable_dt, i.pointer.primary_down(), @@ -162,6 +166,12 @@ impl eframe::App for TemplateApp { ) }); + if let Some(pos) = pointer_latest.or(pointer_pos) { + self.last_cursor_pos = Some(pos); + } + + let is_fullscreen = ctx.input(|i| i.viewport().fullscreen.unwrap_or(false)); + // Update FPS EMA if frame_time > 0.0 { const ALPHA: f32 = 0.1; @@ -227,6 +237,11 @@ impl eframe::App for TemplateApp { let canvas_rect = response.rect; painter.rect_filled(canvas_rect, 0.0, background_color); + // Fullscreen toggle via double-click or 'F' + if response.double_clicked() || f_pressed { + ctx.send_viewport_cmd(egui::ViewportCommand::Fullscreen(!is_fullscreen)); + } + if !self.did_fit_start { self.reset_view_requested = true; self.did_fit_start = true; @@ -300,6 +315,57 @@ impl eframe::App for TemplateApp { } } + // Edge scrolling (only in fullscreen) + let edge_pointer = pointer_latest.or(self.last_cursor_pos); + if is_fullscreen { + if let Some(mouse_pos) = edge_pointer { + let dt = if frame_time > 0.0 { + frame_time + } else { + 1.0 / 60.0 + }; + let nx = if canvas_rect.width() > 0.0 { + ((mouse_pos.x - canvas_rect.left()) / canvas_rect.width()).clamp(0.0, 1.0) + } else { + 0.5 + }; + let ny = if canvas_rect.height() > 0.0 { + ((mouse_pos.y - canvas_rect.top()) / canvas_rect.height()).clamp(0.0, 1.0) + } else { + 0.5 + }; + + let edge_threshold = 0.15; + let mut vx = 0.0; + let mut vy = 0.0; + + if nx < edge_threshold { + vx = (edge_threshold - nx) / edge_threshold; + } else if nx > 1.0 - edge_threshold { + vx = -(nx - (1.0 - edge_threshold)) / edge_threshold; + } + + if ny < edge_threshold { + vy = (edge_threshold - ny) / edge_threshold; + } else if ny > 1.0 - edge_threshold { + vy = -(ny - (1.0 - edge_threshold)) / edge_threshold; + } + + if vx != 0.0 || vy != 0.0 { + let view_w = canvas_rect.width() / self.zoom; + let view_h = canvas_rect.height() / self.zoom; + let speed_w = view_w; // per second at full intensity + let speed_h = view_h; // per second at full intensity + + self.pan_x += vx * speed_w * dt; + self.pan_y += vy * speed_h * dt; + + // keep scrolling even without new input events + ctx.request_repaint(); + } + } + } + // Element colors let internal_alpha = (0.3_f32 * 255.0).round() as u8; let video_scroll_color =