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 15
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.setShortcut(QKeySequence(self.window.getShortcutByName(
"sliceAllKeepBothSides")))
435 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, clip_ids, trans_ids, position))
436 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
437 Slice_Keep_Left.setShortcut(QKeySequence(self.window.getShortcutByName(
"sliceAllKeepLeftSide")))
438 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, clip_ids, trans_ids, position))
439 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
440 Slice_Keep_Right.setShortcut(QKeySequence(self.window.getShortcutByName(
"sliceAllKeepRightSide")))
441 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, clip_ids, trans_ids, position))
442 menu.addMenu(Slice_Menu)
443 return menu.popup(QCursor.pos())
447 log.info(
'ShowEffectMenu: %s' % effect_id)
450 self.window.addSelection(effect_id,
'effect',
True)
454 menu.addAction(self.window.actionProperties)
458 menu.addAction(self.window.actionRemoveEffect)
459 return menu.popup(QCursor.pos())
461 @pyqtSlot(float, int)
463 log.info(
'ShowTimelineMenu: position: %s, layer: %s' % (position, layer_id))
470 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
471 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
475 if len(clipboard_clip_ids) + len(clipboard_tran_ids) > 0:
477 Paste_Clip = menu.addAction(_(
"Paste"))
478 Paste_Clip.setShortcut(QKeySequence(self.window.getShortcutByName(
"pasteAll")))
479 Paste_Clip.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, float(position), int(layer_id), [], []))
481 return menu.popup(QCursor.pos())
485 log.info(
'ShowClipMenu: %s' % clip_id)
491 clip = Clip.get(id=clip_id)
497 if clip_id
not in self.window.selected_clips:
498 self.window.addSelection(clip_id,
'clip')
500 clip_ids = self.window.selected_clips
501 tran_ids = self.window.selected_transitions
504 fps =
get_app().project.get([
"fps"])
505 fps_float = float(fps[
"num"]) / float(fps[
"den"])
508 playhead_position = float(self.window.preview_thread.current_frame) / fps_float
511 translations = [_(
"Start of Clip"), _(
"End of Clip"), _(
"Entire Clip"), _(
"Normal"), _(
"Fast"), _(
"Slow"), _(
"Forward"), _(
"Backward")]
517 if len(tran_ids) + len(clip_ids) > 1:
519 Copy_All = menu.addAction(_(
"Copy"))
520 Copy_All.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
521 Copy_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_ALL, clip_ids, tran_ids))
524 Copy_Menu = QMenu(_(
"Copy"), self)
525 Copy_Clip = Copy_Menu.addAction(_(
"Clip"))
526 Copy_Clip.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
527 Copy_Clip.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_CLIP, [clip_id], []))
529 Keyframe_Menu = QMenu(_(
"Keyframes"), self)
530 Copy_Keyframes_All = Keyframe_Menu.addAction(_(
"All"))
531 Copy_Keyframes_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALL, [clip_id], []))
532 Keyframe_Menu.addSeparator()
533 Copy_Keyframes_Alpha = Keyframe_Menu.addAction(_(
"Alpha"))
534 Copy_Keyframes_Alpha.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALPHA, [clip_id], []))
535 Copy_Keyframes_Scale = Keyframe_Menu.addAction(_(
"Scale"))
536 Copy_Keyframes_Scale.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_SCALE, [clip_id], []))
537 Copy_Keyframes_Rotate = Keyframe_Menu.addAction(_(
"Rotation"))
538 Copy_Keyframes_Rotate.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ROTATE, [clip_id], []))
539 Copy_Keyframes_Locate = Keyframe_Menu.addAction(_(
"Location"))
540 Copy_Keyframes_Locate.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_LOCATION, [clip_id], []))
541 Copy_Keyframes_Time = Keyframe_Menu.addAction(_(
"Time"))
542 Copy_Keyframes_Time.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_TIME, [clip_id], []))
543 Copy_Keyframes_Volume = Keyframe_Menu.addAction(_(
"Volume"))
544 Copy_Keyframes_Volume.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_VOLUME, [clip_id], []))
547 Copy_Effects = Copy_Menu.addAction(_(
"Effects"))
548 Copy_Effects.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_EFFECTS, [clip_id], []))
549 Copy_Menu.addMenu(Keyframe_Menu)
550 menu.addMenu(Copy_Menu)
554 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
555 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
557 if self.
copy_clipboard and len(clipboard_clip_ids) + len(clipboard_tran_ids) == 0:
559 Paste_Clip = menu.addAction(_(
"Paste"))
560 Paste_Clip.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, 0.0, 0, clip_ids, []))
565 if len(clip_ids) > 1:
566 Alignment_Menu = QMenu(_(
"Align"), self)
567 Align_Left = Alignment_Menu.addAction(_(
"Left"))
568 Align_Left.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_LEFT, clip_ids, tran_ids))
569 Align_Right = Alignment_Menu.addAction(_(
"Right"))
570 Align_Right.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_RIGHT, clip_ids, tran_ids))
573 menu.addMenu(Alignment_Menu)
576 Fade_Menu = QMenu(_(
"Fade"), self)
577 Fade_None = Fade_Menu.addAction(_(
"No Fade"))
578 Fade_None.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_NONE, clip_ids))
579 Fade_Menu.addSeparator()
580 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
581 Position_Menu = QMenu(_(position), self)
583 if position ==
"Start of Clip":
584 Fade_In_Fast = Position_Menu.addAction(_(
"Fade In (Fast)"))
585 Fade_In_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_FAST, clip_ids, position))
586 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Slow)"))
587 Fade_In_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_SLOW, clip_ids, position))
589 elif position ==
"End of Clip":
590 Fade_Out_Fast = Position_Menu.addAction(_(
"Fade Out (Fast)"))
591 Fade_Out_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_FAST, clip_ids, position))
592 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Slow)"))
593 Fade_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_SLOW, clip_ids, position))
596 Fade_In_Out_Fast = Position_Menu.addAction(_(
"Fade In and Out (Fast)"))
597 Fade_In_Out_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_OUT_FAST, clip_ids, position))
598 Fade_In_Out_Slow = Position_Menu.addAction(_(
"Fade In and Out (Slow)"))
599 Fade_In_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_OUT_SLOW, clip_ids, position))
600 Position_Menu.addSeparator()
601 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Entire Clip)"))
602 Fade_In_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_SLOW, clip_ids, position))
603 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Entire Clip)"))
604 Fade_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_SLOW, clip_ids, position))
606 Fade_Menu.addMenu(Position_Menu)
607 menu.addMenu(Fade_Menu)
611 Animate_Menu = QMenu(_(
"Animate"), self)
612 Animate_None = Animate_Menu.addAction(_(
"No Animation"))
613 Animate_None.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_NONE, clip_ids))
614 Animate_Menu.addSeparator()
615 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
616 Position_Menu = QMenu(_(position), self)
619 Scale_Menu = QMenu(_(
"Zoom"), self)
620 Animate_In_50_100 = Scale_Menu.addAction(_(
"Zoom In (50% to 100%)"))
621 Animate_In_50_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_50_100, clip_ids, position))
622 Animate_In_75_100 = Scale_Menu.addAction(_(
"Zoom In (75% to 100%)"))
623 Animate_In_75_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_75_100, clip_ids, position))
624 Animate_In_100_150 = Scale_Menu.addAction(_(
"Zoom In (100% to 150%)"))
625 Animate_In_100_150.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_100_150, clip_ids, position))
626 Animate_Out_100_75 = Scale_Menu.addAction(_(
"Zoom Out (100% to 75%)"))
627 Animate_Out_100_75.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_100_75, clip_ids, position))
628 Animate_Out_100_50 = Scale_Menu.addAction(_(
"Zoom Out (100% to 50%)"))
629 Animate_Out_100_50.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_100_50, clip_ids, position))
630 Animate_Out_150_100 = Scale_Menu.addAction(_(
"Zoom Out (150% to 100%)"))
631 Animate_Out_150_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_150_100, clip_ids, position))
632 Position_Menu.addMenu(Scale_Menu)
635 Center_Edge_Menu = QMenu(_(
"Center to Edge"), self)
636 Animate_Center_Top = Center_Edge_Menu.addAction(_(
"Center to Top"))
637 Animate_Center_Top.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_TOP, clip_ids, position))
638 Animate_Center_Left = Center_Edge_Menu.addAction(_(
"Center to Left"))
639 Animate_Center_Left.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_LEFT, clip_ids, position))
640 Animate_Center_Right = Center_Edge_Menu.addAction(_(
"Center to Right"))
641 Animate_Center_Right.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_RIGHT, clip_ids, position))
642 Animate_Center_Bottom = Center_Edge_Menu.addAction(_(
"Center to Bottom"))
643 Animate_Center_Bottom.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_BOTTOM, clip_ids, position))
644 Position_Menu.addMenu(Center_Edge_Menu)
647 Edge_Center_Menu = QMenu(_(
"Edge to Center"), self)
648 Animate_Top_Center = Edge_Center_Menu.addAction(_(
"Top to Center"))
649 Animate_Top_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_TOP_CENTER, clip_ids, position))
650 Animate_Left_Center = Edge_Center_Menu.addAction(_(
"Left to Center"))
651 Animate_Left_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_LEFT_CENTER, clip_ids, position))
652 Animate_Right_Center = Edge_Center_Menu.addAction(_(
"Right to Center"))
653 Animate_Right_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RIGHT_CENTER, clip_ids, position))
654 Animate_Bottom_Center = Edge_Center_Menu.addAction(_(
"Bottom to Center"))
655 Animate_Bottom_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_BOTTOM_CENTER, clip_ids, position))
656 Position_Menu.addMenu(Edge_Center_Menu)
659 Edge_Edge_Menu = QMenu(_(
"Edge to Edge"), self)
660 Animate_Top_Bottom = Edge_Edge_Menu.addAction(_(
"Top to Bottom"))
661 Animate_Top_Bottom.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_TOP_BOTTOM, clip_ids, position))
662 Animate_Left_Right = Edge_Edge_Menu.addAction(_(
"Left to Right"))
663 Animate_Left_Right.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_LEFT_RIGHT, clip_ids, position))
664 Animate_Right_Left = Edge_Edge_Menu.addAction(_(
"Right to Left"))
665 Animate_Right_Left.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RIGHT_LEFT, clip_ids, position))
666 Animate_Bottom_Top = Edge_Edge_Menu.addAction(_(
"Bottom to Top"))
667 Animate_Bottom_Top.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_BOTTOM_TOP, clip_ids, position))
668 Position_Menu.addMenu(Edge_Edge_Menu)
671 Position_Menu.addSeparator()
672 Random = Position_Menu.addAction(_(
"Random"))
673 Random.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RANDOM, clip_ids, position))
676 Animate_Menu.addMenu(Position_Menu)
679 menu.addMenu(Animate_Menu)
682 Rotation_Menu = QMenu(_(
"Rotate"), self)
683 Rotation_None = Rotation_Menu.addAction(_(
"No Rotation"))
684 Rotation_None.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_NONE, clip_ids))
685 Rotation_Menu.addSeparator()
686 Rotation_90_Right = Rotation_Menu.addAction(_(
"Rotate 90 (Right)"))
687 Rotation_90_Right.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_90_RIGHT, clip_ids))
688 Rotation_90_Left = Rotation_Menu.addAction(_(
"Rotate 90 (Left)"))
689 Rotation_90_Left.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_90_LEFT, clip_ids))
690 Rotation_180_Flip = Rotation_Menu.addAction(_(
"Rotate 180 (Flip)"))
691 Rotation_180_Flip.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_180_FLIP, clip_ids))
692 menu.addMenu(Rotation_Menu)
695 Layout_Menu = QMenu(_(
"Layout"), self)
696 Layout_None = Layout_Menu.addAction(_(
"Reset Layout"))
697 Layout_None.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_NONE, clip_ids))
698 Layout_Menu.addSeparator()
699 Layout_Center = Layout_Menu.addAction(_(
"1/4 Size - Center"))
700 Layout_Center.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_CENTER, clip_ids))
701 Layout_Top_Left = Layout_Menu.addAction(_(
"1/4 Size - Top Left"))
702 Layout_Top_Left.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_TOP_LEFT, clip_ids))
703 Layout_Top_Right = Layout_Menu.addAction(_(
"1/4 Size - Top Right"))
704 Layout_Top_Right.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_TOP_RIGHT, clip_ids))
705 Layout_Bottom_Left = Layout_Menu.addAction(_(
"1/4 Size - Bottom Left"))
706 Layout_Bottom_Left.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_BOTTOM_LEFT, clip_ids))
707 Layout_Bottom_Right = Layout_Menu.addAction(_(
"1/4 Size - Bottom Right"))
708 Layout_Bottom_Right.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_BOTTOM_RIGHT, clip_ids))
709 Layout_Menu.addSeparator()
710 Layout_Bottom_All_With_Aspect = Layout_Menu.addAction(_(
"Show All (Maintain Ratio)"))
711 Layout_Bottom_All_With_Aspect.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_ALL_WITH_ASPECT, clip_ids))
712 Layout_Bottom_All_Without_Aspect = Layout_Menu.addAction(_(
"Show All (Distort)"))
713 Layout_Bottom_All_Without_Aspect.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_ALL_WITHOUT_ASPECT, clip_ids))
714 menu.addMenu(Layout_Menu)
717 Time_Menu = QMenu(_(
"Time"), self)
718 Time_None = Time_Menu.addAction(_(
"Reset Time"))
719 Time_None.triggered.connect(partial(self.
Time_Triggered, MENU_TIME_NONE, clip_ids,
'1X'))
720 Time_Menu.addSeparator()
721 for speed, speed_values
in [(
"Normal", [
'1X']), (
"Fast", [
'2X',
'4X',
'8X',
'16X',
'32X']), (
"Slow", [
'1/2X',
'1/4X',
'1/8X',
'1/16X',
'1/32X'])]:
722 Speed_Menu = QMenu(_(speed), self)
724 for direction, direction_value
in [(
"Forward", MENU_TIME_FORWARD), (
"Backward", MENU_TIME_BACKWARD)]:
725 Direction_Menu = QMenu(_(direction), self)
727 for actual_speed
in speed_values:
729 Time_Option = Direction_Menu.addAction(_(actual_speed))
730 Time_Option.triggered.connect(partial(self.
Time_Triggered, direction_value, clip_ids, actual_speed))
733 Speed_Menu.addMenu(Direction_Menu)
735 Time_Menu.addMenu(Speed_Menu)
738 Time_Menu.addSeparator()
739 for freeze_type, trigger_type
in [(_(
"Freeze"), MENU_TIME_FREEZE), (_(
"Freeze && Zoom"), MENU_TIME_FREEZE_ZOOM)]:
740 Freeze_Menu = QMenu(freeze_type, self)
742 for freeze_seconds
in [2, 4, 6, 8, 10, 20, 30]:
744 Time_Option = Freeze_Menu.addAction(_(
'{} seconds').format(freeze_seconds))
745 Time_Option.triggered.connect(partial(self.
Time_Triggered, trigger_type, clip_ids, freeze_seconds, playhead_position))
748 Time_Menu.addMenu(Freeze_Menu)
751 menu.addMenu(Time_Menu)
754 Volume_Menu = QMenu(_(
"Volume"), self)
755 Volume_None = Volume_Menu.addAction(_(
"Reset Volume"))
756 Volume_None.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_NONE, clip_ids))
757 Volume_Menu.addSeparator()
758 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
759 Position_Menu = QMenu(_(position), self)
761 if position ==
"Start of Clip":
762 Fade_In_Fast = Position_Menu.addAction(_(
"Fade In (Fast)"))
763 Fade_In_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_FAST, clip_ids, position))
764 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Slow)"))
765 Fade_In_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_SLOW, clip_ids, position))
767 elif position ==
"End of Clip":
768 Fade_Out_Fast = Position_Menu.addAction(_(
"Fade Out (Fast)"))
769 Fade_Out_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_FAST, clip_ids, position))
770 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Slow)"))
771 Fade_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_SLOW, clip_ids, position))
774 Fade_In_Out_Fast = Position_Menu.addAction(_(
"Fade In and Out (Fast)"))
775 Fade_In_Out_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_OUT_FAST, clip_ids, position))
776 Fade_In_Out_Slow = Position_Menu.addAction(_(
"Fade In and Out (Slow)"))
777 Fade_In_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_OUT_SLOW, clip_ids, position))
778 Position_Menu.addSeparator()
779 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Entire Clip)"))
780 Fade_In_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_SLOW, clip_ids, position))
781 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Entire Clip)"))
782 Fade_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_SLOW, clip_ids, position))
785 Position_Menu.addSeparator()
786 Volume_100 = Position_Menu.addAction(_(
"Level 100%"))
787 Volume_100.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_100, clip_ids, position))
788 Volume_90 = Position_Menu.addAction(_(
"Level 90%"))
789 Volume_90.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_90, clip_ids, position))
790 Volume_80 = Position_Menu.addAction(_(
"Level 80%"))
791 Volume_80.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_80, clip_ids, position))
792 Volume_70 = Position_Menu.addAction(_(
"Level 70%"))
793 Volume_70.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_70, clip_ids, position))
794 Volume_60 = Position_Menu.addAction(_(
"Level 60%"))
795 Volume_60.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_60, clip_ids, position))
796 Volume_50 = Position_Menu.addAction(_(
"Level 50%"))
797 Volume_50.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_50, clip_ids, position))
798 Volume_40 = Position_Menu.addAction(_(
"Level 40%"))
799 Volume_40.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_40, clip_ids, position))
800 Volume_30 = Position_Menu.addAction(_(
"Level 30%"))
801 Volume_30.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_30, clip_ids, position))
802 Volume_20 = Position_Menu.addAction(_(
"Level 20%"))
803 Volume_20.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_20, clip_ids, position))
804 Volume_10 = Position_Menu.addAction(_(
"Level 10%"))
805 Volume_10.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_10, clip_ids, position))
806 Volume_0 = Position_Menu.addAction(_(
"Level 0%"))
807 Volume_0.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_0, clip_ids, position))
809 Volume_Menu.addMenu(Position_Menu)
810 menu.addMenu(Volume_Menu)
813 Split_Audio_Channels_Menu = QMenu(_(
"Separate Audio"), self)
814 Split_Single_Clip = Split_Audio_Channels_Menu.addAction(_(
"Single Clip (all channels)"))
815 Split_Single_Clip.triggered.connect(partial(self.
Split_Audio_Triggered, MENU_SPLIT_AUDIO_SINGLE, clip_ids))
816 Split_Multiple_Clips = Split_Audio_Channels_Menu.addAction(_(
"Multiple Clips (each channel)"))
817 Split_Multiple_Clips.triggered.connect(partial(self.
Split_Audio_Triggered, MENU_SPLIT_AUDIO_MULTIPLE, clip_ids))
818 menu.addMenu(Split_Audio_Channels_Menu)
822 start_of_clip = float(clip.data[
"start"])
823 end_of_clip = float(clip.data[
"end"])
824 position_of_clip = float(clip.data[
"position"])
825 if playhead_position >= position_of_clip
and playhead_position <= (position_of_clip + (end_of_clip - start_of_clip)):
827 Slice_Menu = QMenu(_(
"Slice"), self)
828 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
829 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, [clip_id], [], playhead_position))
830 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
831 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, [clip_id], [], playhead_position))
832 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
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()
935 self.redraw_audio_timer.start()
940 log.info(
"Split_Audio_Triggered")
946 for clip_id
in clip_ids:
949 clip = Clip.get(id=clip_id)
963 p = openshot.Point(1, -1.0, openshot.CONSTANT)
964 p_object = json.loads(p.Json())
965 clip.data[
"has_audio"] = {
"Points" : [p_object]}
974 clip_title = clip.data[
"title"]
976 if action == MENU_SPLIT_AUDIO_SINGLE:
978 p = openshot.Point(1, -1.0, openshot.CONSTANT)
979 p_object = json.loads(p.Json())
980 clip.data[
"channel_filter"] = {
"Points" : [p_object]}
983 p = openshot.Point(1, 0.0, openshot.CONSTANT)
984 p_object = json.loads(p.Json())
985 clip.data[
"has_video"] = {
"Points" : [p_object]}
988 clip.data[
'layer'] = clip.data[
'layer'] - 1
991 channel_label = _(
"(all channels)")
992 clip.data[
"title"] = clip_title +
" " + channel_label
996 if action == MENU_SPLIT_AUDIO_MULTIPLE:
998 channels = int(clip.data[
"reader"][
"channels"])
1001 for channel
in range(0, channels):
1002 log.info(
"Adding clip for channel %s" % channel)
1005 p = openshot.Point(1, channel, openshot.CONSTANT)
1006 p_object = json.loads(p.Json())
1007 clip.data[
"channel_filter"] = {
"Points" : [p_object]}
1010 p = openshot.Point(1, 0.0, openshot.CONSTANT)
1011 p_object = json.loads(p.Json())
1012 clip.data[
"has_video"] = {
"Points" : [p_object]}
1015 clip.data[
'layer'] = max(clip.data[
'layer'] - 1, 0)
1018 channel_label = _(
"(channel %s)") % (channel + 1)
1019 clip.data[
"title"] = clip_title +
" " + channel_label
1026 clip.type =
'insert'
1029 for clip_id
in clip_ids:
1032 clip = Clip.get(id=clip_id)
1038 p = openshot.Point(1, 0.0, openshot.CONSTANT)
1039 p_object = json.loads(p.Json())
1040 clip.data[
"has_audio"] = {
"Points" : [p_object]}
1044 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1053 for clip_id
in clip_ids:
1056 clip = Clip.get(id=clip_id)
1061 new_gravity = openshot.GRAVITY_CENTER
1062 if action == MENU_LAYOUT_CENTER:
1063 new_gravity = openshot.GRAVITY_CENTER
1064 if action == MENU_LAYOUT_TOP_LEFT:
1065 new_gravity = openshot.GRAVITY_TOP_LEFT
1066 elif action == MENU_LAYOUT_TOP_RIGHT:
1067 new_gravity = openshot.GRAVITY_TOP_RIGHT
1068 elif action == MENU_LAYOUT_BOTTOM_LEFT:
1069 new_gravity = openshot.GRAVITY_BOTTOM_LEFT
1070 elif action == MENU_LAYOUT_BOTTOM_RIGHT:
1071 new_gravity = openshot.GRAVITY_BOTTOM_RIGHT
1073 if action == MENU_LAYOUT_NONE:
1075 clip.data[
"scale"] = openshot.SCALE_FIT
1076 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1079 p = openshot.Point(1, 1.0, openshot.BEZIER)
1080 p_object = json.loads(p.Json())
1081 clip.data[
"scale_x"] = {
"Points" : [p_object]}
1082 clip.data[
"scale_y"] = {
"Points" : [p_object]}
1085 p = openshot.Point(1, 0.0, openshot.BEZIER)
1086 p_object = json.loads(p.Json())
1087 clip.data[
"location_x"] = {
"Points" : [p_object]}
1088 clip.data[
"location_y"] = {
"Points" : [p_object]}
1090 if action == MENU_LAYOUT_CENTER
or \
1091 action == MENU_LAYOUT_TOP_LEFT
or \
1092 action == MENU_LAYOUT_TOP_RIGHT
or \
1093 action == MENU_LAYOUT_BOTTOM_LEFT
or \
1094 action == MENU_LAYOUT_BOTTOM_RIGHT:
1096 clip.data[
"scale"] = openshot.SCALE_FIT
1097 clip.data[
"gravity"] = new_gravity
1100 p = openshot.Point(1, 0.5, openshot.BEZIER)
1101 p_object = json.loads(p.Json())
1102 clip.data[
"scale_x"] = {
"Points" : [p_object]}
1103 clip.data[
"scale_y"] = {
"Points" : [p_object]}
1106 p = openshot.Point(1, 0.0, openshot.BEZIER)
1107 p_object = json.loads(p.Json())
1108 clip.data[
"location_x"] = {
"Points" : [p_object]}
1109 clip.data[
"location_y"] = {
"Points" : [p_object]}
1112 if action == MENU_LAYOUT_ALL_WITH_ASPECT:
1116 elif action == MENU_LAYOUT_ALL_WITHOUT_ASPECT:
1122 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1130 for clip_id
in clip_ids:
1133 clip = Clip.get(id=clip_id)
1139 fps =
get_app().project.get([
"fps"])
1140 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1143 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1144 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1148 start_animation = start_of_clip
1149 end_animation = end_of_clip
1150 if position ==
"Start of Clip":
1151 start_animation = start_of_clip
1152 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1153 elif position ==
"End of Clip":
1154 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1155 end_animation = end_of_clip
1157 if action == MENU_ANIMATE_NONE:
1159 default_zoom = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1160 default_zoom_object = json.loads(default_zoom.Json())
1161 default_loc = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1162 default_loc_object = json.loads(default_loc.Json())
1163 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1164 clip.data[
"scale_x"] = {
"Points" : [default_zoom_object]}
1165 clip.data[
"scale_y"] = {
"Points" : [default_zoom_object]}
1166 clip.data[
"location_x"] = {
"Points" : [default_loc_object]}
1167 clip.data[
"location_y"] = {
"Points" : [default_loc_object]}
1169 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]:
1173 if action == MENU_ANIMATE_IN_50_100:
1175 elif action == MENU_ANIMATE_IN_75_100:
1177 elif action == MENU_ANIMATE_IN_100_150:
1179 elif action == MENU_ANIMATE_OUT_100_75:
1181 elif action == MENU_ANIMATE_OUT_100_50:
1183 elif action == MENU_ANIMATE_OUT_150_100:
1187 start = openshot.Point(start_animation, start_scale, openshot.BEZIER)
1188 start_object = json.loads(start.Json())
1189 end = openshot.Point(end_animation, end_scale, openshot.BEZIER)
1190 end_object = json.loads(end.Json())
1191 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1192 clip.data[
"scale_x"][
"Points"].append(start_object)
1193 clip.data[
"scale_x"][
"Points"].append(end_object)
1194 clip.data[
"scale_y"][
"Points"].append(start_object)
1195 clip.data[
"scale_y"][
"Points"].append(end_object)
1198 if action
in [MENU_ANIMATE_CENTER_TOP, MENU_ANIMATE_CENTER_LEFT, MENU_ANIMATE_CENTER_RIGHT, MENU_ANIMATE_CENTER_BOTTOM,
1199 MENU_ANIMATE_TOP_CENTER, MENU_ANIMATE_LEFT_CENTER, MENU_ANIMATE_RIGHT_CENTER, MENU_ANIMATE_BOTTOM_CENTER,
1200 MENU_ANIMATE_TOP_BOTTOM, MENU_ANIMATE_LEFT_RIGHT, MENU_ANIMATE_RIGHT_LEFT, MENU_ANIMATE_BOTTOM_TOP]:
1202 animate_start_x = 0.0
1204 animate_start_y = 0.0
1207 if action == MENU_ANIMATE_CENTER_TOP:
1208 animate_end_y = -1.0
1209 elif action == MENU_ANIMATE_CENTER_LEFT:
1210 animate_end_x = -1.0
1211 elif action == MENU_ANIMATE_CENTER_RIGHT:
1213 elif action == MENU_ANIMATE_CENTER_BOTTOM:
1217 elif action == MENU_ANIMATE_TOP_CENTER:
1218 animate_start_y = -1.0
1219 elif action == MENU_ANIMATE_LEFT_CENTER:
1220 animate_start_x = -1.0
1221 elif action == MENU_ANIMATE_RIGHT_CENTER:
1222 animate_start_x = 1.0
1223 elif action == MENU_ANIMATE_BOTTOM_CENTER:
1224 animate_start_y = 1.0
1227 elif action == MENU_ANIMATE_TOP_BOTTOM:
1228 animate_start_y = -1.0
1230 elif action == MENU_ANIMATE_LEFT_RIGHT:
1231 animate_start_x = -1.0
1233 elif action == MENU_ANIMATE_RIGHT_LEFT:
1234 animate_start_x = 1.0
1235 animate_end_x = -1.0
1236 elif action == MENU_ANIMATE_BOTTOM_TOP:
1237 animate_start_y = 1.0
1238 animate_end_y = -1.0
1241 start_x = openshot.Point(start_animation, animate_start_x, openshot.BEZIER)
1242 start_x_object = json.loads(start_x.Json())
1243 end_x = openshot.Point(end_animation, animate_end_x, openshot.BEZIER)
1244 end_x_object = json.loads(end_x.Json())
1245 start_y = openshot.Point(start_animation, animate_start_y, openshot.BEZIER)
1246 start_y_object = json.loads(start_y.Json())
1247 end_y = openshot.Point(end_animation, animate_end_y, openshot.BEZIER)
1248 end_y_object = json.loads(end_y.Json())
1249 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1250 clip.data[
"location_x"][
"Points"].append(start_x_object)
1251 clip.data[
"location_x"][
"Points"].append(end_x_object)
1252 clip.data[
"location_y"][
"Points"].append(start_y_object)
1253 clip.data[
"location_y"][
"Points"].append(end_y_object)
1255 if action == MENU_ANIMATE_RANDOM:
1257 animate_start_x = uniform(-0.5, 0.5)
1258 animate_end_x = uniform(-0.15, 0.15)
1259 animate_start_y = uniform(-0.5, 0.5)
1260 animate_end_y = uniform(-0.15, 0.15)
1263 start_scale = uniform(0.5, 1.5)
1264 end_scale = uniform(0.85, 1.15)
1267 start = openshot.Point(start_animation, start_scale, openshot.BEZIER)
1268 start_object = json.loads(start.Json())
1269 end = openshot.Point(end_animation, end_scale, openshot.BEZIER)
1270 end_object = json.loads(end.Json())
1271 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1272 clip.data[
"scale_x"][
"Points"].append(start_object)
1273 clip.data[
"scale_x"][
"Points"].append(end_object)
1274 clip.data[
"scale_y"][
"Points"].append(start_object)
1275 clip.data[
"scale_y"][
"Points"].append(end_object)
1278 start_x = openshot.Point(start_animation, animate_start_x, openshot.BEZIER)
1279 start_x_object = json.loads(start_x.Json())
1280 end_x = openshot.Point(end_animation, animate_end_x, openshot.BEZIER)
1281 end_x_object = json.loads(end_x.Json())
1282 start_y = openshot.Point(start_animation, animate_start_y, openshot.BEZIER)
1283 start_y_object = json.loads(start_y.Json())
1284 end_y = openshot.Point(end_animation, animate_end_y, openshot.BEZIER)
1285 end_y_object = json.loads(end_y.Json())
1286 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1287 clip.data[
"location_x"][
"Points"].append(start_x_object)
1288 clip.data[
"location_x"][
"Points"].append(end_x_object)
1289 clip.data[
"location_y"][
"Points"].append(start_y_object)
1290 clip.data[
"location_y"][
"Points"].append(end_y_object)
1293 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1305 for clip_id
in clip_ids:
1308 clip = Clip.get(id=clip_id)
1315 if action == MENU_COPY_CLIP
or action == MENU_COPY_ALL:
1317 elif action == MENU_COPY_KEYFRAMES_ALL:
1323 self.
copy_clipboard[clip_id][
'location_x'] = clip.data[
'location_x']
1324 self.
copy_clipboard[clip_id][
'location_y'] = clip.data[
'location_y']
1327 elif action == MENU_COPY_KEYFRAMES_ALPHA:
1329 elif action == MENU_COPY_KEYFRAMES_SCALE:
1333 elif action == MENU_COPY_KEYFRAMES_ROTATE:
1336 elif action == MENU_COPY_KEYFRAMES_LOCATION:
1338 self.
copy_clipboard[clip_id][
'location_x'] = clip.data[
'location_x']
1339 self.
copy_clipboard[clip_id][
'location_y'] = clip.data[
'location_y']
1340 elif action == MENU_COPY_KEYFRAMES_TIME:
1342 elif action == MENU_COPY_KEYFRAMES_VOLUME:
1344 elif action == MENU_COPY_EFFECTS:
1348 for tran_id
in tran_ids:
1351 tran = Transition.get(id=tran_id)
1358 if action == MENU_COPY_TRANSITION
or action == MENU_COPY_ALL:
1360 elif action == MENU_COPY_KEYFRAMES_ALL:
1363 elif action == MENU_COPY_KEYFRAMES_BRIGHTNESS:
1365 elif action == MENU_COPY_KEYFRAMES_CONTRAST:
1375 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
1376 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
1379 if len(clipboard_clip_ids) + len(clipboard_tran_ids):
1380 left_most_position = -1.0
1383 for clip_id
in clipboard_clip_ids:
1386 clip.data = self.copy_clipboard.get(clip_id, {})
1387 if clip.data[
'position'] < left_most_position
or left_most_position == -1.0:
1388 left_most_position = clip.data[
'position']
1389 if clip.data[
'layer'] > top_most_layer
or top_most_layer == -1.0:
1390 top_most_layer = clip.data[
'layer']
1392 for tran_id
in clipboard_tran_ids:
1395 tran.data = self.copy_transition_clipboard.get(tran_id, {})
1396 if tran.data[
'position'] < left_most_position
or left_most_position == -1.0:
1397 left_most_position = tran.data[
'position']
1398 if tran.data[
'layer'] > top_most_layer
or top_most_layer == -1.0:
1399 top_most_layer = tran.data[
'layer']
1403 layer_id = top_most_layer
1406 position_diff = position - left_most_position
1407 layer_diff = layer_id - top_most_layer
1410 for clip_id
in clipboard_clip_ids:
1413 clip.data = self.copy_clipboard.get(clip_id, {})
1416 clip.type =
'insert'
1420 clip.data[
'position'] += position_diff
1421 clip.data[
'layer'] += layer_diff
1427 for tran_id
in clipboard_tran_ids:
1430 tran.data = self.copy_transition_clipboard.get(tran_id, {})
1433 tran.type =
'insert'
1437 tran.data[
'position'] += position_diff
1438 tran.data[
'layer'] += layer_diff
1445 for clip_id
in clip_ids:
1448 clip = Clip.get(id=clip_id)
1464 for tran_id
in tran_ids:
1467 tran = Transition.get(id=tran_id)
1484 log.info(
"Nudging clip(s) and/or transition(s)")
1489 fps =
get_app().project.get([
"fps"])
1490 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1491 nudgeDistance = float(action) / float(fps_float)
1492 nudgeDistance /= 2.0
1493 if abs(nudgeDistance) < 0.01:
1494 nudgeDistance = 0.01 * action
1495 log.info(
"Nudging by %s sec" % nudgeDistance)
1498 for clip_id
in clip_ids:
1500 clip = Clip.get(id=clip_id)
1505 position = float(clip.data[
"position"])
1506 start_of_clip = float(clip.data[
"start"])
1507 end_of_clip = float(clip.data[
"end"])
1509 if position < left_edge
or left_edge == -1.0:
1510 left_edge = position
1511 if position + (end_of_clip - start_of_clip) > right_edge
or right_edge == -1.0:
1512 right_edge = position + (end_of_clip - start_of_clip)
1515 if left_edge + nudgeDistance < 0.0:
1516 log.info(
"Cannot nudge beyond start of timeline")
1520 for tran_id
in tran_ids:
1522 tran = Transition.get(id=tran_id)
1527 position = float(tran.data[
"position"])
1528 start_of_tran = float(tran.data[
"start"])
1529 end_of_tran = float(tran.data[
"end"])
1531 if position < left_edge
or left_edge == -1.0:
1532 left_edge = position
1533 if position + (end_of_tran - start_of_tran) > right_edge
or right_edge == -1.0:
1534 right_edge = position + (end_of_tran - start_of_tran)
1537 if left_edge + nudgeDistance < 0.0:
1538 log.info(
"Cannot nudge beyond start of timeline")
1542 for clip_id
in clip_ids:
1544 clip = Clip.get(id=clip_id)
1550 clip.data[
'position'] += nudgeDistance
1553 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1556 for tran_id
in tran_ids:
1558 tran = Transition.get(id=tran_id)
1564 tran.data[
'position'] += nudgeDistance
1574 prop_name =
"position"
1579 for clip_id
in clip_ids:
1581 clip = Clip.get(id=clip_id)
1586 position = float(clip.data[
"position"])
1587 start_of_clip = float(clip.data[
"start"])
1588 end_of_clip = float(clip.data[
"end"])
1590 if position < left_edge
or left_edge == -1.0:
1591 left_edge = position
1592 if position + (end_of_clip - start_of_clip) > right_edge
or right_edge == -1.0:
1593 right_edge = position + (end_of_clip - start_of_clip)
1596 for tran_id
in tran_ids:
1598 tran = Transition.get(id=tran_id)
1603 position = float(tran.data[
"position"])
1604 start_of_tran = float(tran.data[
"start"])
1605 end_of_tran = float(tran.data[
"end"])
1607 if position < left_edge
or left_edge == -1.0:
1608 left_edge = position
1609 if position + (end_of_tran - start_of_tran) > right_edge
or right_edge == -1.0:
1610 right_edge = position + (end_of_tran - start_of_tran)
1614 for clip_id
in clip_ids:
1616 clip = Clip.get(id=clip_id)
1621 if action == MENU_ALIGN_LEFT:
1622 clip.data[
'position'] = left_edge
1623 elif action == MENU_ALIGN_RIGHT:
1624 position = float(clip.data[
"position"])
1625 start_of_clip = float(clip.data[
"start"])
1626 end_of_clip = float(clip.data[
"end"])
1627 right_clip_edge = position + (end_of_clip - start_of_clip)
1629 clip.data[
'position'] = position + (right_edge - right_clip_edge)
1632 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1635 for tran_id
in tran_ids:
1637 tran = Transition.get(id=tran_id)
1642 if action == MENU_ALIGN_LEFT:
1643 tran.data[
'position'] = left_edge
1644 elif action == MENU_ALIGN_RIGHT:
1645 position = float(tran.data[
"position"])
1646 start_of_tran = float(tran.data[
"start"])
1647 end_of_tran = float(tran.data[
"end"])
1648 right_tran_edge = position + (end_of_tran - start_of_tran)
1650 tran.data[
'position'] = position + (right_edge - right_tran_edge)
1662 fps =
get_app().project.get([
"fps"])
1663 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1666 for clip_id
in clip_ids:
1669 clip = Clip.get(id=clip_id)
1674 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1675 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1679 start_animation = start_of_clip
1680 end_animation = end_of_clip
1681 if position ==
"Start of Clip" and action
in [MENU_FADE_IN_FAST, MENU_FADE_OUT_FAST]:
1682 start_animation = start_of_clip
1683 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1684 elif position ==
"Start of Clip" and action
in [MENU_FADE_IN_SLOW, MENU_FADE_OUT_SLOW]:
1685 start_animation = start_of_clip
1686 end_animation = min(start_of_clip + (3.0 * fps_float), end_of_clip)
1687 elif position ==
"End of Clip" and action
in [MENU_FADE_IN_FAST, MENU_FADE_OUT_FAST]:
1688 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1689 end_animation = end_of_clip
1690 elif position ==
"End of Clip" and action
in [MENU_FADE_IN_SLOW, MENU_FADE_OUT_SLOW]:
1691 start_animation = max(1.0, end_of_clip - (3.0 * fps_float))
1692 end_animation = end_of_clip
1695 if position ==
"Entire Clip" and action == MENU_FADE_IN_OUT_FAST:
1697 self.
Fade_Triggered(MENU_FADE_IN_FAST, clip_ids,
"Start of Clip")
1700 elif position ==
"Entire Clip" and action == MENU_FADE_IN_OUT_SLOW:
1702 self.
Fade_Triggered(MENU_FADE_IN_SLOW, clip_ids,
"Start of Clip")
1706 if action == MENU_FADE_NONE:
1708 p = openshot.Point(1, 1.0, openshot.BEZIER)
1709 p_object = json.loads(p.Json())
1710 clip.data[prop_name] = {
"Points" : [p_object]}
1712 if action
in [MENU_FADE_IN_FAST, MENU_FADE_IN_SLOW]:
1714 start = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1715 start_object = json.loads(start.Json())
1716 end = openshot.Point(end_animation, 1.0, openshot.BEZIER)
1717 end_object = json.loads(end.Json())
1718 clip.data[prop_name][
"Points"].append(start_object)
1719 clip.data[prop_name][
"Points"].append(end_object)
1721 if action
in [MENU_FADE_OUT_FAST, MENU_FADE_OUT_SLOW]:
1723 start = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1724 start_object = json.loads(start.Json())
1725 end = openshot.Point(end_animation, 0.0, openshot.BEZIER)
1726 end_object = json.loads(end.Json())
1727 clip.data[prop_name][
"Points"].append(start_object)
1728 clip.data[prop_name][
"Points"].append(end_object)
1731 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1733 @pyqtSlot(str, str, float)
1739 slice_mode = MENU_SLICE_KEEP_BOTH
1740 if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
1741 slice_mode = MENU_SLICE_KEEP_RIGHT
1742 elif int(QCoreApplication.instance().keyboardModifiers() & Qt.ShiftModifier) > 0:
1743 slice_mode = MENU_SLICE_KEEP_LEFT
1747 QTimer.singleShot(0, partial(self.
Slice_Triggered, slice_mode, [clip_id], [], cursor_position))
1750 QTimer.singleShot(0, partial(self.
Slice_Triggered, slice_mode, [], [trans_id], cursor_position))
1756 fps =
get_app().project.get([
"fps"])
1757 fps_num = float(fps[
"num"])
1758 fps_den = float(fps[
"den"])
1759 fps_float = fps_num / fps_den
1760 frame_duration = fps_den / fps_num
1764 playhead_position = float(round((playhead_position * fps_num) / fps_den ) * fps_den ) / fps_num
1767 for clip_id
in clip_ids:
1770 clip = Clip.get(id=clip_id)
1776 has_audio_data = bool(self.
eval_js(JS_SCOPE_SELECTOR +
".hasAudioData('" + clip_id +
"');"))
1778 if action == MENU_SLICE_KEEP_LEFT
or action == MENU_SLICE_KEEP_BOTH:
1780 position_of_clip = float(clip.data[
"position"])
1781 start_of_clip = float(clip.data[
"start"])
1784 clip.data[
"end"] = start_of_clip + (playhead_position - position_of_clip)
1786 elif action == MENU_SLICE_KEEP_RIGHT:
1788 position_of_clip = float(clip.data[
"position"])
1789 start_of_clip = float(clip.data[
"start"])
1792 clip.data[
"position"] = playhead_position
1793 clip.data[
"start"] = start_of_clip + (playhead_position - position_of_clip)
1798 if action == MENU_SLICE_KEEP_BOTH:
1801 right_clip = Clip.get(id=clip_id)
1807 right_clip.id =
None
1808 right_clip.type =
'insert'
1809 right_clip.data.pop(
'id')
1810 right_clip.key.pop(1)
1813 position_of_clip = float(right_clip.data[
"position"])
1814 start_of_clip = float(right_clip.data[
"start"])
1817 right_clip.data[
"position"] = (round(float(playhead_position) * fps_float) + 1) / fps_float
1818 right_clip.data[
"start"] = (round(float(clip.data[
"end"]) * fps_float) + 2) / fps_float
1827 self.
update_clip_data(right_clip.data, only_basic_props=
False, ignore_reader=
True)
1831 log.info(
"Generate right splice waveform for clip id: %s" % right_clip.id)
1835 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1839 log.info(
"Generate left splice waveform for clip id: %s" % clip.id)
1844 for trans_id
in trans_ids:
1846 trans = Transition.get(id=trans_id)
1851 if action == MENU_SLICE_KEEP_LEFT
or action == MENU_SLICE_KEEP_BOTH:
1853 position_of_tran = float(trans.data[
"position"])
1856 trans.data[
"end"] = playhead_position - position_of_tran
1858 elif action == MENU_SLICE_KEEP_RIGHT:
1860 position_of_tran = float(trans.data[
"position"])
1861 end_of_tran = float(trans.data[
"end"])
1864 trans.data[
"position"] = playhead_position
1865 trans.data[
"end"] = end_of_tran - (playhead_position - position_of_tran)
1867 if action == MENU_SLICE_KEEP_BOTH:
1870 right_tran = Transition.get(id=trans_id)
1876 right_tran.id =
None
1877 right_tran.type =
'insert'
1878 right_tran.data.pop(
'id')
1879 right_tran.key.pop(1)
1882 position_of_tran = float(right_tran.data[
"position"])
1883 end_of_tran = float(right_tran.data[
"end"])
1886 right_tran.data[
"position"] = playhead_position + frame_duration
1887 right_tran.data[
"end"] = end_of_tran - (playhead_position - position_of_tran) + frame_duration
1902 prop_name =
"volume"
1905 fps =
get_app().project.get([
"fps"])
1906 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1909 for clip_id
in clip_ids:
1912 clip = Clip.get(id=clip_id)
1917 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1918 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1922 start_animation = start_of_clip
1923 end_animation = end_of_clip
1924 if position ==
"Start of Clip" and action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_OUT_FAST]:
1925 start_animation = start_of_clip
1926 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1927 elif position ==
"Start of Clip" and action
in [MENU_VOLUME_FADE_IN_SLOW, MENU_VOLUME_FADE_OUT_SLOW]:
1928 start_animation = start_of_clip
1929 end_animation = min(start_of_clip + (3.0 * fps_float), end_of_clip)
1930 elif position ==
"End of Clip" and action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_OUT_FAST]:
1931 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1932 end_animation = end_of_clip
1933 elif position ==
"End of Clip" and action
in [MENU_VOLUME_FADE_IN_SLOW, MENU_VOLUME_FADE_OUT_SLOW]:
1934 start_animation = max(1.0, end_of_clip - (3.0 * fps_float))
1935 end_animation = end_of_clip
1936 elif position ==
"Start of Clip":
1938 start_animation = start_of_clip
1939 end_animation = start_of_clip
1940 elif position ==
"End of Clip":
1942 start_animation = end_of_clip
1943 end_animation = end_of_clip
1946 if position ==
"Entire Clip" and action == MENU_VOLUME_FADE_IN_OUT_FAST:
1951 elif position ==
"Entire Clip" and action == MENU_VOLUME_FADE_IN_OUT_SLOW:
1957 if action == MENU_VOLUME_NONE:
1959 p = openshot.Point(1, 1.0, openshot.BEZIER)
1960 p_object = json.loads(p.Json())
1961 clip.data[prop_name] = {
"Points" : [p_object]}
1963 if action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_IN_SLOW]:
1965 start = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1966 start_object = json.loads(start.Json())
1967 end = openshot.Point(end_animation, 1.0, openshot.BEZIER)
1968 end_object = json.loads(end.Json())
1969 clip.data[prop_name][
"Points"].append(start_object)
1970 clip.data[prop_name][
"Points"].append(end_object)
1972 if action
in [MENU_VOLUME_FADE_OUT_FAST, MENU_VOLUME_FADE_OUT_SLOW]:
1974 start = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1975 start_object = json.loads(start.Json())
1976 end = openshot.Point(end_animation, 0.0, openshot.BEZIER)
1977 end_object = json.loads(end.Json())
1978 clip.data[prop_name][
"Points"].append(start_object)
1979 clip.data[prop_name][
"Points"].append(end_object)
1981 if action
in [MENU_VOLUME_LEVEL_100, MENU_VOLUME_LEVEL_90, MENU_VOLUME_LEVEL_80, MENU_VOLUME_LEVEL_70,
1982 MENU_VOLUME_LEVEL_60, MENU_VOLUME_LEVEL_50, MENU_VOLUME_LEVEL_40, MENU_VOLUME_LEVEL_30,
1983 MENU_VOLUME_LEVEL_20, MENU_VOLUME_LEVEL_10, MENU_VOLUME_LEVEL_0]:
1985 p = openshot.Point(start_animation, float(action) / 100.0, openshot.BEZIER)
1986 p_object = json.loads(p.Json())
1987 clip.data[prop_name][
"Points"].append(p_object)
1990 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1993 has_audio_data = bool(self.
eval_js(JS_SCOPE_SELECTOR +
".hasAudioData('" + clip.id +
"');"))
2002 prop_name =
"rotation"
2005 fps =
get_app().project.get([
"fps"])
2006 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2009 for clip_id
in clip_ids:
2012 clip = Clip.get(id=clip_id)
2017 if action == MENU_ROTATE_NONE:
2019 p = openshot.Point(1, 0.0, openshot.BEZIER)
2020 p_object = json.loads(p.Json())
2021 clip.data[prop_name] = {
"Points" : [p_object]}
2023 if action == MENU_ROTATE_90_RIGHT:
2025 p = openshot.Point(1, 90.0, openshot.BEZIER)
2026 p_object = json.loads(p.Json())
2027 clip.data[prop_name] = {
"Points" : [p_object]}
2029 if action == MENU_ROTATE_90_LEFT:
2031 p = openshot.Point(1, -90.0, openshot.BEZIER)
2032 p_object = json.loads(p.Json())
2033 clip.data[prop_name] = {
"Points" : [p_object]}
2035 if action == MENU_ROTATE_180_FLIP:
2037 p = openshot.Point(1, 180.0, openshot.BEZIER)
2038 p_object = json.loads(p.Json())
2039 clip.data[prop_name] = {
"Points" : [p_object]}
2042 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2051 fps =
get_app().project.get([
"fps"])
2052 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2055 for clip_id
in clip_ids:
2058 clip = Clip.get(id=clip_id)
2064 if "original_data" not in clip.data.keys():
2065 clip.data[
"original_data"] = {
"end": clip.data[
"end"],
2066 "duration": clip.data[
"duration"],
2067 "video_length": clip.data[
"reader"][
"video_length"]}
2073 if action
in [MENU_TIME_FREEZE, MENU_TIME_FREEZE_ZOOM]:
2075 freeze_seconds = float(speed)
2077 original_duration = clip.data[
"duration"]
2078 if "original_data" in clip.data.keys():
2079 original_duration = clip.data[
"original_data"][
"duration"]
2081 print(
'ORIGINAL DURATION: %s' % original_duration)
2085 clip.data[
"end"] = float(clip.data[
"end"]) + freeze_seconds
2086 clip.data[
"duration"] = float(clip.data[
"duration"]) + freeze_seconds
2087 clip.data[
"reader"][
"video_length"] = float(clip.data[
"reader"][
"video_length"]) + freeze_seconds
2090 freeze_length_frames = round(freeze_seconds * fps_float) + 1
2091 start_animation_seconds = float(clip.data[
"start"]) + (playhead_position - float(clip.data[
"position"]))
2092 start_animation_frames = round(start_animation_seconds * fps_float) + 1
2093 start_animation_frames_value = start_animation_frames
2094 end_animation_seconds = start_animation_seconds + freeze_seconds
2095 end_animation_frames = round(end_animation_seconds * fps_float) + 1
2096 end_of_clip_seconds = float(clip.data[
"duration"])
2097 end_of_clip_frames = round((end_of_clip_seconds) * fps_float) + 1
2098 end_of_clip_frames_value = round((original_duration) * fps_float) + 1
2101 start_volume_value = 1.0
2104 if len(clip.data[
"time"][
"Points"]) > 1:
2107 del clip.data[
"time"][
"Points"][-1]
2111 clips =
get_app().window.timeline_sync.timeline.Clips()
2112 for clip_object
in clips:
2113 if clip_object.Id() == clip_id:
2118 start_animation_frames_value = c.time.GetLong(start_animation_frames)
2121 if len(clip.data[
"volume"][
"Points"]) > 1:
2124 clips =
get_app().window.timeline_sync.timeline.Clips()
2125 for clip_object
in clips:
2126 if clip_object.Id() == clip_id:
2131 start_volume_value = c.volume.GetValue(start_animation_frames)
2134 p = openshot.Point(start_animation_frames, start_animation_frames_value, openshot.LINEAR)
2135 p_object = json.loads(p.Json())
2136 clip.data[prop_name][
"Points"].append(p_object)
2137 p1 = openshot.Point(end_animation_frames, start_animation_frames_value, openshot.LINEAR)
2138 p1_object = json.loads(p1.Json())
2139 clip.data[prop_name][
"Points"].append(p1_object)
2140 p2 = openshot.Point(end_of_clip_frames, end_of_clip_frames_value, openshot.LINEAR)
2141 p2_object = json.loads(p2.Json())
2142 clip.data[prop_name][
"Points"].append(p2_object)
2145 p = openshot.Point(start_animation_frames - 1, start_volume_value, openshot.LINEAR)
2146 p_object = json.loads(p.Json())
2147 clip.data[
'volume'][
"Points"].append(p_object)
2148 p = openshot.Point(start_animation_frames, 0.0, openshot.LINEAR)
2149 p_object = json.loads(p.Json())
2150 clip.data[
'volume'][
"Points"].append(p_object)
2151 p2 = openshot.Point(end_animation_frames - 1, 0.0, openshot.LINEAR)
2152 p2_object = json.loads(p2.Json())
2153 clip.data[
'volume'][
"Points"].append(p2_object)
2154 p3 = openshot.Point(end_animation_frames, start_volume_value, openshot.LINEAR)
2155 p3_object = json.loads(p3.Json())
2156 clip.data[
'volume'][
"Points"].append(p3_object)
2159 if action == MENU_TIME_FREEZE_ZOOM:
2160 p = openshot.Point(start_animation_frames, 1.0, openshot.BEZIER)
2161 p_object = json.loads(p.Json())
2162 clip.data[
'scale_x'][
"Points"].append(p_object)
2163 p = openshot.Point(start_animation_frames, 1.0, openshot.BEZIER)
2164 p_object = json.loads(p.Json())
2165 clip.data[
'scale_y'][
"Points"].append(p_object)
2167 diff_halfed = (end_animation_frames - start_animation_frames) / 2.0
2168 p1 = openshot.Point(start_animation_frames + diff_halfed, 1.05, openshot.BEZIER)
2169 p1_object = json.loads(p1.Json())
2170 clip.data[
'scale_x'][
"Points"].append(p1_object)
2171 p1 = openshot.Point(start_animation_frames + diff_halfed, 1.05, openshot.BEZIER)
2172 p1_object = json.loads(p1.Json())
2173 clip.data[
'scale_y'][
"Points"].append(p1_object)
2175 p1 = openshot.Point(end_animation_frames, 1.0, openshot.BEZIER)
2176 p1_object = json.loads(p1.Json())
2177 clip.data[
'scale_x'][
"Points"].append(p1_object)
2178 p1 = openshot.Point(end_animation_frames, 1.0, openshot.BEZIER)
2179 p1_object = json.loads(p1.Json())
2180 clip.data[
'scale_y'][
"Points"].append(p1_object)
2185 speed_label = speed.replace(
'X',
'')
2186 speed_parts = speed_label.split(
'/')
2188 if len(speed_parts) == 2:
2189 speed_factor = float(speed_parts[0]) / float(speed_parts[1])
2190 even_multiple = int(speed_parts[1])
2192 speed_factor = float(speed_label)
2193 even_multiple = int(speed_factor)
2196 p = openshot.Point(start_animation, 0.0, openshot.LINEAR)
2197 p_object = json.loads(p.Json())
2198 clip.data[prop_name] = {
"Points" : [p_object]}
2201 if "original_data" in clip.data.keys():
2202 clip.data[
"end"] = clip.data[
"original_data"][
"end"]
2203 clip.data[
"duration"] = clip.data[
"original_data"][
"duration"]
2204 clip.data[
"reader"][
"video_length"] = clip.data[
"original_data"][
"video_length"]
2205 clip.data.pop(
"original_data")
2208 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
2211 start_animation = round(float(clip.data[
"start"]) * fps_float) + 1
2212 duration_animation = self.
round_to_multiple(end_of_clip - start_animation, even_multiple)
2213 end_animation = start_animation + duration_animation
2215 if action == MENU_TIME_FORWARD:
2217 start = openshot.Point(start_animation, start_animation, openshot.LINEAR)
2218 start_object = json.loads(start.Json())
2219 clip.data[prop_name] = {
"Points" : [start_object]}
2220 end = openshot.Point(start_animation + (duration_animation / speed_factor), end_animation, openshot.LINEAR)
2221 end_object = json.loads(end.Json())
2222 clip.data[prop_name][
"Points"].append(end_object)
2225 clip.data[
"end"] = (start_animation + (duration_animation / speed_factor)) / fps_float
2226 clip.data[
"duration"] = self.
round_to_multiple(clip.data[
"duration"] / speed_factor, even_multiple)
2227 clip.data[
"reader"][
"video_length"] = str(self.
round_to_multiple(float(clip.data[
"reader"][
"video_length"]) / speed_factor, even_multiple))
2229 if action == MENU_TIME_BACKWARD:
2231 start = openshot.Point(start_animation, end_animation, openshot.LINEAR)
2232 start_object = json.loads(start.Json())
2233 clip.data[prop_name] = {
"Points" : [start_object]}
2234 end = openshot.Point(start_animation + (duration_animation / speed_factor), start_animation, openshot.LINEAR)
2235 end_object = json.loads(end.Json())
2236 clip.data[prop_name][
"Points"].append(end_object)
2239 clip.data[
"end"] = (start_animation + (duration_animation / speed_factor)) / fps_float
2240 clip.data[
"duration"] = self.
round_to_multiple(clip.data[
"duration"] / speed_factor, even_multiple)
2241 clip.data[
"reader"][
"video_length"] = str(self.
round_to_multiple(float(clip.data[
"reader"][
"video_length"]) / speed_factor, even_multiple))
2244 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2249 return number - (number % multiple)
2254 from math
import sqrt
2257 available_clips = []
2258 start_position = float(clip.data[
"position"])
2259 for c
in Clip.filter():
2260 if float(c.data[
"position"]) >= (start_position - 0.5)
and float(c.data[
"position"]) <= (start_position + 0.5):
2262 available_clips.append(c)
2265 number_of_clips = len(available_clips)
2266 number_of_rows = int(sqrt(number_of_clips))
2267 max_clips_on_row = float(number_of_clips) / float(number_of_rows)
2270 if max_clips_on_row > float(int(max_clips_on_row)):
2271 max_clips_on_row = int(max_clips_on_row + 1)
2273 max_clips_on_row = int(max_clips_on_row)
2276 height = 1.0 / float(number_of_rows)
2277 width = 1.0 / float(max_clips_on_row)
2282 for row
in range(0, number_of_rows):
2285 column_string =
" - - - "
2286 for col
in range(0, max_clips_on_row):
2287 if clip_index < number_of_clips:
2289 X = float(col) * width
2290 Y = float(row) * height
2293 selected_clip = available_clips[clip_index]
2294 selected_clip.data[
"gravity"] = openshot.GRAVITY_TOP_LEFT
2297 selected_clip.data[
"scale"] = openshot.SCALE_STRETCH
2299 selected_clip.data[
"scale"] = openshot.SCALE_FIT
2302 w = openshot.Point(1, width, openshot.BEZIER)
2303 w_object = json.loads(w.Json())
2304 selected_clip.data[
"scale_x"] = {
"Points" : [w_object]}
2305 h = openshot.Point(1, height, openshot.BEZIER)
2306 h_object = json.loads(h.Json())
2307 selected_clip.data[
"scale_y"] = {
"Points" : [h_object]}
2308 x_point = openshot.Point(1, X, openshot.BEZIER)
2309 x_object = json.loads(x_point.Json())
2310 selected_clip.data[
"location_x"] = {
"Points" : [x_object]}
2311 y_point = openshot.Point(1, Y, openshot.BEZIER)
2312 y_object = json.loads(y_point.Json())
2313 selected_clip.data[
"location_y"] = {
"Points" : [y_object]}
2315 log.info(
'Updating clip id: %s' % selected_clip.data[
"id"])
2316 log.info(
'width: %s, height: %s' % (width, height))
2322 self.
update_clip_data(selected_clip.data, only_basic_props=
False, ignore_reader=
True)
2327 log.info(
"Reverse_Transition_Triggered")
2330 for tran_id
in tran_ids:
2333 tran = Transition.get(id=tran_id)
2339 tran_data_copy = deepcopy(tran.data)
2340 new_index = len(tran.data[
"brightness"][
"Points"])
2341 for point
in tran.data[
"brightness"][
"Points"]:
2343 tran_data_copy[
"brightness"][
"Points"][new_index][
"co"][
"Y"] = point[
"co"][
"Y"]
2344 if "handle_left" in point:
2345 tran_data_copy[
"brightness"][
"Points"][new_index][
"handle_left"][
"Y"] = point[
"handle_left"][
"Y"]
2346 tran_data_copy[
"brightness"][
"Points"][new_index][
"handle_right"][
"Y"] = point[
"handle_right"][
"Y"]
2353 log.info(
'ShowTransitionMenu: %s' % tran_id)
2359 tran = Transition.get(id=tran_id)
2365 if tran_id
not in self.window.selected_transitions:
2366 self.window.addSelection(tran_id,
'transition')
2368 tran_ids = self.window.selected_transitions
2369 clip_ids = self.window.selected_clips
2372 fps =
get_app().project.get([
"fps"])
2373 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2376 playhead_position = float(self.window.preview_thread.current_frame) / fps_float
2381 if len(tran_ids) + len(clip_ids) > 1:
2383 Copy_All = menu.addAction(_(
"Copy"))
2384 Copy_All.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
2385 Copy_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_ALL, clip_ids, tran_ids))
2388 Copy_Menu = QMenu(_(
"Copy"), self)
2389 Copy_Tran = Copy_Menu.addAction(_(
"Transition"))
2390 Copy_Tran.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
2391 Copy_Tran.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_TRANSITION, [], [tran_id]))
2393 Keyframe_Menu = QMenu(_(
"Keyframes"), self)
2394 Copy_Keyframes_All = Keyframe_Menu.addAction(_(
"All"))
2395 Copy_Keyframes_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALL, [], [tran_id]))
2396 Keyframe_Menu.addSeparator()
2397 Copy_Keyframes_Brightness = Keyframe_Menu.addAction(_(
"Brightness"))
2398 Copy_Keyframes_Brightness.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_BRIGHTNESS, [], [tran_id]))
2399 Copy_Keyframes_Scale = Keyframe_Menu.addAction(_(
"Contrast"))
2400 Copy_Keyframes_Scale.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_CONTRAST, [], [tran_id]))
2403 Copy_Menu.addMenu(Keyframe_Menu)
2404 menu.addMenu(Copy_Menu)
2408 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
2409 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
2413 Paste_Tran = menu.addAction(_(
"Paste"))
2414 Paste_Tran.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, 0.0, 0, [], tran_ids))
2419 if len(clip_ids) > 1:
2420 Alignment_Menu = QMenu(_(
"Align"), self)
2421 Align_Left = Alignment_Menu.addAction(_(
"Left"))
2422 Align_Left.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_LEFT, clip_ids, tran_ids))
2423 Align_Right = Alignment_Menu.addAction(_(
"Right"))
2424 Align_Right.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_RIGHT, clip_ids, tran_ids))
2427 menu.addMenu(Alignment_Menu)
2431 start_of_tran = float(tran.data[
"start"])
2432 end_of_tran = float(tran.data[
"end"])
2433 position_of_tran = float(tran.data[
"position"])
2434 if playhead_position >= position_of_tran
and playhead_position <= (position_of_tran + (end_of_tran - start_of_tran)):
2436 Slice_Menu = QMenu(_(
"Slice"), self)
2437 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
2438 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, [], [tran_id], playhead_position))
2439 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
2440 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, [], [tran_id], playhead_position))
2441 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
2442 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, [], [tran_id], playhead_position))
2443 menu.addMenu(Slice_Menu)
2446 Reverse_Transition = menu.addAction(_(
"Reverse Transition"))
2451 menu.addAction(self.window.actionProperties)
2455 menu.addAction(self.window.actionRemoveTransition)
2458 return menu.popup(QCursor.pos())
2462 log.info(
'ShowTrackMenu: %s' % layer_id)
2464 if layer_id
not in self.window.selected_tracks:
2465 self.window.selected_tracks = [layer_id]
2468 track = Track.get(id=layer_id)
2471 menu.addAction(self.window.actionAddTrackAbove)
2472 menu.addAction(self.window.actionAddTrackBelow)
2473 menu.addAction(self.window.actionRenameTrack)
2474 if track.data.get(
"lock",
False):
2475 menu.addAction(self.window.actionUnlockTrack)
2477 menu.addAction(self.window.actionLockTrack)
2479 menu.addAction(self.window.actionRemoveTrack)
2480 return menu.popup(QCursor.pos())
2484 log.info(
'ShowMarkerMenu: %s' % marker_id)
2486 if marker_id
not in self.window.selected_markers:
2487 self.window.selected_markers = [marker_id]
2490 menu.addAction(self.window.actionRemoveMarker)
2491 return menu.popup(QCursor.pos())
2497 clip = Clip.get(id=clip_id)
2502 path = clip.data[
'reader'][
'path']
2505 frame_number = max(frame_number, 1)
2506 frame_number = min(frame_number, int(clip.data[
'reader'][
'video_length']))
2509 self.window.LoadFileSignal.emit(path)
2510 self.window.SpeedSignal.emit(0)
2513 self.window.SeekSignal.emit(frame_number)
2515 @pyqtSlot(float, int, str)
2519 self.window.LoadFileSignal.emit(
'')
2526 self.window.previewFrame(position_seconds, position_frames, time_code)
2534 code = JS_SCOPE_SELECTOR +
".MovePlayheadToFrame(" + str(position_frames) +
");"
2543 self.
eval_js(JS_SCOPE_SELECTOR +
".SetSnappingMode(%s);" % int(enable_snapping))
2551 self.
eval_js(JS_SCOPE_SELECTOR +
".SetRazorMode(%s);" % int(enable_razor))
2553 @pyqtSlot(str, str, bool)
2559 self.window.addSelection(item_id, item_type, clear_existing)
2567 self.window.removeSelection(item_id, item_type)
2581 self.window.zoomScaleLabel.setText(_(
"{} seconds").format(newScale))
2584 cursor_y = self.mapFromGlobal(self.cursor().pos()).y()
2586 cursor_x = self.mapFromGlobal(self.cursor().pos()).x()
2591 cmd = JS_SCOPE_SELECTOR +
".setScale(" + str(newScale) +
"," + str(cursor_x) +
");"
2592 self.page().mainFrame().evaluateJavaScript(cmd)
2595 self.redraw_audio_timer.start()
2598 get_app().updates.ignore_history =
True
2599 get_app().updates.update([
"scale"], newScale)
2600 get_app().updates.ignore_history =
False
2605 key_value = event.key()
2606 if (key_value == Qt.Key_Shift
or key_value == Qt.Key_Control):
2609 return QWebView.keyPressEvent(self, event)
2617 if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
2620 steps = int(event.angleDelta().y() / tick_scale)
2621 self.window.sliderZoom.setValue(self.window.sliderZoom.value() - self.window.sliderZoom.pageStep() * steps)
2628 self.page().mainFrame().addToJavaScriptWindowObject(
'timeline', self)
2629 self.page().mainFrame().addToJavaScriptWindowObject(
'mainWindow', self.
window)
2638 if not self.
new_item and not event.mimeData().hasUrls()
and event.mimeData().html():
2646 data = json.loads(event.mimeData().text())
2659 elif not self.
new_item and event.mimeData().hasUrls():
2675 file = File.get(id=file_id)
2681 if (file.data[
"media_type"] ==
"video" or file.data[
"media_type"] ==
"image"):
2683 thumb_path = os.path.join(info.THUMBNAIL_PATH,
"%s.png" % file.data[
"id"])
2686 thumb_path = os.path.join(info.PATH,
"images",
"AudioThumbnail.png")
2689 path, filename = os.path.split(file.data[
"path"])
2692 file_path = file.absolute_path()
2695 c = openshot.Clip(file_path)
2698 new_clip = json.loads(c.Json())
2699 new_clip[
"file_id"] = file.id
2700 new_clip[
"title"] = filename
2701 new_clip[
"image"] = thumb_path
2705 if not new_clip.get(
"reader"):
2710 end_frame = new_clip[
"reader"][
"duration"]
2711 if 'start' in file.data.keys():
2712 new_clip[
"start"] = file.data[
'start']
2713 if 'end' in file.data.keys():
2714 new_clip[
"end"] = file.data[
'end']
2717 top_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2718 new_clip[
"layer"] = top_layer
2721 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2722 new_clip[
"position"] = js_position
2725 new_clip[
"duration"] = new_clip[
"reader"][
"duration"]
2726 if file.data[
"media_type"] ==
"image":
2727 new_clip[
"end"] = self.settings.get(
"default-image-length")
2730 file_properties_fps = float(file.data[
"fps"][
"num"]) / float(file.data[
"fps"][
"den"])
2731 file_fps = float(new_clip[
"reader"][
"fps"][
"num"]) / float(new_clip[
"reader"][
"fps"][
"den"])
2732 fps_diff = file_fps / file_properties_fps
2733 new_clip[
"reader"][
"fps"][
"num"] = file.data[
"fps"][
"num"]
2734 new_clip[
"reader"][
"fps"][
"den"] = file.data[
"fps"][
"den"]
2736 new_clip[
"reader"][
"duration"] *= fps_diff
2737 new_clip[
"end"] *= fps_diff
2738 new_clip[
"duration"] *= fps_diff
2747 code = JS_SCOPE_SELECTOR +
".StartManualMove('" + self.
item_type +
"', '" + self.
item_id +
"');"
2755 get_app().updates.update([
"duration"], new_duration)
2759 log.info(
"addTransition...")
2762 top_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2765 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2768 fps =
get_app().project.get([
"fps"])
2769 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2772 transition_reader = openshot.QtImageReader(file_ids[0])
2774 brightness = openshot.Keyframe()
2775 brightness.AddPoint(1, 1.0, openshot.BEZIER)
2776 brightness.AddPoint(round(10 * fps_float) + 1, -1.0, openshot.BEZIER)
2777 contrast = openshot.Keyframe(3.0)
2780 transitions_data = {
2781 "id":
get_app().project.generate_id(),
2783 "title":
"Transition",
2785 "position": js_position,
2788 "brightness": json.loads(brightness.Json()),
2789 "contrast": json.loads(contrast.Json()),
2790 "reader": json.loads(transition_reader.Json()),
2791 "replace_image":
False
2798 self.
item_id = transitions_data.get(
'id')
2801 code = JS_SCOPE_SELECTOR +
".StartManualMove('" + self.
item_type +
"', '" + self.
item_id +
"');"
2806 log.info(
"addEffect: %s at %s" % (effect_names, position))
2808 name = effect_names[0]
2811 closest_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2814 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2817 possible_clips = Clip.filter(layer=closest_layer)
2818 for clip
in possible_clips:
2819 if js_position == 0
or (clip.data[
"position"] <= js_position <= clip.data[
"position"] + (
2820 clip.data[
"end"] - clip.data[
"start"])):
2821 log.info(
"Applying effect to clip")
2825 effect = openshot.EffectInfo().CreateEffect(name)
2828 effect.Id(
get_app().project.generate_id())
2829 effect_json = json.loads(effect.Json())
2832 clip.data[
"effects"].append(effect_json)
2835 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2846 if self.
item_type in [
"clip",
"transition"]:
2847 code = JS_SCOPE_SELECTOR +
".MoveItem(" + str(pos.x()) +
", " + str(pos.y()) +
", '" + self.
item_type +
"');"
2852 log.info(
"Dropping item on timeline - item_id: %s, item_type: %s" % (self.
item_id, self.
item_type))
2863 data = json.loads(event.mimeData().text())
2868 get_app().window.filesTreeView.dropEvent(event)
2871 for uri
in event.mimeData().urls():
2872 filepath = uri.toLocalFile()
2873 if os.path.exists(filepath)
and os.path.isfile(filepath):
2875 log.info(
'Adding clip for {}'.format(os.path.basename(filepath)))
2876 for file
in File.filter(path=filepath):
2889 get_app().window.refreshFrameSignal.emit()
2890 get_app().window.propertyTableView.select_frame(self.window.preview_thread.player.Position())
2895 log.info(
'dragLeaveEvent - Undo drop')
2897 get_app().window.actionRemoveClip.trigger()
2899 get_app().window.actionRemoveTransition.trigger()
2912 log.info(
'redraw_audio_onTimeout')
2915 self.redraw_audio_timer.stop()
2918 cmd = JS_SCOPE_SELECTOR +
".reDrawAllAudioData();"
2919 self.page().mainFrame().evaluateJavaScript(cmd)
2926 cmd = JS_SCOPE_SELECTOR +
".ClearAllSelections();"
2927 self.page().mainFrame().evaluateJavaScript(cmd)
2934 cmd = JS_SCOPE_SELECTOR +
".SelectAll();"
2935 self.page().mainFrame().evaluateJavaScript(cmd)
2943 cache_object =
get_app().window.timeline_sync.timeline.GetCache()
2944 if cache_object
and cache_object.Count() > 0:
2946 cache_json =
get_app().window.timeline_sync.timeline.GetCache().Json()
2947 cache_dict = json.loads(cache_json)
2948 cache_version = cache_dict[
"version"]
2954 cmd = JS_SCOPE_SELECTOR +
".RenderCache(" + cache_json +
");"
2955 self.page().mainFrame().evaluateJavaScript(cmd)
2961 QWebView.__init__(self)
2963 self.setAcceptDrops(
True)
2971 get_app().updates.add_listener(self)
2974 self.setUrl(QUrl.fromLocalFile(QFileInfo(self.
html_path).absoluteFilePath()))
2977 self.page().mainFrame().javaScriptWindowObjectCleared.connect(self.
setup_js_data)
2980 window.sliderZoom.valueChanged.connect(self.
update_zoom)
2996 self.redraw_audio_timer.setInterval(300)
3002 self.cache_renderer.setInterval(0.5 * 1000)
3006 QTimer.singleShot(1500, self.cache_renderer.start)
def secondsToZoom
Convert a number of seconds to a timeline zoom factor.
def Volume_Triggered
Callback for volume context menus.
def update_clip_data
Create an updateAction and send it to the update manager.
def get_app
Returns the current QApplication instance of OpenShot.
def keyPressEvent
Keypress callback for timeline.
def Hide_Waveform_Triggered
Hide the waveform for the selected clip.
def Split_Audio_Triggered
Callback for split audio context menus.
def UpdateClipThumbnail
Update the thumbnail image for clips.
def SetRazorMode
Enable / Disable razor mode.
def update_transition_data
Create an updateAction and send it to the update manager.
def RazorSliceAtCursor
Callback from javascript that the razor tool was clicked.
def page_ready
Document.Ready event has fired, and is initialized.
def Paste_Triggered
Callback for paste context menus.
A WebView QWidget used to load the Timeline.
def show_all_clips
Show all clips at the same time (arranged col by col, row by row)
def movePlayhead
Move the playhead since the position has changed inside OpenShot (probably due to the video player) ...
def ClearAllSelections
Clear all selections in JavaScript.
def Reverse_Transition_Triggered
Callback for reversing a transition.
def Show_Waveform_Triggered
Show a waveform for the selected clip.
def render_cache_json
Render the cached frames to the timeline (called every X seconds), and only if changed.
def dragLeaveEvent
A drag is in-progress and the user moves mouse outside of timeline.
def SetSnappingMode
Enable / Disable snapping mode.
def GenerateThumbnail
Create thumbnail image, and check for rotate metadata (if any)
def removeSelection
Remove the selected clip from the selection.
def Rotate_Triggered
Callback for rotate context menus.
def Layout_Triggered
Callback for the layout context menus.
def round_to_multiple
Round this to the closest multiple of a given #.
def Copy_Triggered
Callback for copy context menus.
def addSelection
Add the selected item to the current selection.
def zoomToSeconds
Convert zoom factor (slider position) into scale-seconds.
def add_missing_transition
def Fade_Triggered
Callback for fade context menus.
def resizeTimeline
Resize the duration of the timeline.
def SelectAll
Select all clips and transitions in JavaScript.
def Waveform_Ready
Callback when audio waveform is ready.
def Align_Triggered
Callback for alignment context menus.
def redraw_audio_onTimeout
Timer is ready to redraw audio (if any)
def Time_Triggered
Callback for rotate context menus.
copy_transition_clipboard
Interface for classes that listen for changes (insert, update, and delete).
def Slice_Triggered
Callback for slice context menus.
def Nudge_Triggered
Callback for clip nudges.
def get_settings
Get the current QApplication's settings instance.
def Animate_Triggered
Callback for the animate context menus.