diff --git a/doc/clips.rst b/doc/clips.rst index 7293e7660..d262eb449 100644 --- a/doc/clips.rst +++ b/doc/clips.rst @@ -247,7 +247,7 @@ Speed The :guilabel:`Speed` menu manipulates clip playback speed, allowing for reverse playback, time-lapse, slow-motion, freezes, and looping effects. See :ref:`clip_time_ref` key-frame. -- :guilabel:`Reset` — restores the clip to normal 1× speed. +- :guilabel:`Reset Speed` — restores the clip to normal 1× speed. - :guilabel:`Reverse` — plays the clip backwards at normal speed. - :guilabel:`Speed Up` → Forward / Backward → 2×, 4×, 8×, 16× — speeds up playback in either direction. - :guilabel:`Slow Down` → Forward / Backward → 1/2×, 1/4×, 1/8×, 1/16× — slows down playback in either direction. @@ -302,7 +302,7 @@ Example: “Forward then Back and stop” = :guilabel:`Ping-Pong → Forward → **Reset** -- :guilabel:`Speed → Reset` completely removes any Time curve (including Repeat) and restores the clip to its +- :guilabel:`Speed → Reset Speed` completely removes any Time curve (including Repeat) and restores the clip to its original playback, **without deleting your original non-Time keyframes**. Timing Tool diff --git a/src/tests/test_timeline_helpers.py b/src/tests/test_timeline_helpers.py index 74b5cb5f0..1af847f9e 100644 --- a/src/tests/test_timeline_helpers.py +++ b/src/tests/test_timeline_helpers.py @@ -2104,6 +2104,43 @@ class TimelineHelperTests(unittest.TestCase): self.assertEqual(middle_frame, 777) self.assertEqual(end_frame, 64) + def test_freeze_uses_absolute_trim_end_for_right_side_split_clip(self): + helper = self.make_time_helper() + clip = types.SimpleNamespace( + id="C1", + data={ + "id": "C1", + "position": 10.0, + "start": 10.0, + "end": 52.0, + "duration": 42.0, + "time": {"Points": [{"co": {"X": 1, "Y": 1}, "interpolation": openshot.LINEAR}]}, + "volume": {"Points": [{"co": {"X": 1, "Y": 1.0}, "interpolation": openshot.LINEAR}]}, + "ui": {}, + }, + ) + app = types.SimpleNamespace( + project=types.SimpleNamespace(get=lambda key: {"num": 30, "den": 1} if key == "fps" else None), + updates=types.SimpleNamespace(apply_last_action_to_history=lambda _data: None), + ) + + with patch.object(self.timeline_module.Clip, "get", return_value=clip), \ + patch.object(self.timeline_module, "get_app", return_value=app): + self.timeline_module.TimelineView.Time_Triggered( + helper, + self.timeline_module.MenuTime.FREEZE, + ["C1"], + 8, + 10.0, + ) + + self.assertEqual(clip.data["end"], 60.0) + self.assertEqual(clip.data["duration"], 50.0) + self.assertIn( + {"co": {"X": 1801.0, "Y": 1561.0}, "interpolation": openshot.LINEAR}, + clip.data["time"]["Points"], + ) + def test_volume_triggered_refreshes_waveforms_for_visible_waveform_clips(self): helper = self.make_time_helper() clip = types.SimpleNamespace( diff --git a/src/windows/views/timeline.py b/src/windows/views/timeline.py index 36f928c90..965d4dcdb 100644 --- a/src/windows/views/timeline.py +++ b/src/windows/views/timeline.py @@ -1925,7 +1925,7 @@ class TimelineView(updates.UpdateInterface, ViewClass): # Speed Menu Time_Menu = StyledContextMenu(title=_("Speed"), parent=self) - Time_None = Time_Menu.addAction(_("Reset")) + Time_None = Time_Menu.addAction(_("Reset Speed")) Time_None.triggered.connect(partial(self.Time_Triggered, MenuTime.NONE, clip_ids, '1X')) Time_Menu.addSeparator() @@ -4274,6 +4274,7 @@ class TimelineView(updates.UpdateInterface, ViewClass): freeze_seconds = float(speed) original_duration = clip.data["duration"] + original_end = float(clip.data["end"]) log.info('Updating timing for clip ID {}, original duration: {}'.format(clip.id, original_duration)) log.debug(clip.data) @@ -4287,9 +4288,9 @@ class TimelineView(updates.UpdateInterface, ViewClass): start_animation_frames_value = start_animation_frames end_animation_seconds = start_animation_seconds + freeze_seconds end_animation_frames = round(end_animation_seconds * fps_float) + 1 - end_of_clip_seconds = float(clip.data["duration"]) + end_of_clip_seconds = float(clip.data["end"]) end_of_clip_frames = round((end_of_clip_seconds) * fps_float) + 1 - end_of_clip_frames_value = round((original_duration) * fps_float) + 1 + end_of_clip_frames_value = round((original_end) * fps_float) + 1 # Determine volume start and end start_volume_value = 1.0