You've already forked openshot-qt
mirror of
https://github.com/OpenShot/openshot-qt.git
synced 2026-06-08 22:18:12 -07:00
Fix freeze keyframes for trimmed clips and rename "Speed->Reset" to "Speed->Reset Speed"
- Use absolute trim end when adding freeze endpoint keyframes - Add regression coverage for freezing a right-side split clip - Rename Speed > Reset to Speed > Reset Speed - Update clip docs to match the new menu label
This commit is contained in:
+2
-2
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user