33 from copy
import deepcopy
34 from functools
import partial
35 from random
import uniform
36 from urllib.parse
import urlparse
39 from PyQt5.QtCore import QFileInfo, pyqtSlot, QUrl, Qt, QCoreApplication, QTimer
41 from PyQt5.QtWebKitWidgets
import QWebView
44 from classes
import info, updates
45 from classes
import settings
46 from classes.app
import get_app
47 from classes.logger
import log
48 from classes.query
import File, Clip, Transition, Track
49 from classes.waveform
import get_audio_data
50 from classes.thumbnail
import GenerateThumbnail
51 from classes.conversion
import zoomToSeconds, secondsToZoom
56 import simplejson
as json
59 JS_SCOPE_SELECTOR =
"$('body').scope()" 64 MENU_FADE_OUT_FAST = 3
65 MENU_FADE_OUT_SLOW = 4
66 MENU_FADE_IN_OUT_FAST = 5
67 MENU_FADE_IN_OUT_SLOW = 6
70 MENU_ROTATE_90_RIGHT = 1
71 MENU_ROTATE_90_LEFT = 2
72 MENU_ROTATE_180_FLIP = 3
75 MENU_LAYOUT_CENTER = 1
76 MENU_LAYOUT_TOP_LEFT = 2
77 MENU_LAYOUT_TOP_RIGHT = 3
78 MENU_LAYOUT_BOTTOM_LEFT = 4
79 MENU_LAYOUT_BOTTOM_RIGHT = 5
80 MENU_LAYOUT_ALL_WITH_ASPECT = 6
81 MENU_LAYOUT_ALL_WITHOUT_ASPECT = 7
87 MENU_ANIMATE_IN_50_100 = 1
88 MENU_ANIMATE_IN_75_100 = 2
89 MENU_ANIMATE_IN_100_150 = 3
90 MENU_ANIMATE_OUT_100_75 = 4
91 MENU_ANIMATE_OUT_100_50 = 5
92 MENU_ANIMATE_OUT_150_100 = 6
93 MENU_ANIMATE_CENTER_TOP = 7
94 MENU_ANIMATE_CENTER_LEFT = 8
95 MENU_ANIMATE_CENTER_RIGHT = 9
96 MENU_ANIMATE_CENTER_BOTTOM = 10
97 MENU_ANIMATE_TOP_CENTER = 11
98 MENU_ANIMATE_LEFT_CENTER = 12
99 MENU_ANIMATE_RIGHT_CENTER = 13
100 MENU_ANIMATE_BOTTOM_CENTER = 14
101 MENU_ANIMATE_TOP_BOTTOM = 15
102 MENU_ANIMATE_LEFT_RIGHT = 16
103 MENU_ANIMATE_RIGHT_LEFT = 17
104 MENU_ANIMATE_BOTTOM_TOP = 18
105 MENU_ANIMATE_RANDOM = 19
108 MENU_VOLUME_FADE_IN_FAST = 2
109 MENU_VOLUME_FADE_IN_SLOW = 3
110 MENU_VOLUME_FADE_OUT_FAST = 4
111 MENU_VOLUME_FADE_OUT_SLOW = 5
112 MENU_VOLUME_FADE_IN_OUT_FAST = 6
113 MENU_VOLUME_FADE_IN_OUT_SLOW = 7
114 MENU_VOLUME_LEVEL_100 = 100
115 MENU_VOLUME_LEVEL_90 = 90
116 MENU_VOLUME_LEVEL_80 = 80
117 MENU_VOLUME_LEVEL_70 = 70
118 MENU_VOLUME_LEVEL_60 = 60
119 MENU_VOLUME_LEVEL_50 = 50
120 MENU_VOLUME_LEVEL_40 = 40
121 MENU_VOLUME_LEVEL_30 = 30
122 MENU_VOLUME_LEVEL_20 = 20
123 MENU_VOLUME_LEVEL_10 = 10
124 MENU_VOLUME_LEVEL_0 = 0
129 MENU_TIME_FORWARD = 1
130 MENU_TIME_BACKWARD = 2
132 MENU_TIME_FREEZE_ZOOM = 4
136 MENU_COPY_KEYFRAMES_ALL = 1
137 MENU_COPY_KEYFRAMES_ALPHA = 2
138 MENU_COPY_KEYFRAMES_SCALE = 3
139 MENU_COPY_KEYFRAMES_ROTATE = 4
140 MENU_COPY_KEYFRAMES_LOCATION = 5
141 MENU_COPY_KEYFRAMES_TIME = 6
142 MENU_COPY_KEYFRAMES_VOLUME = 7
143 MENU_COPY_EFFECTS = 8
146 MENU_COPY_TRANSITION = 10
147 MENU_COPY_KEYFRAMES_BRIGHTNESS = 11
148 MENU_COPY_KEYFRAMES_CONTRAST = 12
150 MENU_SLICE_KEEP_BOTH = 0
151 MENU_SLICE_KEEP_LEFT = 1
152 MENU_SLICE_KEEP_RIGHT = 2
154 MENU_SPLIT_AUDIO_SINGLE = 0
155 MENU_SPLIT_AUDIO_MULTIPLE = 1
163 html_path = os.path.join(info.PATH,
'timeline',
'index.html')
175 log.error(
"TimelineWebView::eval_js() called before document ready event. Script queued: %s" % code)
176 QTimer.singleShot(50, partial(self.
eval_js, code))
180 return self.page().mainFrame().evaluateJavaScript(code)
185 if action.type ==
"load":
188 self.
eval_js(JS_SCOPE_SELECTOR +
".SetTrackLabel('" + _(
"Track %s") +
"');")
191 code = JS_SCOPE_SELECTOR +
".LoadJson(" + action.json() +
");" 194 code = JS_SCOPE_SELECTOR +
".ApplyJsonDiff([" + action.json() +
"]);" 198 if action.type ==
"load":
200 initial_scale =
get_app().project.get([
"scale"])
or 16
211 if not isinstance(clip_json, dict):
212 clip_data = json.loads(clip_json)
214 clip_data = clip_json
220 existing_clip = Clip.get(id=clip_data[
"id"])
221 if not existing_clip:
223 existing_clip = Clip()
226 start_changed =
False 227 if existing_clip.data
and existing_clip.data[
"start"] != clip_data[
"start"]
and clip_data[
"reader"][
"has_video"]
and not clip_data[
"reader"][
"has_single_image"]:
232 existing_clip.data = clip_data
236 existing_clip.data = {}
237 existing_clip.data[
"id"] = clip_data[
"id"]
238 existing_clip.data[
"layer"] = clip_data[
"layer"]
239 existing_clip.data[
"position"] = clip_data[
"position"]
240 existing_clip.data[
"image"] = clip_data[
"image"]
241 existing_clip.data[
"start"] = clip_data[
"start"]
242 existing_clip.data[
"end"] = clip_data[
"end"]
245 if ignore_reader
and "reader" in existing_clip.data:
246 existing_clip.data.pop(
"reader")
252 get_app().window.refreshFrameSignal.emit()
253 get_app().window.propertyTableView.select_frame(self.
window.preview_thread.player.Position())
261 fps = clip_data[
"reader"][
"fps"]
262 fps_float = float(fps[
"num"]) / float(fps[
"den"])
265 start_frame = round(float(clip_data[
"start"]) * fps_float) + 1
268 thumb_path = os.path.join(info.THUMBNAIL_PATH,
"{}-{}.png".format(clip_data[
"id"], start_frame))
269 log.info(
'Updating thumbnail image: %s' % thumb_path)
272 if not os.path.exists(thumb_path):
275 file = File.get(id=clip_data[
"file_id"])
282 file_path = file.absolute_path()
286 if file.data[
"media_type"] ==
"video":
287 overlay_path = os.path.join(info.IMAGES_PATH,
"overlay.png")
290 GenerateThumbnail(file_path, thumb_path, start_frame, 98, 64, os.path.join(info.IMAGES_PATH,
"mask.png"), overlay_path)
293 clip_data[
"image"] = thumb_path
299 transition_details = json.loads(transition_json)
302 fps =
get_app().project.get([
"fps"])
303 fps_float = float(fps[
"num"]) / float(fps[
"den"])
306 transition_reader = openshot.QtImageReader(
307 os.path.join(info.PATH,
"transitions",
"common",
"fade.svg"))
310 transition_object = openshot.Mask()
313 brightness = transition_object.brightness
314 brightness.AddPoint(1, 1.0, openshot.BEZIER)
315 brightness.AddPoint(round(transition_details[
"end"] * fps_float) + 1, -1.0, openshot.BEZIER)
316 contrast = openshot.Keyframe(3.0)
320 "id":
get_app().project.generate_id(),
321 "layer": transition_details[
"layer"],
322 "title":
"Transition",
324 "position": transition_details[
"position"],
325 "start": transition_details[
"start"],
326 "end": transition_details[
"end"],
327 "brightness": json.loads(brightness.Json()),
328 "contrast": json.loads(contrast.Json()),
329 "reader": json.loads(transition_reader.Json()),
330 "replace_image":
False 343 if not isinstance(transition_json, dict):
344 transition_data = json.loads(transition_json)
346 transition_data = transition_json
349 existing_item = Transition.get(id=transition_data[
"id"])
351 if not existing_item:
353 existing_item = Transition()
355 existing_item.data = transition_data
358 fps =
get_app().project.get([
"fps"])
359 fps_float = float(fps[
"num"]) / float(fps[
"den"])
360 duration = existing_item.data[
"end"] - existing_item.data[
"start"]
368 brightness = existing_item.data[
"brightness"]
369 if len(brightness[
"Points"]) > 1:
371 brightness[
"Points"][-1][
"co"][
"X"] = round(duration * fps_float) + 1
374 contrast = existing_item.data[
"contrast"]
375 if len(contrast[
"Points"]) > 1:
377 contrast[
"Points"][-1][
"co"][
"X"] = round(duration * fps_float) + 1
380 b = openshot.Keyframe()
381 b.AddPoint(1, 1.0, openshot.BEZIER)
382 b.AddPoint(round(duration * fps_float) + 1, -1.0, openshot.BEZIER)
383 brightness = json.loads(b.Json())
387 existing_item.data = {}
388 existing_item.data[
"id"] = transition_data[
"id"]
389 existing_item.data[
"layer"] = transition_data[
"layer"]
390 existing_item.data[
"position"] = transition_data[
"position"]
391 existing_item.data[
"start"] = transition_data[
"start"]
392 existing_item.data[
"end"] = transition_data[
"end"]
394 log.info(
'transition start: %s' % transition_data[
"start"])
395 log.info(
'transition end: %s' % transition_data[
"end"])
398 existing_item.data[
"brightness"] = brightness
400 existing_item.data[
"contrast"] = contrast
406 get_app().window.refreshFrameSignal.emit()
407 get_app().window.propertyTableView.select_frame(self.
window.preview_thread.player.Position())
416 log.info(
'ShowPlayheadMenu: %s' % position)
422 intersecting_clips = Clip.filter(intersect=position)
423 intersecting_trans = Transition.filter(intersect=position)
426 if intersecting_clips
or intersecting_trans:
428 clip_ids = [c.id
for c
in intersecting_clips]
429 trans_ids = [t.id
for t
in intersecting_trans]
432 Slice_Menu = QMenu(_(
"Slice All"), self)
433 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
434 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, clip_ids, trans_ids, position))
435 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
436 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, clip_ids, trans_ids, position))
437 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
438 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, clip_ids, trans_ids, position))
439 menu.addMenu(Slice_Menu)
440 return menu.popup(QCursor.pos())
444 log.info(
'ShowEffectMenu: %s' % effect_id)
451 menu.addAction(self.
window.actionProperties)
455 menu.addAction(self.
window.actionRemoveEffect)
456 return menu.popup(QCursor.pos())
458 @pyqtSlot(float, int)
460 log.info(
'ShowTimelineMenu: position: %s, layer: %s' % (position, layer_id))
467 clipboard_clip_ids = [k
for k, v
in self.
copy_clipboard.items()
if v.get(
'id')]
472 if len(clipboard_clip_ids) + len(clipboard_tran_ids) > 0:
474 Paste_Clip = menu.addAction(_(
"Paste"))
475 Paste_Clip.setShortcut(QKeySequence(self.
window.getShortcutByName(
"pasteAll")))
476 Paste_Clip.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, float(position), int(layer_id), [], []))
478 return menu.popup(QCursor.pos())
482 log.info(
'ShowClipMenu: %s' % clip_id)
488 clip = Clip.get(id=clip_id)
494 if clip_id
not in self.
window.selected_clips:
497 clip_ids = self.
window.selected_clips
498 tran_ids = self.
window.selected_transitions
501 fps =
get_app().project.get([
"fps"])
502 fps_float = float(fps[
"num"]) / float(fps[
"den"])
505 playhead_position = float(self.
window.preview_thread.current_frame) / fps_float
508 translations = [_(
"Start of Clip"), _(
"End of Clip"), _(
"Entire Clip"), _(
"Normal"), _(
"Fast"), _(
"Slow"), _(
"Forward"), _(
"Backward")]
514 if len(tran_ids) + len(clip_ids) > 1:
516 Copy_All = menu.addAction(_(
"Copy"))
517 Copy_All.setShortcut(QKeySequence(self.
window.getShortcutByName(
"copyAll")))
518 Copy_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_ALL, clip_ids, tran_ids))
521 Copy_Menu = QMenu(_(
"Copy"), self)
522 Copy_Clip = Copy_Menu.addAction(_(
"Clip"))
523 Copy_Clip.setShortcut(QKeySequence(self.
window.getShortcutByName(
"copyAll")))
524 Copy_Clip.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_CLIP, [clip_id], []))
526 Keyframe_Menu = QMenu(_(
"Keyframes"), self)
527 Copy_Keyframes_All = Keyframe_Menu.addAction(_(
"All"))
528 Copy_Keyframes_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALL, [clip_id], []))
529 Keyframe_Menu.addSeparator()
530 Copy_Keyframes_Alpha = Keyframe_Menu.addAction(_(
"Alpha"))
531 Copy_Keyframes_Alpha.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALPHA, [clip_id], []))
532 Copy_Keyframes_Scale = Keyframe_Menu.addAction(_(
"Scale"))
533 Copy_Keyframes_Scale.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_SCALE, [clip_id], []))
534 Copy_Keyframes_Rotate = Keyframe_Menu.addAction(_(
"Rotation"))
535 Copy_Keyframes_Rotate.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ROTATE, [clip_id], []))
536 Copy_Keyframes_Locate = Keyframe_Menu.addAction(_(
"Location"))
537 Copy_Keyframes_Locate.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_LOCATION, [clip_id], []))
538 Copy_Keyframes_Time = Keyframe_Menu.addAction(_(
"Time"))
539 Copy_Keyframes_Time.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_TIME, [clip_id], []))
540 Copy_Keyframes_Volume = Keyframe_Menu.addAction(_(
"Volume"))
541 Copy_Keyframes_Volume.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_VOLUME, [clip_id], []))
544 Copy_Effects = Copy_Menu.addAction(_(
"Effects"))
545 Copy_Effects.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_EFFECTS, [clip_id], []))
546 Copy_Menu.addMenu(Keyframe_Menu)
547 menu.addMenu(Copy_Menu)
551 clipboard_clip_ids = [k
for k, v
in self.
copy_clipboard.items()
if v.get(
'id')]
554 if self.
copy_clipboard and len(clipboard_clip_ids) + len(clipboard_tran_ids) == 0:
556 Paste_Clip = menu.addAction(_(
"Paste"))
557 Paste_Clip.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, 0.0, 0, clip_ids, []))
562 if len(clip_ids) > 1:
563 Alignment_Menu = QMenu(_(
"Align"), self)
564 Align_Left = Alignment_Menu.addAction(_(
"Left"))
565 Align_Left.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_LEFT, clip_ids, tran_ids))
566 Align_Right = Alignment_Menu.addAction(_(
"Right"))
567 Align_Right.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_RIGHT, clip_ids, tran_ids))
570 menu.addMenu(Alignment_Menu)
573 Fade_Menu = QMenu(_(
"Fade"), self)
574 Fade_None = Fade_Menu.addAction(_(
"No Fade"))
575 Fade_None.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_NONE, clip_ids))
576 Fade_Menu.addSeparator()
577 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
578 Position_Menu = QMenu(_(position), self)
580 if position ==
"Start of Clip":
581 Fade_In_Fast = Position_Menu.addAction(_(
"Fade In (Fast)"))
582 Fade_In_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_FAST, clip_ids, position))
583 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Slow)"))
584 Fade_In_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_SLOW, clip_ids, position))
586 elif position ==
"End of Clip":
587 Fade_Out_Fast = Position_Menu.addAction(_(
"Fade Out (Fast)"))
588 Fade_Out_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_FAST, clip_ids, position))
589 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Slow)"))
590 Fade_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_SLOW, clip_ids, position))
593 Fade_In_Out_Fast = Position_Menu.addAction(_(
"Fade In and Out (Fast)"))
594 Fade_In_Out_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_OUT_FAST, clip_ids, position))
595 Fade_In_Out_Slow = Position_Menu.addAction(_(
"Fade In and Out (Slow)"))
596 Fade_In_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_OUT_SLOW, clip_ids, position))
597 Position_Menu.addSeparator()
598 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Entire Clip)"))
599 Fade_In_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_SLOW, clip_ids, position))
600 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Entire Clip)"))
601 Fade_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_SLOW, clip_ids, position))
603 Fade_Menu.addMenu(Position_Menu)
604 menu.addMenu(Fade_Menu)
608 Animate_Menu = QMenu(_(
"Animate"), self)
609 Animate_None = Animate_Menu.addAction(_(
"No Animation"))
610 Animate_None.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_NONE, clip_ids))
611 Animate_Menu.addSeparator()
612 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
613 Position_Menu = QMenu(_(position), self)
616 Scale_Menu = QMenu(_(
"Zoom"), self)
617 Animate_In_50_100 = Scale_Menu.addAction(_(
"Zoom In (50% to 100%)"))
618 Animate_In_50_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_50_100, clip_ids, position))
619 Animate_In_75_100 = Scale_Menu.addAction(_(
"Zoom In (75% to 100%)"))
620 Animate_In_75_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_75_100, clip_ids, position))
621 Animate_In_100_150 = Scale_Menu.addAction(_(
"Zoom In (100% to 150%)"))
622 Animate_In_100_150.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_100_150, clip_ids, position))
623 Animate_Out_100_75 = Scale_Menu.addAction(_(
"Zoom Out (100% to 75%)"))
624 Animate_Out_100_75.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_100_75, clip_ids, position))
625 Animate_Out_100_50 = Scale_Menu.addAction(_(
"Zoom Out (100% to 50%)"))
626 Animate_Out_100_50.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_100_50, clip_ids, position))
627 Animate_Out_150_100 = Scale_Menu.addAction(_(
"Zoom Out (150% to 100%)"))
628 Animate_Out_150_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_150_100, clip_ids, position))
629 Position_Menu.addMenu(Scale_Menu)
632 Center_Edge_Menu = QMenu(_(
"Center to Edge"), self)
633 Animate_Center_Top = Center_Edge_Menu.addAction(_(
"Center to Top"))
634 Animate_Center_Top.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_TOP, clip_ids, position))
635 Animate_Center_Left = Center_Edge_Menu.addAction(_(
"Center to Left"))
636 Animate_Center_Left.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_LEFT, clip_ids, position))
637 Animate_Center_Right = Center_Edge_Menu.addAction(_(
"Center to Right"))
638 Animate_Center_Right.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_RIGHT, clip_ids, position))
639 Animate_Center_Bottom = Center_Edge_Menu.addAction(_(
"Center to Bottom"))
640 Animate_Center_Bottom.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_BOTTOM, clip_ids, position))
641 Position_Menu.addMenu(Center_Edge_Menu)
644 Edge_Center_Menu = QMenu(_(
"Edge to Center"), self)
645 Animate_Top_Center = Edge_Center_Menu.addAction(_(
"Top to Center"))
646 Animate_Top_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_TOP_CENTER, clip_ids, position))
647 Animate_Left_Center = Edge_Center_Menu.addAction(_(
"Left to Center"))
648 Animate_Left_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_LEFT_CENTER, clip_ids, position))
649 Animate_Right_Center = Edge_Center_Menu.addAction(_(
"Right to Center"))
650 Animate_Right_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RIGHT_CENTER, clip_ids, position))
651 Animate_Bottom_Center = Edge_Center_Menu.addAction(_(
"Bottom to Center"))
652 Animate_Bottom_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_BOTTOM_CENTER, clip_ids, position))
653 Position_Menu.addMenu(Edge_Center_Menu)
656 Edge_Edge_Menu = QMenu(_(
"Edge to Edge"), self)
657 Animate_Top_Bottom = Edge_Edge_Menu.addAction(_(
"Top to Bottom"))
658 Animate_Top_Bottom.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_TOP_BOTTOM, clip_ids, position))
659 Animate_Left_Right = Edge_Edge_Menu.addAction(_(
"Left to Right"))
660 Animate_Left_Right.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_LEFT_RIGHT, clip_ids, position))
661 Animate_Right_Left = Edge_Edge_Menu.addAction(_(
"Right to Left"))
662 Animate_Right_Left.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RIGHT_LEFT, clip_ids, position))
663 Animate_Bottom_Top = Edge_Edge_Menu.addAction(_(
"Bottom to Top"))
664 Animate_Bottom_Top.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_BOTTOM_TOP, clip_ids, position))
665 Position_Menu.addMenu(Edge_Edge_Menu)
668 Position_Menu.addSeparator()
669 Random = Position_Menu.addAction(_(
"Random"))
670 Random.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RANDOM, clip_ids, position))
673 Animate_Menu.addMenu(Position_Menu)
676 menu.addMenu(Animate_Menu)
679 Rotation_Menu = QMenu(_(
"Rotate"), self)
680 Rotation_None = Rotation_Menu.addAction(_(
"No Rotation"))
681 Rotation_None.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_NONE, clip_ids))
682 Rotation_Menu.addSeparator()
683 Rotation_90_Right = Rotation_Menu.addAction(_(
"Rotate 90 (Right)"))
684 Rotation_90_Right.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_90_RIGHT, clip_ids))
685 Rotation_90_Left = Rotation_Menu.addAction(_(
"Rotate 90 (Left)"))
686 Rotation_90_Left.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_90_LEFT, clip_ids))
687 Rotation_180_Flip = Rotation_Menu.addAction(_(
"Rotate 180 (Flip)"))
688 Rotation_180_Flip.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_180_FLIP, clip_ids))
689 menu.addMenu(Rotation_Menu)
692 Layout_Menu = QMenu(_(
"Layout"), self)
693 Layout_None = Layout_Menu.addAction(_(
"Reset Layout"))
694 Layout_None.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_NONE, clip_ids))
695 Layout_Menu.addSeparator()
696 Layout_Center = Layout_Menu.addAction(_(
"1/4 Size - Center"))
697 Layout_Center.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_CENTER, clip_ids))
698 Layout_Top_Left = Layout_Menu.addAction(_(
"1/4 Size - Top Left"))
699 Layout_Top_Left.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_TOP_LEFT, clip_ids))
700 Layout_Top_Right = Layout_Menu.addAction(_(
"1/4 Size - Top Right"))
701 Layout_Top_Right.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_TOP_RIGHT, clip_ids))
702 Layout_Bottom_Left = Layout_Menu.addAction(_(
"1/4 Size - Bottom Left"))
703 Layout_Bottom_Left.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_BOTTOM_LEFT, clip_ids))
704 Layout_Bottom_Right = Layout_Menu.addAction(_(
"1/4 Size - Bottom Right"))
705 Layout_Bottom_Right.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_BOTTOM_RIGHT, clip_ids))
706 Layout_Menu.addSeparator()
707 Layout_Bottom_All_With_Aspect = Layout_Menu.addAction(_(
"Show All (Maintain Ratio)"))
708 Layout_Bottom_All_With_Aspect.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_ALL_WITH_ASPECT, clip_ids))
709 Layout_Bottom_All_Without_Aspect = Layout_Menu.addAction(_(
"Show All (Distort)"))
710 Layout_Bottom_All_Without_Aspect.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_ALL_WITHOUT_ASPECT, clip_ids))
711 menu.addMenu(Layout_Menu)
714 Time_Menu = QMenu(_(
"Time"), self)
715 Time_None = Time_Menu.addAction(_(
"Reset Time"))
716 Time_None.triggered.connect(partial(self.
Time_Triggered, MENU_TIME_NONE, clip_ids,
'1X'))
717 Time_Menu.addSeparator()
718 for speed, speed_values
in [(
"Normal", [
'1X']), (
"Fast", [
'2X',
'4X',
'8X',
'16X',
'32X']), (
"Slow", [
'1/2X',
'1/4X',
'1/8X',
'1/16X',
'1/32X'])]:
719 Speed_Menu = QMenu(_(speed), self)
721 for direction, direction_value
in [(
"Forward", MENU_TIME_FORWARD), (
"Backward", MENU_TIME_BACKWARD)]:
722 Direction_Menu = QMenu(_(direction), self)
724 for actual_speed
in speed_values:
726 Time_Option = Direction_Menu.addAction(_(actual_speed))
727 Time_Option.triggered.connect(partial(self.
Time_Triggered, direction_value, clip_ids, actual_speed))
730 Speed_Menu.addMenu(Direction_Menu)
732 Time_Menu.addMenu(Speed_Menu)
735 Time_Menu.addSeparator()
736 for freeze_type, trigger_type
in [(_(
"Freeze"), MENU_TIME_FREEZE), (_(
"Freeze && Zoom"), MENU_TIME_FREEZE_ZOOM)]:
737 Freeze_Menu = QMenu(freeze_type, self)
739 for freeze_seconds
in [2, 4, 6, 8, 10, 20, 30]:
741 Time_Option = Freeze_Menu.addAction(_(
'{} seconds').format(freeze_seconds))
742 Time_Option.triggered.connect(partial(self.
Time_Triggered, trigger_type, clip_ids, freeze_seconds, playhead_position))
745 Time_Menu.addMenu(Freeze_Menu)
748 menu.addMenu(Time_Menu)
751 Volume_Menu = QMenu(_(
"Volume"), self)
752 Volume_None = Volume_Menu.addAction(_(
"Reset Volume"))
753 Volume_None.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_NONE, clip_ids))
754 Volume_Menu.addSeparator()
755 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
756 Position_Menu = QMenu(_(position), self)
758 if position ==
"Start of Clip":
759 Fade_In_Fast = Position_Menu.addAction(_(
"Fade In (Fast)"))
760 Fade_In_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_FAST, clip_ids, position))
761 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Slow)"))
762 Fade_In_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_SLOW, clip_ids, position))
764 elif position ==
"End of Clip":
765 Fade_Out_Fast = Position_Menu.addAction(_(
"Fade Out (Fast)"))
766 Fade_Out_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_FAST, clip_ids, position))
767 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Slow)"))
768 Fade_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_SLOW, clip_ids, position))
771 Fade_In_Out_Fast = Position_Menu.addAction(_(
"Fade In and Out (Fast)"))
772 Fade_In_Out_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_OUT_FAST, clip_ids, position))
773 Fade_In_Out_Slow = Position_Menu.addAction(_(
"Fade In and Out (Slow)"))
774 Fade_In_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_OUT_SLOW, clip_ids, position))
775 Position_Menu.addSeparator()
776 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Entire Clip)"))
777 Fade_In_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_SLOW, clip_ids, position))
778 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Entire Clip)"))
779 Fade_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_SLOW, clip_ids, position))
782 Position_Menu.addSeparator()
783 Volume_100 = Position_Menu.addAction(_(
"Level 100%"))
784 Volume_100.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_100, clip_ids, position))
785 Volume_90 = Position_Menu.addAction(_(
"Level 90%"))
786 Volume_90.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_90, clip_ids, position))
787 Volume_80 = Position_Menu.addAction(_(
"Level 80%"))
788 Volume_80.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_80, clip_ids, position))
789 Volume_70 = Position_Menu.addAction(_(
"Level 70%"))
790 Volume_70.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_70, clip_ids, position))
791 Volume_60 = Position_Menu.addAction(_(
"Level 60%"))
792 Volume_60.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_60, clip_ids, position))
793 Volume_50 = Position_Menu.addAction(_(
"Level 50%"))
794 Volume_50.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_50, clip_ids, position))
795 Volume_40 = Position_Menu.addAction(_(
"Level 40%"))
796 Volume_40.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_40, clip_ids, position))
797 Volume_30 = Position_Menu.addAction(_(
"Level 30%"))
798 Volume_30.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_30, clip_ids, position))
799 Volume_20 = Position_Menu.addAction(_(
"Level 20%"))
800 Volume_20.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_20, clip_ids, position))
801 Volume_10 = Position_Menu.addAction(_(
"Level 10%"))
802 Volume_10.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_10, clip_ids, position))
803 Volume_0 = Position_Menu.addAction(_(
"Level 0%"))
804 Volume_0.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_0, clip_ids, position))
806 Volume_Menu.addMenu(Position_Menu)
807 menu.addMenu(Volume_Menu)
810 Split_Audio_Channels_Menu = QMenu(_(
"Separate Audio"), self)
811 Split_Single_Clip = Split_Audio_Channels_Menu.addAction(_(
"Single Clip (all channels)"))
812 Split_Single_Clip.triggered.connect(partial(self.
Split_Audio_Triggered, MENU_SPLIT_AUDIO_SINGLE, clip_ids))
813 Split_Multiple_Clips = Split_Audio_Channels_Menu.addAction(_(
"Multiple Clips (each channel)"))
814 Split_Multiple_Clips.triggered.connect(partial(self.
Split_Audio_Triggered, MENU_SPLIT_AUDIO_MULTIPLE, clip_ids))
815 menu.addMenu(Split_Audio_Channels_Menu)
819 start_of_clip = float(clip.data[
"start"])
820 end_of_clip = float(clip.data[
"end"])
821 position_of_clip = float(clip.data[
"position"])
822 if playhead_position >= position_of_clip
and playhead_position <= (position_of_clip + (end_of_clip - start_of_clip)):
824 Slice_Menu = QMenu(_(
"Slice"), self)
825 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
826 Slice_Keep_Both.setShortcut(QKeySequence(self.
window.getShortcutByName(
"sliceAllKeepBothSides")))
827 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, [clip_id], [], playhead_position))
828 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
829 Slice_Keep_Left.setShortcut(QKeySequence(self.
window.getShortcutByName(
"sliceAllKeepLeftSide")))
830 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, [clip_id], [], playhead_position))
831 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
832 Slice_Keep_Right.setShortcut(QKeySequence(self.
window.getShortcutByName(
"sliceAllKeepRightSide")))
833 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, [clip_id], [], playhead_position))
834 menu.addMenu(Slice_Menu)
837 Transform_Action = self.
window.actionTransform
838 Transform_Action.triggered.connect(partial(self.
Transform_Triggered, MENU_TRANSFORM, clip_ids))
839 menu.addAction(Transform_Action)
843 Waveform_Menu = QMenu(_(
"Display"), self)
844 ShowWaveform = Waveform_Menu.addAction(_(
"Show Waveform"))
846 HideWaveform = Waveform_Menu.addAction(_(
"Show Thumbnail"))
848 menu.addMenu(Waveform_Menu)
851 menu.addAction(self.
window.actionProperties)
855 menu.addAction(self.
window.actionRemoveClip)
858 return menu.popup(QCursor.pos())
861 print(
"Transform_Triggered")
866 get_app().window.TransformSignal.emit(clip_ids[0])
869 get_app().window.TransformSignal.emit(
"")
876 for clip_id
in clip_ids:
879 clip = Clip.get(id=clip_id)
884 file_path = clip.data[
"reader"][
"path"]
888 clips =
get_app().window.timeline_sync.timeline.Clips()
889 for clip_object
in clips:
890 if clip_object.Id() == clip_id:
893 if c
and c.Reader()
and not c.Reader().info.has_single_image:
895 channel_filter = c.channel_filter.GetInt(1)
898 get_app().setOverrideCursor(QCursor(Qt.WaitCursor))
901 channel_filter = channel_filter
909 for clip_id
in clip_ids:
912 clip = Clip.get(id=clip_id)
916 cmd = JS_SCOPE_SELECTOR +
".hideAudioData('" + clip_id +
"');" 917 self.page().mainFrame().evaluateJavaScript(cmd)
922 log.info(
"Waveform_Ready for clip ID: %s" % (clip_id))
925 serialized_audio_data = json.dumps(audio_data)
928 cmd = JS_SCOPE_SELECTOR +
".setAudioData('" + clip_id +
"', " + serialized_audio_data +
");" 929 self.page().mainFrame().evaluateJavaScript(cmd)
932 get_app().restoreOverrideCursor()
937 log.info(
"Split_Audio_Triggered")
943 for clip_id
in clip_ids:
946 clip = Clip.get(id=clip_id)
960 p = openshot.Point(1, -1.0, openshot.CONSTANT)
961 p_object = json.loads(p.Json())
962 clip.data[
"has_audio"] = {
"Points" : [p_object]}
971 clip_title = clip.data[
"title"]
973 if action == MENU_SPLIT_AUDIO_SINGLE:
975 p = openshot.Point(1, -1.0, openshot.CONSTANT)
976 p_object = json.loads(p.Json())
977 clip.data[
"channel_filter"] = {
"Points" : [p_object]}
980 p = openshot.Point(1, 0.0, openshot.CONSTANT)
981 p_object = json.loads(p.Json())
982 clip.data[
"has_video"] = {
"Points" : [p_object]}
985 clip.data[
'layer'] = clip.data[
'layer'] - 1
988 channel_label = _(
"(all channels)")
989 clip.data[
"title"] = clip_title +
" " + channel_label
993 if action == MENU_SPLIT_AUDIO_MULTIPLE:
995 channels = int(clip.data[
"reader"][
"channels"])
998 for channel
in range(0, channels):
999 log.info(
"Adding clip for channel %s" % channel)
1002 p = openshot.Point(1, channel, openshot.CONSTANT)
1003 p_object = json.loads(p.Json())
1004 clip.data[
"channel_filter"] = {
"Points" : [p_object]}
1007 p = openshot.Point(1, 0.0, openshot.CONSTANT)
1008 p_object = json.loads(p.Json())
1009 clip.data[
"has_video"] = {
"Points" : [p_object]}
1012 clip.data[
'layer'] = max(clip.data[
'layer'] - 1, 0)
1015 channel_label = _(
"(channel %s)") % (channel + 1)
1016 clip.data[
"title"] = clip_title +
" " + channel_label
1023 clip.type =
'insert' 1026 for clip_id
in clip_ids:
1029 clip = Clip.get(id=clip_id)
1035 p = openshot.Point(1, 0.0, openshot.CONSTANT)
1036 p_object = json.loads(p.Json())
1037 clip.data[
"has_audio"] = {
"Points" : [p_object]}
1041 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1050 for clip_id
in clip_ids:
1053 clip = Clip.get(id=clip_id)
1058 new_gravity = openshot.GRAVITY_CENTER
1059 if action == MENU_LAYOUT_CENTER:
1060 new_gravity = openshot.GRAVITY_CENTER
1061 if action == MENU_LAYOUT_TOP_LEFT:
1062 new_gravity = openshot.GRAVITY_TOP_LEFT
1063 elif action == MENU_LAYOUT_TOP_RIGHT:
1064 new_gravity = openshot.GRAVITY_TOP_RIGHT
1065 elif action == MENU_LAYOUT_BOTTOM_LEFT:
1066 new_gravity = openshot.GRAVITY_BOTTOM_LEFT
1067 elif action == MENU_LAYOUT_BOTTOM_RIGHT:
1068 new_gravity = openshot.GRAVITY_BOTTOM_RIGHT
1070 if action == MENU_LAYOUT_NONE:
1072 clip.data[
"scale"] = openshot.SCALE_FIT
1073 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1076 p = openshot.Point(1, 1.0, openshot.BEZIER)
1077 p_object = json.loads(p.Json())
1078 clip.data[
"scale_x"] = {
"Points" : [p_object]}
1079 clip.data[
"scale_y"] = {
"Points" : [p_object]}
1082 p = openshot.Point(1, 0.0, openshot.BEZIER)
1083 p_object = json.loads(p.Json())
1084 clip.data[
"location_x"] = {
"Points" : [p_object]}
1085 clip.data[
"location_y"] = {
"Points" : [p_object]}
1087 if action == MENU_LAYOUT_CENTER
or \
1088 action == MENU_LAYOUT_TOP_LEFT
or \
1089 action == MENU_LAYOUT_TOP_RIGHT
or \
1090 action == MENU_LAYOUT_BOTTOM_LEFT
or \
1091 action == MENU_LAYOUT_BOTTOM_RIGHT:
1093 clip.data[
"scale"] = openshot.SCALE_FIT
1094 clip.data[
"gravity"] = new_gravity
1097 p = openshot.Point(1, 0.5, openshot.BEZIER)
1098 p_object = json.loads(p.Json())
1099 clip.data[
"scale_x"] = {
"Points" : [p_object]}
1100 clip.data[
"scale_y"] = {
"Points" : [p_object]}
1103 p = openshot.Point(1, 0.0, openshot.BEZIER)
1104 p_object = json.loads(p.Json())
1105 clip.data[
"location_x"] = {
"Points" : [p_object]}
1106 clip.data[
"location_y"] = {
"Points" : [p_object]}
1109 if action == MENU_LAYOUT_ALL_WITH_ASPECT:
1113 elif action == MENU_LAYOUT_ALL_WITHOUT_ASPECT:
1119 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1127 for clip_id
in clip_ids:
1130 clip = Clip.get(id=clip_id)
1136 fps =
get_app().project.get([
"fps"])
1137 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1140 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1141 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1145 start_animation = start_of_clip
1146 end_animation = end_of_clip
1147 if position ==
"Start of Clip":
1148 start_animation = start_of_clip
1149 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1150 elif position ==
"End of Clip":
1151 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1152 end_animation = end_of_clip
1154 if action == MENU_ANIMATE_NONE:
1156 default_zoom = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1157 default_zoom_object = json.loads(default_zoom.Json())
1158 default_loc = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1159 default_loc_object = json.loads(default_loc.Json())
1160 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1161 clip.data[
"scale_x"] = {
"Points" : [default_zoom_object]}
1162 clip.data[
"scale_y"] = {
"Points" : [default_zoom_object]}
1163 clip.data[
"location_x"] = {
"Points" : [default_loc_object]}
1164 clip.data[
"location_y"] = {
"Points" : [default_loc_object]}
1166 if action
in [MENU_ANIMATE_IN_50_100, MENU_ANIMATE_IN_75_100, MENU_ANIMATE_IN_100_150, MENU_ANIMATE_OUT_100_75, MENU_ANIMATE_OUT_100_50, MENU_ANIMATE_OUT_150_100]:
1170 if action == MENU_ANIMATE_IN_50_100:
1172 elif action == MENU_ANIMATE_IN_75_100:
1174 elif action == MENU_ANIMATE_IN_100_150:
1176 elif action == MENU_ANIMATE_OUT_100_75:
1178 elif action == MENU_ANIMATE_OUT_100_50:
1180 elif action == MENU_ANIMATE_OUT_150_100:
1184 start = openshot.Point(start_animation, start_scale, openshot.BEZIER)
1185 start_object = json.loads(start.Json())
1186 end = openshot.Point(end_animation, end_scale, openshot.BEZIER)
1187 end_object = json.loads(end.Json())
1188 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1189 clip.data[
"scale_x"][
"Points"].append(start_object)
1190 clip.data[
"scale_x"][
"Points"].append(end_object)
1191 clip.data[
"scale_y"][
"Points"].append(start_object)
1192 clip.data[
"scale_y"][
"Points"].append(end_object)
1195 if action
in [MENU_ANIMATE_CENTER_TOP, MENU_ANIMATE_CENTER_LEFT, MENU_ANIMATE_CENTER_RIGHT, MENU_ANIMATE_CENTER_BOTTOM,
1196 MENU_ANIMATE_TOP_CENTER, MENU_ANIMATE_LEFT_CENTER, MENU_ANIMATE_RIGHT_CENTER, MENU_ANIMATE_BOTTOM_CENTER,
1197 MENU_ANIMATE_TOP_BOTTOM, MENU_ANIMATE_LEFT_RIGHT, MENU_ANIMATE_RIGHT_LEFT, MENU_ANIMATE_BOTTOM_TOP]:
1199 animate_start_x = 0.0
1201 animate_start_y = 0.0
1204 if action == MENU_ANIMATE_CENTER_TOP:
1205 animate_end_y = -1.0
1206 elif action == MENU_ANIMATE_CENTER_LEFT:
1207 animate_end_x = -1.0
1208 elif action == MENU_ANIMATE_CENTER_RIGHT:
1210 elif action == MENU_ANIMATE_CENTER_BOTTOM:
1214 elif action == MENU_ANIMATE_TOP_CENTER:
1215 animate_start_y = -1.0
1216 elif action == MENU_ANIMATE_LEFT_CENTER:
1217 animate_start_x = -1.0
1218 elif action == MENU_ANIMATE_RIGHT_CENTER:
1219 animate_start_x = 1.0
1220 elif action == MENU_ANIMATE_BOTTOM_CENTER:
1221 animate_start_y = 1.0
1224 elif action == MENU_ANIMATE_TOP_BOTTOM:
1225 animate_start_y = -1.0
1227 elif action == MENU_ANIMATE_LEFT_RIGHT:
1228 animate_start_x = -1.0
1230 elif action == MENU_ANIMATE_RIGHT_LEFT:
1231 animate_start_x = 1.0
1232 animate_end_x = -1.0
1233 elif action == MENU_ANIMATE_BOTTOM_TOP:
1234 animate_start_y = 1.0
1235 animate_end_y = -1.0
1238 start_x = openshot.Point(start_animation, animate_start_x, openshot.BEZIER)
1239 start_x_object = json.loads(start_x.Json())
1240 end_x = openshot.Point(end_animation, animate_end_x, openshot.BEZIER)
1241 end_x_object = json.loads(end_x.Json())
1242 start_y = openshot.Point(start_animation, animate_start_y, openshot.BEZIER)
1243 start_y_object = json.loads(start_y.Json())
1244 end_y = openshot.Point(end_animation, animate_end_y, openshot.BEZIER)
1245 end_y_object = json.loads(end_y.Json())
1246 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1247 clip.data[
"location_x"][
"Points"].append(start_x_object)
1248 clip.data[
"location_x"][
"Points"].append(end_x_object)
1249 clip.data[
"location_y"][
"Points"].append(start_y_object)
1250 clip.data[
"location_y"][
"Points"].append(end_y_object)
1252 if action == MENU_ANIMATE_RANDOM:
1254 animate_start_x = uniform(-0.5, 0.5)
1255 animate_end_x = uniform(-0.15, 0.15)
1256 animate_start_y = uniform(-0.5, 0.5)
1257 animate_end_y = uniform(-0.15, 0.15)
1260 start_scale = uniform(0.5, 1.5)
1261 end_scale = uniform(0.85, 1.15)
1264 start = openshot.Point(start_animation, start_scale, openshot.BEZIER)
1265 start_object = json.loads(start.Json())
1266 end = openshot.Point(end_animation, end_scale, openshot.BEZIER)
1267 end_object = json.loads(end.Json())
1268 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1269 clip.data[
"scale_x"][
"Points"].append(start_object)
1270 clip.data[
"scale_x"][
"Points"].append(end_object)
1271 clip.data[
"scale_y"][
"Points"].append(start_object)
1272 clip.data[
"scale_y"][
"Points"].append(end_object)
1275 start_x = openshot.Point(start_animation, animate_start_x, openshot.BEZIER)
1276 start_x_object = json.loads(start_x.Json())
1277 end_x = openshot.Point(end_animation, animate_end_x, openshot.BEZIER)
1278 end_x_object = json.loads(end_x.Json())
1279 start_y = openshot.Point(start_animation, animate_start_y, openshot.BEZIER)
1280 start_y_object = json.loads(start_y.Json())
1281 end_y = openshot.Point(end_animation, animate_end_y, openshot.BEZIER)
1282 end_y_object = json.loads(end_y.Json())
1283 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1284 clip.data[
"location_x"][
"Points"].append(start_x_object)
1285 clip.data[
"location_x"][
"Points"].append(end_x_object)
1286 clip.data[
"location_y"][
"Points"].append(start_y_object)
1287 clip.data[
"location_y"][
"Points"].append(end_y_object)
1290 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1302 for clip_id
in clip_ids:
1305 clip = Clip.get(id=clip_id)
1312 if action == MENU_COPY_CLIP
or action == MENU_COPY_ALL:
1314 elif action == MENU_COPY_KEYFRAMES_ALL:
1320 self.
copy_clipboard[clip_id][
'location_x'] = clip.data[
'location_x']
1321 self.
copy_clipboard[clip_id][
'location_y'] = clip.data[
'location_y']
1324 elif action == MENU_COPY_KEYFRAMES_ALPHA:
1326 elif action == MENU_COPY_KEYFRAMES_SCALE:
1330 elif action == MENU_COPY_KEYFRAMES_ROTATE:
1333 elif action == MENU_COPY_KEYFRAMES_LOCATION:
1335 self.
copy_clipboard[clip_id][
'location_x'] = clip.data[
'location_x']
1336 self.
copy_clipboard[clip_id][
'location_y'] = clip.data[
'location_y']
1337 elif action == MENU_COPY_KEYFRAMES_TIME:
1339 elif action == MENU_COPY_KEYFRAMES_VOLUME:
1341 elif action == MENU_COPY_EFFECTS:
1345 for tran_id
in tran_ids:
1348 tran = Transition.get(id=tran_id)
1355 if action == MENU_COPY_TRANSITION
or action == MENU_COPY_ALL:
1357 elif action == MENU_COPY_KEYFRAMES_ALL:
1360 elif action == MENU_COPY_KEYFRAMES_BRIGHTNESS:
1362 elif action == MENU_COPY_KEYFRAMES_CONTRAST:
1372 clipboard_clip_ids = [k
for k, v
in self.
copy_clipboard.items()
if v.get(
'id')]
1376 if len(clipboard_clip_ids) + len(clipboard_tran_ids):
1377 left_most_position = -1.0
1380 for clip_id
in clipboard_clip_ids:
1384 if clip.data[
'position'] < left_most_position
or left_most_position == -1.0:
1385 left_most_position = clip.data[
'position']
1386 if clip.data[
'layer'] > top_most_layer
or top_most_layer == -1.0:
1387 top_most_layer = clip.data[
'layer']
1389 for tran_id
in clipboard_tran_ids:
1393 if tran.data[
'position'] < left_most_position
or left_most_position == -1.0:
1394 left_most_position = tran.data[
'position']
1395 if tran.data[
'layer'] > top_most_layer
or top_most_layer == -1.0:
1396 top_most_layer = tran.data[
'layer']
1400 layer_id = top_most_layer
1403 position_diff = position - left_most_position
1404 layer_diff = layer_id - top_most_layer
1407 for clip_id
in clipboard_clip_ids:
1413 clip.type =
'insert' 1417 clip.data[
'position'] += position_diff
1418 clip.data[
'layer'] += layer_diff
1424 for tran_id
in clipboard_tran_ids:
1430 tran.type =
'insert' 1434 tran.data[
'position'] += position_diff
1435 tran.data[
'layer'] += layer_diff
1442 for clip_id
in clip_ids:
1445 clip = Clip.get(id=clip_id)
1461 for tran_id
in tran_ids:
1464 tran = Transition.get(id=tran_id)
1482 prop_name =
"position" 1487 for clip_id
in clip_ids:
1489 clip = Clip.get(id=clip_id)
1494 position = float(clip.data[
"position"])
1495 start_of_clip = float(clip.data[
"start"])
1496 end_of_clip = float(clip.data[
"end"])
1498 if position < left_edge
or left_edge == -1.0:
1499 left_edge = position
1500 if position + (end_of_clip - start_of_clip) > right_edge
or right_edge == -1.0:
1501 right_edge = position + (end_of_clip - start_of_clip)
1504 for tran_id
in tran_ids:
1506 tran = Transition.get(id=tran_id)
1511 position = float(tran.data[
"position"])
1512 start_of_tran = float(tran.data[
"start"])
1513 end_of_tran = float(tran.data[
"end"])
1515 if position < left_edge
or left_edge == -1.0:
1516 left_edge = position
1517 if position + (end_of_tran - start_of_tran) > right_edge
or right_edge == -1.0:
1518 right_edge = position + (end_of_tran - start_of_tran)
1522 for clip_id
in clip_ids:
1524 clip = Clip.get(id=clip_id)
1529 if action == MENU_ALIGN_LEFT:
1530 clip.data[
'position'] = left_edge
1531 elif action == MENU_ALIGN_RIGHT:
1532 position = float(clip.data[
"position"])
1533 start_of_clip = float(clip.data[
"start"])
1534 end_of_clip = float(clip.data[
"end"])
1535 right_clip_edge = position + (end_of_clip - start_of_clip)
1537 clip.data[
'position'] = position + (right_edge - right_clip_edge)
1540 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1543 for tran_id
in tran_ids:
1545 tran = Transition.get(id=tran_id)
1550 if action == MENU_ALIGN_LEFT:
1551 tran.data[
'position'] = left_edge
1552 elif action == MENU_ALIGN_RIGHT:
1553 position = float(tran.data[
"position"])
1554 start_of_tran = float(tran.data[
"start"])
1555 end_of_tran = float(tran.data[
"end"])
1556 right_tran_edge = position + (end_of_tran - start_of_tran)
1558 tran.data[
'position'] = position + (right_edge - right_tran_edge)
1570 fps =
get_app().project.get([
"fps"])
1571 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1574 for clip_id
in clip_ids:
1577 clip = Clip.get(id=clip_id)
1582 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1583 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1587 start_animation = start_of_clip
1588 end_animation = end_of_clip
1589 if position ==
"Start of Clip" and action
in [MENU_FADE_IN_FAST, MENU_FADE_OUT_FAST]:
1590 start_animation = start_of_clip
1591 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1592 elif position ==
"Start of Clip" and action
in [MENU_FADE_IN_SLOW, MENU_FADE_OUT_SLOW]:
1593 start_animation = start_of_clip
1594 end_animation = min(start_of_clip + (3.0 * fps_float), end_of_clip)
1595 elif position ==
"End of Clip" and action
in [MENU_FADE_IN_FAST, MENU_FADE_OUT_FAST]:
1596 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1597 end_animation = end_of_clip
1598 elif position ==
"End of Clip" and action
in [MENU_FADE_IN_SLOW, MENU_FADE_OUT_SLOW]:
1599 start_animation = max(1.0, end_of_clip - (3.0 * fps_float))
1600 end_animation = end_of_clip
1603 if position ==
"Entire Clip" and action == MENU_FADE_IN_OUT_FAST:
1605 self.
Fade_Triggered(MENU_FADE_IN_FAST, clip_ids,
"Start of Clip")
1608 elif position ==
"Entire Clip" and action == MENU_FADE_IN_OUT_SLOW:
1610 self.
Fade_Triggered(MENU_FADE_IN_SLOW, clip_ids,
"Start of Clip")
1614 if action == MENU_FADE_NONE:
1616 p = openshot.Point(1, 1.0, openshot.BEZIER)
1617 p_object = json.loads(p.Json())
1618 clip.data[prop_name] = {
"Points" : [p_object]}
1620 if action
in [MENU_FADE_IN_FAST, MENU_FADE_IN_SLOW]:
1622 start = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1623 start_object = json.loads(start.Json())
1624 end = openshot.Point(end_animation, 1.0, openshot.BEZIER)
1625 end_object = json.loads(end.Json())
1626 clip.data[prop_name][
"Points"].append(start_object)
1627 clip.data[prop_name][
"Points"].append(end_object)
1629 if action
in [MENU_FADE_OUT_FAST, MENU_FADE_OUT_SLOW]:
1631 start = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1632 start_object = json.loads(start.Json())
1633 end = openshot.Point(end_animation, 0.0, openshot.BEZIER)
1634 end_object = json.loads(end.Json())
1635 clip.data[prop_name][
"Points"].append(start_object)
1636 clip.data[prop_name][
"Points"].append(end_object)
1639 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1641 @pyqtSlot(str, str, float)
1647 slice_mode = MENU_SLICE_KEEP_BOTH
1648 if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
1649 slice_mode = MENU_SLICE_KEEP_RIGHT
1650 elif int(QCoreApplication.instance().keyboardModifiers() & Qt.ShiftModifier) > 0:
1651 slice_mode = MENU_SLICE_KEEP_LEFT
1655 QTimer.singleShot(0, partial(self.
Slice_Triggered, slice_mode, [clip_id], [], cursor_position))
1658 QTimer.singleShot(0, partial(self.
Slice_Triggered, slice_mode, [], [trans_id], cursor_position))
1664 fps =
get_app().project.get([
"fps"])
1665 fps_num = fps[
"num"]
1666 fps_den = fps[
"den"]
1670 playhead_position = float(round((playhead_position * fps_num) / fps_den ) * fps_den ) / fps_num
1673 for clip_id
in clip_ids:
1676 clip = Clip.get(id=clip_id)
1682 has_audio_data = bool(self.
eval_js(JS_SCOPE_SELECTOR +
".hasAudioData('" + clip_id +
"');"))
1684 if action == MENU_SLICE_KEEP_LEFT
or action == MENU_SLICE_KEEP_BOTH:
1686 position_of_clip = float(clip.data[
"position"])
1687 start_of_clip = float(clip.data[
"start"])
1690 clip.data[
"end"] = start_of_clip + (playhead_position - position_of_clip)
1692 elif action == MENU_SLICE_KEEP_RIGHT:
1694 position_of_clip = float(clip.data[
"position"])
1695 start_of_clip = float(clip.data[
"start"])
1698 clip.data[
"position"] = playhead_position
1699 clip.data[
"start"] = start_of_clip + (playhead_position - position_of_clip)
1704 if action == MENU_SLICE_KEEP_BOTH:
1707 right_clip = Clip.get(id=clip_id)
1713 right_clip.id =
None 1714 right_clip.type =
'insert' 1715 right_clip.data.pop(
'id')
1716 right_clip.key.pop(1)
1719 position_of_clip = float(right_clip.data[
"position"])
1720 start_of_clip = float(right_clip.data[
"start"])
1723 right_clip.data[
"position"] = playhead_position
1724 right_clip.data[
"start"] = start_of_clip + (playhead_position - position_of_clip)
1733 self.
update_clip_data(right_clip.data, only_basic_props=
False, ignore_reader=
True)
1737 log.info(
"Generate right splice waveform for clip id: %s" % right_clip.id)
1741 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1745 log.info(
"Generate left splice waveform for clip id: %s" % clip.id)
1750 for trans_id
in trans_ids:
1752 trans = Transition.get(id=trans_id)
1757 if action == MENU_SLICE_KEEP_LEFT
or action == MENU_SLICE_KEEP_BOTH:
1759 position_of_tran = float(trans.data[
"position"])
1762 trans.data[
"end"] = playhead_position - position_of_tran
1764 elif action == MENU_SLICE_KEEP_RIGHT:
1766 position_of_tran = float(trans.data[
"position"])
1767 end_of_tran = float(trans.data[
"end"])
1770 trans.data[
"position"] = playhead_position
1771 trans.data[
"end"] = end_of_tran - (playhead_position - position_of_tran)
1773 if action == MENU_SLICE_KEEP_BOTH:
1776 right_tran = Transition.get(id=trans_id)
1782 right_tran.id =
None 1783 right_tran.type =
'insert' 1784 right_tran.data.pop(
'id')
1785 right_tran.key.pop(1)
1788 position_of_tran = float(right_tran.data[
"position"])
1789 end_of_tran = float(right_tran.data[
"end"])
1792 right_tran.data[
"position"] = playhead_position
1793 right_tran.data[
"end"] = end_of_tran - (playhead_position - position_of_tran)
1808 prop_name =
"volume" 1811 fps =
get_app().project.get([
"fps"])
1812 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1815 for clip_id
in clip_ids:
1818 clip = Clip.get(id=clip_id)
1823 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1824 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1828 start_animation = start_of_clip
1829 end_animation = end_of_clip
1830 if position ==
"Start of Clip" and action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_OUT_FAST]:
1831 start_animation = start_of_clip
1832 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1833 elif position ==
"Start of Clip" and action
in [MENU_VOLUME_FADE_IN_SLOW, MENU_VOLUME_FADE_OUT_SLOW]:
1834 start_animation = start_of_clip
1835 end_animation = min(start_of_clip + (3.0 * fps_float), end_of_clip)
1836 elif position ==
"End of Clip" and action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_OUT_FAST]:
1837 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1838 end_animation = end_of_clip
1839 elif position ==
"End of Clip" and action
in [MENU_VOLUME_FADE_IN_SLOW, MENU_VOLUME_FADE_OUT_SLOW]:
1840 start_animation = max(1.0, end_of_clip - (3.0 * fps_float))
1841 end_animation = end_of_clip
1842 elif position ==
"Start of Clip":
1844 start_animation = start_of_clip
1845 end_animation = start_of_clip
1846 elif position ==
"End of Clip":
1848 start_animation = end_of_clip
1849 end_animation = end_of_clip
1852 if position ==
"Entire Clip" and action == MENU_VOLUME_FADE_IN_OUT_FAST:
1857 elif position ==
"Entire Clip" and action == MENU_VOLUME_FADE_IN_OUT_SLOW:
1863 if action == MENU_VOLUME_NONE:
1865 p = openshot.Point(1, 1.0, openshot.BEZIER)
1866 p_object = json.loads(p.Json())
1867 clip.data[prop_name] = {
"Points" : [p_object]}
1869 if action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_IN_SLOW]:
1871 start = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1872 start_object = json.loads(start.Json())
1873 end = openshot.Point(end_animation, 1.0, openshot.BEZIER)
1874 end_object = json.loads(end.Json())
1875 clip.data[prop_name][
"Points"].append(start_object)
1876 clip.data[prop_name][
"Points"].append(end_object)
1878 if action
in [MENU_VOLUME_FADE_OUT_FAST, MENU_VOLUME_FADE_OUT_SLOW]:
1880 start = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1881 start_object = json.loads(start.Json())
1882 end = openshot.Point(end_animation, 0.0, openshot.BEZIER)
1883 end_object = json.loads(end.Json())
1884 clip.data[prop_name][
"Points"].append(start_object)
1885 clip.data[prop_name][
"Points"].append(end_object)
1887 if action
in [MENU_VOLUME_LEVEL_100, MENU_VOLUME_LEVEL_90, MENU_VOLUME_LEVEL_80, MENU_VOLUME_LEVEL_70,
1888 MENU_VOLUME_LEVEL_60, MENU_VOLUME_LEVEL_50, MENU_VOLUME_LEVEL_40, MENU_VOLUME_LEVEL_30,
1889 MENU_VOLUME_LEVEL_20, MENU_VOLUME_LEVEL_10, MENU_VOLUME_LEVEL_0]:
1891 p = openshot.Point(start_animation, float(action) / 100.0, openshot.BEZIER)
1892 p_object = json.loads(p.Json())
1893 clip.data[prop_name][
"Points"].append(p_object)
1896 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1899 has_audio_data = bool(self.
eval_js(JS_SCOPE_SELECTOR +
".hasAudioData('" + clip.id +
"');"))
1908 prop_name =
"rotation" 1911 fps =
get_app().project.get([
"fps"])
1912 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1915 for clip_id
in clip_ids:
1918 clip = Clip.get(id=clip_id)
1923 if action == MENU_ROTATE_NONE:
1925 p = openshot.Point(1, 0.0, openshot.BEZIER)
1926 p_object = json.loads(p.Json())
1927 clip.data[prop_name] = {
"Points" : [p_object]}
1929 if action == MENU_ROTATE_90_RIGHT:
1931 p = openshot.Point(1, 90.0, openshot.BEZIER)
1932 p_object = json.loads(p.Json())
1933 clip.data[prop_name] = {
"Points" : [p_object]}
1935 if action == MENU_ROTATE_90_LEFT:
1937 p = openshot.Point(1, -90.0, openshot.BEZIER)
1938 p_object = json.loads(p.Json())
1939 clip.data[prop_name] = {
"Points" : [p_object]}
1941 if action == MENU_ROTATE_180_FLIP:
1943 p = openshot.Point(1, 180.0, openshot.BEZIER)
1944 p_object = json.loads(p.Json())
1945 clip.data[prop_name] = {
"Points" : [p_object]}
1948 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1957 fps =
get_app().project.get([
"fps"])
1958 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1961 for clip_id
in clip_ids:
1964 clip = Clip.get(id=clip_id)
1970 if "original_data" not in clip.data.keys():
1971 clip.data[
"original_data"] = {
"end": clip.data[
"end"],
1972 "duration": clip.data[
"duration"],
1973 "video_length": clip.data[
"reader"][
"video_length"]}
1979 if action
in [MENU_TIME_FREEZE, MENU_TIME_FREEZE_ZOOM]:
1981 freeze_seconds = float(speed)
1983 original_duration = clip.data[
"duration"]
1984 if "original_data" in clip.data.keys():
1985 original_duration = clip.data[
"original_data"][
"duration"]
1987 print(
'ORIGINAL DURATION: %s' % original_duration)
1991 clip.data[
"end"] = float(clip.data[
"end"]) + freeze_seconds
1992 clip.data[
"duration"] = float(clip.data[
"duration"]) + freeze_seconds
1993 clip.data[
"reader"][
"video_length"] = float(clip.data[
"reader"][
"video_length"]) + freeze_seconds
1996 freeze_length_frames = round(freeze_seconds * fps_float) + 1
1997 start_animation_seconds = float(clip.data[
"start"]) + (playhead_position - float(clip.data[
"position"]))
1998 start_animation_frames = round(start_animation_seconds * fps_float) + 1
1999 start_animation_frames_value = start_animation_frames
2000 end_animation_seconds = start_animation_seconds + freeze_seconds
2001 end_animation_frames = round(end_animation_seconds * fps_float) + 1
2002 end_of_clip_seconds = float(clip.data[
"duration"])
2003 end_of_clip_frames = round((end_of_clip_seconds) * fps_float) + 1
2004 end_of_clip_frames_value = round((original_duration) * fps_float) + 1
2007 start_volume_value = 1.0
2010 if len(clip.data[
"time"][
"Points"]) > 1:
2013 del clip.data[
"time"][
"Points"][-1]
2017 clips =
get_app().window.timeline_sync.timeline.Clips()
2018 for clip_object
in clips:
2019 if clip_object.Id() == clip_id:
2024 start_animation_frames_value = c.time.GetLong(start_animation_frames)
2027 if len(clip.data[
"volume"][
"Points"]) > 1:
2030 clips =
get_app().window.timeline_sync.timeline.Clips()
2031 for clip_object
in clips:
2032 if clip_object.Id() == clip_id:
2037 start_volume_value = c.volume.GetValue(start_animation_frames)
2040 p = openshot.Point(start_animation_frames, start_animation_frames_value, openshot.LINEAR)
2041 p_object = json.loads(p.Json())
2042 clip.data[prop_name][
"Points"].append(p_object)
2043 p1 = openshot.Point(end_animation_frames, start_animation_frames_value, openshot.LINEAR)
2044 p1_object = json.loads(p1.Json())
2045 clip.data[prop_name][
"Points"].append(p1_object)
2046 p2 = openshot.Point(end_of_clip_frames, end_of_clip_frames_value, openshot.LINEAR)
2047 p2_object = json.loads(p2.Json())
2048 clip.data[prop_name][
"Points"].append(p2_object)
2051 p = openshot.Point(start_animation_frames - 1, start_volume_value, openshot.LINEAR)
2052 p_object = json.loads(p.Json())
2053 clip.data[
'volume'][
"Points"].append(p_object)
2054 p = openshot.Point(start_animation_frames, 0.0, openshot.LINEAR)
2055 p_object = json.loads(p.Json())
2056 clip.data[
'volume'][
"Points"].append(p_object)
2057 p2 = openshot.Point(end_animation_frames - 1, 0.0, openshot.LINEAR)
2058 p2_object = json.loads(p2.Json())
2059 clip.data[
'volume'][
"Points"].append(p2_object)
2060 p3 = openshot.Point(end_animation_frames, start_volume_value, openshot.LINEAR)
2061 p3_object = json.loads(p3.Json())
2062 clip.data[
'volume'][
"Points"].append(p3_object)
2065 if action == MENU_TIME_FREEZE_ZOOM:
2066 p = openshot.Point(start_animation_frames, 1.0, openshot.BEZIER)
2067 p_object = json.loads(p.Json())
2068 clip.data[
'scale_x'][
"Points"].append(p_object)
2069 p = openshot.Point(start_animation_frames, 1.0, openshot.BEZIER)
2070 p_object = json.loads(p.Json())
2071 clip.data[
'scale_y'][
"Points"].append(p_object)
2073 diff_halfed = (end_animation_frames - start_animation_frames) / 2.0
2074 p1 = openshot.Point(start_animation_frames + diff_halfed, 1.05, openshot.BEZIER)
2075 p1_object = json.loads(p1.Json())
2076 clip.data[
'scale_x'][
"Points"].append(p1_object)
2077 p1 = openshot.Point(start_animation_frames + diff_halfed, 1.05, openshot.BEZIER)
2078 p1_object = json.loads(p1.Json())
2079 clip.data[
'scale_y'][
"Points"].append(p1_object)
2081 p1 = openshot.Point(end_animation_frames, 1.0, openshot.BEZIER)
2082 p1_object = json.loads(p1.Json())
2083 clip.data[
'scale_x'][
"Points"].append(p1_object)
2084 p1 = openshot.Point(end_animation_frames, 1.0, openshot.BEZIER)
2085 p1_object = json.loads(p1.Json())
2086 clip.data[
'scale_y'][
"Points"].append(p1_object)
2091 speed_label = speed.replace(
'X',
'')
2092 speed_parts = speed_label.split(
'/')
2094 if len(speed_parts) == 2:
2095 speed_factor = float(speed_parts[0]) / float(speed_parts[1])
2096 even_multiple = int(speed_parts[1])
2098 speed_factor = float(speed_label)
2099 even_multiple = int(speed_factor)
2102 p = openshot.Point(start_animation, 0.0, openshot.LINEAR)
2103 p_object = json.loads(p.Json())
2104 clip.data[prop_name] = {
"Points" : [p_object]}
2107 if "original_data" in clip.data.keys():
2108 clip.data[
"end"] = clip.data[
"original_data"][
"end"]
2109 clip.data[
"duration"] = clip.data[
"original_data"][
"duration"]
2110 clip.data[
"reader"][
"video_length"] = clip.data[
"original_data"][
"video_length"]
2111 clip.data.pop(
"original_data")
2114 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
2117 start_animation = round(float(clip.data[
"start"]) * fps_float) + 1
2118 duration_animation = self.
round_to_multiple(end_of_clip - start_animation, even_multiple)
2119 end_animation = start_animation + duration_animation
2121 if action == MENU_TIME_FORWARD:
2123 start = openshot.Point(start_animation, start_animation, openshot.LINEAR)
2124 start_object = json.loads(start.Json())
2125 clip.data[prop_name] = {
"Points" : [start_object]}
2126 end = openshot.Point(start_animation + (duration_animation / speed_factor), end_animation, openshot.LINEAR)
2127 end_object = json.loads(end.Json())
2128 clip.data[prop_name][
"Points"].append(end_object)
2131 clip.data[
"end"] = (start_animation + (duration_animation / speed_factor)) / fps_float
2132 clip.data[
"duration"] = self.
round_to_multiple(clip.data[
"duration"] / speed_factor, even_multiple)
2133 clip.data[
"reader"][
"video_length"] = str(self.
round_to_multiple(float(clip.data[
"reader"][
"video_length"]) / speed_factor, even_multiple))
2135 if action == MENU_TIME_BACKWARD:
2137 start = openshot.Point(start_animation, end_animation, openshot.LINEAR)
2138 start_object = json.loads(start.Json())
2139 clip.data[prop_name] = {
"Points" : [start_object]}
2140 end = openshot.Point(start_animation + (duration_animation / speed_factor), start_animation, openshot.LINEAR)
2141 end_object = json.loads(end.Json())
2142 clip.data[prop_name][
"Points"].append(end_object)
2145 clip.data[
"end"] = (start_animation + (duration_animation / speed_factor)) / fps_float
2146 clip.data[
"duration"] = self.
round_to_multiple(clip.data[
"duration"] / speed_factor, even_multiple)
2147 clip.data[
"reader"][
"video_length"] = str(self.
round_to_multiple(float(clip.data[
"reader"][
"video_length"]) / speed_factor, even_multiple))
2150 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2155 return number - (number % multiple)
2160 from math
import sqrt
2163 available_clips = []
2164 start_position = float(clip.data[
"position"])
2165 for c
in Clip.filter():
2166 if float(c.data[
"position"]) >= (start_position - 0.5)
and float(c.data[
"position"]) <= (start_position + 0.5):
2168 available_clips.append(c)
2171 number_of_clips = len(available_clips)
2172 number_of_rows = int(sqrt(number_of_clips))
2173 max_clips_on_row = float(number_of_clips) / float(number_of_rows)
2176 if max_clips_on_row > float(int(max_clips_on_row)):
2177 max_clips_on_row = int(max_clips_on_row + 1)
2179 max_clips_on_row = int(max_clips_on_row)
2182 height = 1.0 / float(number_of_rows)
2183 width = 1.0 / float(max_clips_on_row)
2188 for row
in range(0, number_of_rows):
2191 column_string =
" - - - " 2192 for col
in range(0, max_clips_on_row):
2193 if clip_index < number_of_clips:
2195 X = float(col) * width
2196 Y = float(row) * height
2199 selected_clip = available_clips[clip_index]
2200 selected_clip.data[
"gravity"] = openshot.GRAVITY_TOP_LEFT
2203 selected_clip.data[
"scale"] = openshot.SCALE_STRETCH
2205 selected_clip.data[
"scale"] = openshot.SCALE_FIT
2208 w = openshot.Point(1, width, openshot.BEZIER)
2209 w_object = json.loads(w.Json())
2210 selected_clip.data[
"scale_x"] = {
"Points" : [w_object]}
2211 h = openshot.Point(1, height, openshot.BEZIER)
2212 h_object = json.loads(h.Json())
2213 selected_clip.data[
"scale_y"] = {
"Points" : [h_object]}
2214 x_point = openshot.Point(1, X, openshot.BEZIER)
2215 x_object = json.loads(x_point.Json())
2216 selected_clip.data[
"location_x"] = {
"Points" : [x_object]}
2217 y_point = openshot.Point(1, Y, openshot.BEZIER)
2218 y_object = json.loads(y_point.Json())
2219 selected_clip.data[
"location_y"] = {
"Points" : [y_object]}
2221 log.info(
'Updating clip id: %s' % selected_clip.data[
"id"])
2222 log.info(
'width: %s, height: %s' % (width, height))
2228 self.
update_clip_data(selected_clip.data, only_basic_props=
False, ignore_reader=
True)
2233 log.info(
"Reverse_Transition_Triggered")
2236 for tran_id
in tran_ids:
2239 tran = Transition.get(id=tran_id)
2245 tran_data_copy = deepcopy(tran.data)
2246 new_index = len(tran.data[
"brightness"][
"Points"])
2247 for point
in tran.data[
"brightness"][
"Points"]:
2249 tran_data_copy[
"brightness"][
"Points"][new_index][
"co"][
"Y"] = point[
"co"][
"Y"]
2250 if "handle_left" in point:
2251 tran_data_copy[
"brightness"][
"Points"][new_index][
"handle_left"][
"Y"] = point[
"handle_left"][
"Y"]
2252 tran_data_copy[
"brightness"][
"Points"][new_index][
"handle_right"][
"Y"] = point[
"handle_right"][
"Y"]
2259 log.info(
'ShowTransitionMenu: %s' % tran_id)
2265 tran = Transition.get(id=tran_id)
2271 if tran_id
not in self.
window.selected_transitions:
2274 tran_ids = self.
window.selected_transitions
2275 clip_ids = self.
window.selected_clips
2278 fps =
get_app().project.get([
"fps"])
2279 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2282 playhead_position = float(self.
window.preview_thread.current_frame) / fps_float
2287 if len(tran_ids) + len(clip_ids) > 1:
2289 Copy_All = menu.addAction(_(
"Copy"))
2290 Copy_All.setShortcut(QKeySequence(self.
window.getShortcutByName(
"copyAll")))
2291 Copy_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_ALL, clip_ids, tran_ids))
2294 Copy_Menu = QMenu(_(
"Copy"), self)
2295 Copy_Tran = Copy_Menu.addAction(_(
"Transition"))
2296 Copy_Tran.setShortcut(QKeySequence(self.
window.getShortcutByName(
"copyAll")))
2297 Copy_Tran.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_TRANSITION, [], [tran_id]))
2299 Keyframe_Menu = QMenu(_(
"Keyframes"), self)
2300 Copy_Keyframes_All = Keyframe_Menu.addAction(_(
"All"))
2301 Copy_Keyframes_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALL, [], [tran_id]))
2302 Keyframe_Menu.addSeparator()
2303 Copy_Keyframes_Brightness = Keyframe_Menu.addAction(_(
"Brightness"))
2304 Copy_Keyframes_Brightness.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_BRIGHTNESS, [], [tran_id]))
2305 Copy_Keyframes_Scale = Keyframe_Menu.addAction(_(
"Contrast"))
2306 Copy_Keyframes_Scale.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_CONTRAST, [], [tran_id]))
2309 Copy_Menu.addMenu(Keyframe_Menu)
2310 menu.addMenu(Copy_Menu)
2314 clipboard_clip_ids = [k
for k, v
in self.
copy_clipboard.items()
if v.get(
'id')]
2319 Paste_Tran = menu.addAction(_(
"Paste"))
2320 Paste_Tran.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, 0.0, 0, [], tran_ids))
2325 if len(clip_ids) > 1:
2326 Alignment_Menu = QMenu(_(
"Align"), self)
2327 Align_Left = Alignment_Menu.addAction(_(
"Left"))
2328 Align_Left.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_LEFT, clip_ids, tran_ids))
2329 Align_Right = Alignment_Menu.addAction(_(
"Right"))
2330 Align_Right.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_RIGHT, clip_ids, tran_ids))
2333 menu.addMenu(Alignment_Menu)
2337 start_of_tran = float(tran.data[
"start"])
2338 end_of_tran = float(tran.data[
"end"])
2339 position_of_tran = float(tran.data[
"position"])
2340 if playhead_position >= position_of_tran
and playhead_position <= (position_of_tran + (end_of_tran - start_of_tran)):
2342 Slice_Menu = QMenu(_(
"Slice"), self)
2343 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
2344 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, [], [tran_id], playhead_position))
2345 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
2346 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, [], [tran_id], playhead_position))
2347 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
2348 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, [], [tran_id], playhead_position))
2349 menu.addMenu(Slice_Menu)
2352 Reverse_Transition = menu.addAction(_(
"Reverse Transition"))
2357 menu.addAction(self.
window.actionProperties)
2361 menu.addAction(self.
window.actionRemoveTransition)
2364 return menu.popup(QCursor.pos())
2368 log.info(
'ShowTrackMenu: %s' % layer_id)
2370 if layer_id
not in self.
window.selected_tracks:
2371 self.
window.selected_tracks = [layer_id]
2374 track = Track.get(id=layer_id)
2377 menu.addAction(self.
window.actionAddTrackAbove)
2378 menu.addAction(self.
window.actionAddTrackBelow)
2379 menu.addAction(self.
window.actionRenameTrack)
2380 if track.data.get(
"lock",
False):
2381 menu.addAction(self.
window.actionUnlockTrack)
2383 menu.addAction(self.
window.actionLockTrack)
2385 menu.addAction(self.
window.actionRemoveTrack)
2386 return menu.popup(QCursor.pos())
2390 log.info(
'ShowMarkerMenu: %s' % marker_id)
2392 if marker_id
not in self.
window.selected_markers:
2393 self.
window.selected_markers = [marker_id]
2396 menu.addAction(self.
window.actionRemoveMarker)
2397 return menu.popup(QCursor.pos())
2403 clip = Clip.get(id=clip_id)
2408 path = clip.data[
'reader'][
'path']
2411 frame_number = max(frame_number, 1)
2412 frame_number = min(frame_number, int(clip.data[
'reader'][
'video_length']))
2415 self.
window.LoadFileSignal.emit(path)
2416 self.
window.SpeedSignal.emit(0)
2419 self.
window.SeekSignal.emit(frame_number)
2421 @pyqtSlot(float, int, str)
2425 self.
window.LoadFileSignal.emit(
'')
2432 self.
window.previewFrame(position_seconds, position_frames, time_code)
2440 code = JS_SCOPE_SELECTOR +
".MovePlayheadToFrame(" + str(position_frames) +
");" 2449 self.
eval_js(JS_SCOPE_SELECTOR +
".SetSnappingMode(%s);" % int(enable_snapping))
2457 self.
eval_js(JS_SCOPE_SELECTOR +
".SetRazorMode(%s);" % int(enable_razor))
2459 @pyqtSlot(str, str, bool)
2487 self.
window.zoomScaleLabel.setText(_(
"{} seconds").format(newScale))
2490 cursor_y = self.mapFromGlobal(self.cursor().pos()).y()
2492 cursor_x = self.mapFromGlobal(self.cursor().pos()).x()
2497 cmd = JS_SCOPE_SELECTOR +
".setScale(" + str(newScale) +
"," + str(cursor_x) +
");" 2498 self.page().mainFrame().evaluateJavaScript(cmd)
2504 get_app().updates.update([
"scale"], newScale)
2509 key_value = event.key()
2510 if (key_value == Qt.Key_Shift
or key_value == Qt.Key_Control):
2513 return QWebView.keyPressEvent(self, event)
2521 if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
2524 steps = int(event.angleDelta().y() / tick_scale)
2525 self.
window.sliderZoom.setValue(self.
window.sliderZoom.value() - self.
window.sliderZoom.pageStep() * steps)
2532 self.page().mainFrame().addToJavaScriptWindowObject(
'timeline', self)
2533 self.page().mainFrame().addToJavaScriptWindowObject(
'mainWindow', self.
window)
2542 if not self.
new_item and not event.mimeData().hasUrls()
and event.mimeData().html():
2550 data = json.loads(event.mimeData().text())
2563 elif not self.
new_item and event.mimeData().hasUrls():
2579 file = File.get(id=file_id)
2585 if (file.data[
"media_type"] ==
"video" or file.data[
"media_type"] ==
"image"):
2587 thumb_path = os.path.join(info.THUMBNAIL_PATH,
"%s.png" % file.data[
"id"])
2590 thumb_path = os.path.join(info.PATH,
"images",
"AudioThumbnail.png")
2593 path, filename = os.path.split(file.data[
"path"])
2596 file_path = file.absolute_path()
2599 c = openshot.Clip(file_path)
2602 new_clip = json.loads(c.Json())
2603 new_clip[
"file_id"] = file.id
2604 new_clip[
"title"] = filename
2605 new_clip[
"image"] = thumb_path
2609 if not new_clip.get(
"reader"):
2614 end_frame = new_clip[
"reader"][
"duration"]
2615 if 'start' in file.data.keys():
2616 new_clip[
"start"] = file.data[
'start']
2617 if 'end' in file.data.keys():
2618 new_clip[
"end"] = file.data[
'end']
2621 top_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2622 new_clip[
"layer"] = top_layer
2625 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2626 new_clip[
"position"] = js_position
2629 new_clip[
"duration"] = new_clip[
"reader"][
"duration"]
2630 if file.data[
"media_type"] ==
"image":
2631 new_clip[
"end"] = self.
settings.get(
"default-image-length")
2634 file_properties_fps = float(file.data[
"fps"][
"num"]) / float(file.data[
"fps"][
"den"])
2635 file_fps = float(new_clip[
"reader"][
"fps"][
"num"]) / float(new_clip[
"reader"][
"fps"][
"den"])
2636 fps_diff = file_fps / file_properties_fps
2637 new_clip[
"reader"][
"fps"][
"num"] = file.data[
"fps"][
"num"]
2638 new_clip[
"reader"][
"fps"][
"den"] = file.data[
"fps"][
"den"]
2640 new_clip[
"reader"][
"duration"] *= fps_diff
2641 new_clip[
"end"] *= fps_diff
2642 new_clip[
"duration"] *= fps_diff
2651 code = JS_SCOPE_SELECTOR +
".StartManualMove('" + self.
item_type +
"', '" + self.
item_id +
"');" 2659 get_app().updates.update([
"duration"], new_duration)
2663 log.info(
"addTransition...")
2666 top_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2669 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2672 fps =
get_app().project.get([
"fps"])
2673 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2676 transition_reader = openshot.QtImageReader(file_ids[0])
2678 brightness = openshot.Keyframe()
2679 brightness.AddPoint(1, 1.0, openshot.BEZIER)
2680 brightness.AddPoint(round(10 * fps_float) + 1, -1.0, openshot.BEZIER)
2681 contrast = openshot.Keyframe(3.0)
2684 transitions_data = {
2685 "id":
get_app().project.generate_id(),
2687 "title":
"Transition",
2689 "position": js_position,
2692 "brightness": json.loads(brightness.Json()),
2693 "contrast": json.loads(contrast.Json()),
2694 "reader": json.loads(transition_reader.Json()),
2695 "replace_image":
False 2702 self.
item_id = transitions_data.get(
'id')
2705 code = JS_SCOPE_SELECTOR +
".StartManualMove('" + self.
item_type +
"', '" + self.
item_id +
"');" 2710 log.info(
"addEffect: %s at %s" % (effect_names, position))
2712 name = effect_names[0]
2715 closest_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2718 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2721 possible_clips = Clip.filter(layer=closest_layer)
2722 for clip
in possible_clips:
2723 if js_position == 0
or (clip.data[
"position"] <= js_position <= clip.data[
"position"] + (
2724 clip.data[
"end"] - clip.data[
"start"])):
2725 log.info(
"Applying effect to clip")
2729 effect = openshot.EffectInfo().CreateEffect(name)
2732 effect.Id(
get_app().project.generate_id())
2733 effect_json = json.loads(effect.Json())
2736 clip.data[
"effects"].append(effect_json)
2739 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2750 if self.
item_type in [
"clip",
"transition"]:
2751 code = JS_SCOPE_SELECTOR +
".MoveItem(" + str(pos.x()) +
", " + str(pos.y()) +
", '" + self.
item_type +
"');" 2756 log.info(
"Dropping item on timeline - item_id: %s, item_type: %s" % (self.
item_id, self.
item_type))
2767 data = json.loads(event.mimeData().text())
2772 get_app().window.filesTreeView.dropEvent(event)
2775 for uri
in event.mimeData().urls():
2776 filepath = uri.toLocalFile()
2777 if os.path.exists(filepath)
and os.path.isfile(filepath):
2779 log.info(
'Adding clip for {}'.format(os.path.basename(filepath)))
2780 for file
in File.filter(path=filepath):
2793 get_app().window.refreshFrameSignal.emit()
2794 get_app().window.propertyTableView.select_frame(self.
window.preview_thread.player.Position())
2799 log.info(
'dragLeaveEvent - Undo drop')
2801 get_app().window.actionRemoveClip.trigger()
2803 get_app().window.actionRemoveTransition.trigger()
2816 log.info(
'redraw_audio_onTimeout')
2822 cmd = JS_SCOPE_SELECTOR +
".reDrawAllAudioData();" 2823 self.page().mainFrame().evaluateJavaScript(cmd)
2830 cmd = JS_SCOPE_SELECTOR +
".ClearAllSelections();" 2831 self.page().mainFrame().evaluateJavaScript(cmd)
2838 cmd = JS_SCOPE_SELECTOR +
".SelectAll();" 2839 self.page().mainFrame().evaluateJavaScript(cmd)
2847 cache_object =
get_app().window.timeline_sync.timeline.GetCache()
2848 if cache_object
and cache_object.Count() > 0:
2850 cache_json =
get_app().window.timeline_sync.timeline.GetCache().Json()
2851 cache_dict = json.loads(cache_json)
2852 cache_version = cache_dict[
"version"]
2858 cmd = JS_SCOPE_SELECTOR +
".RenderCache(" + cache_json +
");" 2859 self.page().mainFrame().evaluateJavaScript(cmd)
2865 QWebView.__init__(self)
2867 self.setAcceptDrops(
True)
2875 get_app().updates.add_listener(self)
2878 self.setUrl(QUrl.fromLocalFile(QFileInfo(self.
html_path).absoluteFilePath()))
2881 self.page().mainFrame().javaScriptWindowObjectCleared.connect(self.
setup_js_data)
2884 window.sliderZoom.valueChanged.connect(self.
update_zoom)
def update_clip_data(self, clip_json, only_basic_props=True, ignore_reader=False)
Create an updateAction and send it to the update manager.
def get_app()
Returns the current QApplication instance of OpenShot.
def Animate_Triggered(self, action, clip_ids, position="Entire Clip")
Callback for the animate context menus.
def page_ready(self)
Document.Ready event has fired, and is initialized.
def zoomToSeconds(zoomValue)
Convert zoom factor (slider position) into scale-seconds.
def Rotate_Triggered(self, action, clip_ids, position="Start of Clip")
Callback for rotate context menus.
def keyPressEvent(self, event)
Keypress callback for timeline.
def add_missing_transition(self, transition_json)
def Time_Triggered(self, action, clip_ids, speed="1X", playhead_position=0.0)
Callback for rotate context menus.
def dropEvent(self, event)
def PlayheadMoved(self, position_seconds, position_frames, time_code)
def secondsToZoom(scaleValue)
Convert a number of seconds to a timeline zoom factor.
def Split_Audio_Triggered(self, action, clip_ids)
Callback for split audio context menus.
def Reverse_Transition_Triggered(self, tran_ids)
Callback for reversing a transition.
def ShowClipMenu(self, clip_id=None)
def Waveform_Ready(self, clip_id, audio_data)
Callback when audio waveform is ready.
def PreviewClipFrame(self, clip_id, frame_number)
def movePlayhead(self, position_frames)
Move the playhead since the position has changed inside OpenShot (probably due to the video player) ...
def ShowTransitionMenu(self, tran_id=None)
def Layout_Triggered(self, action, clip_ids)
Callback for the layout context menus.
def contextMenuEvent(self, event)
def render_cache_json(self)
Render the cached frames to the timeline (called every X seconds), and only if changed.
def Fade_Triggered(self, action, clip_ids, position="Entire Clip")
Callback for fade context menus.
A WebView QWidget used to load the Timeline.
def Align_Triggered(self, action, clip_ids, tran_ids)
Callback for alignment context menus.
def qt_log(self, message=None)
def addSelection(self, item_id, item_type, clear_existing=False)
Add the selected item to the current selection.
def ShowPlayheadMenu(self, position=None)
def redraw_audio_onTimeout(self)
Timer is ready to redraw audio (if any)
def changed(self, action)
def Transform_Triggered(self, action, clip_ids)
def Hide_Waveform_Triggered(self, clip_ids)
Hide the waveform for the selected clip.
def ShowTrackMenu(self, layer_id=None)
def addClip(self, data, position)
def SetRazorMode(self, enable_razor)
Enable / Disable razor mode.
def Show_Waveform_Triggered(self, clip_ids)
Show a waveform for the selected clip.
def addTransition(self, file_ids, position)
def resizeTimeline(self, new_duration)
Resize the duration of the timeline.
def dragLeaveEvent(self, event)
A drag is in-progress and the user moves mouse outside of timeline.
def UpdateClipThumbnail(self, clip_data)
Update the thumbnail image for clips.
def RazorSliceAtCursor(self, clip_id, trans_id, cursor_position)
Callback from javascript that the razor tool was clicked.
def __init__(self, window)
def get_settings()
Get the current QApplication's settings instance.
def round_to_multiple(self, number, multiple)
Round this to the closest multiple of a given #.
def show_all_clips(self, clip, stretch=False)
Show all clips at the same time (arranged col by col, row by row)
def Volume_Triggered(self, action, clip_ids, position="Entire Clip")
Callback for volume context menus.
def wheelEvent(self, event)
def removeSelection(self, item_id, item_type)
Remove the selected clip from the selection.
def GenerateThumbnail(file_path, thumb_path, thumbnail_frame, width, height, mask, overlay)
Create thumbnail image, and check for rotate metadata (if any)
def update_zoom(self, newValue)
def ClearAllSelections(self)
Clear all selections in JavaScript.
def ShowMarkerMenu(self, marker_id=None)
def dragMoveEvent(self, event)
copy_transition_clipboard
def dragEnterEvent(self, event)
def Copy_Triggered(self, action, clip_ids, tran_ids)
Callback for copy context menus.
def SelectAll(self)
Select all clips and transitions in JavaScript.
def SetSnappingMode(self, enable_snapping)
Enable / Disable snapping mode.
def addEffect(self, effect_names, position)
def update_transition_data(self, transition_json, only_basic_props=True)
Create an updateAction and send it to the update manager.
Interface for classes that listen for changes (insert, update, and delete).
def Slice_Triggered(self, action, clip_ids, trans_ids, playhead_position=0)
Callback for slice context menus.
def Paste_Triggered(self, action, position, layer_id, clip_ids, tran_ids)
Callback for paste context menus.
def ShowTimelineMenu(self, position, layer_id)
def ShowEffectMenu(self, effect_id=None)