diff --git a/apps/desktop-gpui/src/app_windows.rs b/apps/desktop-gpui/src/app_windows.rs index 028fcc3ab0..07865f8a59 100644 --- a/apps/desktop-gpui/src/app_windows.rs +++ b/apps/desktop-gpui/src/app_windows.rs @@ -6119,6 +6119,11 @@ pub fn reload_editor(project_path: &Path, cx: &mut App) { let index = editors.iter().position(|(path, _)| path == &key); index.map(|index| editors.remove(index).1) }; + let transform = handle.and_then(|handle| { + handle + .update(cx, |view, _window, _cx| view.timeline_transform()) + .ok() + }); if let Some(handle) = handle { if let Ok(pending) = handle.update(cx, |view, _window, _cx| view.pending_save()) { @@ -6137,7 +6142,16 @@ pub fn reload_editor(project_path: &Path, cx: &mut App) { } tracing::info!(path = %key.display(), "reloading editor after import"); - open_editor(key, cx); + open_editor(key.clone(), cx); + if let Some(transform) = transform + && let Some(handle) = editor_window_handle(&key, cx) + { + handle + .update(cx, |view, _window, _cx| { + view.restore_timeline_transform(transform) + }) + .ok(); + } } /// `editor_window_for_path` (`src-tauri/src/windows.rs:3699-3706`): the live diff --git a/apps/desktop-gpui/src/editor_timeline.rs b/apps/desktop-gpui/src/editor_timeline.rs index 78757d14de..9cd6a884a8 100644 --- a/apps/desktop-gpui/src/editor_timeline.rs +++ b/apps/desktop-gpui/src/editor_timeline.rs @@ -283,6 +283,16 @@ impl Transform { } } + pub fn restored(saved: Transform, total_duration: f64) -> Option { + if saved.zoom <= 0. { + return None; + } + let mut transform = Self::initial(total_duration); + transform.update_zoom(saved.zoom, 0., total_duration); + transform.set_position(saved.position, total_duration); + Some(transform) + } + /// `secsPerPixel = transform.zoom / timelineBounds.width` /// (`TL/index.tsx:189`, `TL/context.ts:91-92`). /// Floored at the smallest positive double so a transform with no project @@ -3634,6 +3644,19 @@ mod tests { assert_eq!(Transform::initial(3_600.0).zoom, 600.0); } + #[test] + fn restored_transform_keeps_the_saved_view_and_clamps_to_the_timeline() { + let saved = Transform { + zoom: 17.05, + position: 12.5, + }; + assert_eq!(Transform::restored(saved, 61.0), Some(saved)); + let shorter = Transform::restored(saved, 10.0).unwrap(); + assert_eq!(shorter.zoom, 10.0); + assert_eq!(shorter.position, 4.0); + assert_eq!(Transform::restored(Transform::default(), 61.0), None); + } + #[test] fn zoom_clamps_to_max_zoom_in_and_the_zoom_out_limit() { let total = 60.0; diff --git a/apps/desktop-gpui/src/editor_window.rs b/apps/desktop-gpui/src/editor_window.rs index 086f10a0f2..d88e57ac19 100644 --- a/apps/desktop-gpui/src/editor_window.rs +++ b/apps/desktop-gpui/src/editor_window.rs @@ -1435,6 +1435,7 @@ pub struct EditorWindow { /// width (`TL/index.tsx:689-703`). There is no mount hook here, so the /// first render that knows both the width and the duration does it. fitted: bool, + restore_transform: Option, /// The transport's zoom slider track rect, written by the slider's own /// prepaint canvas and read by the pointer maths. zoom_slider_track: ui::SliderTrack, @@ -2090,6 +2091,7 @@ impl EditorWindow { view: TimelineView::default(), playback_follow: timeline::PlaybackFollow::default(), fitted: false, + restore_transform: None, zoom_slider_track: ui::SliderTrack::default(), zoom_slider_drag: false, project: ProjectConfiguration::default(), @@ -2911,6 +2913,14 @@ impl EditorWindow { self.instance.take() } + pub fn timeline_transform(&self) -> Transform { + self.view.transform + } + + pub fn restore_timeline_transform(&mut self, transform: Transform) { + self.restore_transform = Some(transform); + } + /// Hand the window its transport, the pump's counters, and the duration /// the engine will actually stop at. pub fn set_transport( @@ -11204,9 +11214,17 @@ impl Render for EditorWindow { if !self.fitted && self.total_duration() > 0.0 { self.fitted = true; let total = self.total_duration(); - self.view - .transform - .fit_on_mount(timeline::content_width(viewport_width), total); + match self + .restore_transform + .take() + .and_then(|saved| Transform::restored(saved, total)) + { + Some(transform) => self.view.transform = transform, + None => self + .view + .transform + .fit_on_mount(timeline::content_width(viewport_width), total), + } } if self.export.is_some() {