33 from copy
import deepcopy
34 from functools
import partial
35 from random
import uniform
36 from urllib.parse
import urlparse
37 from operator
import itemgetter
40 from PyQt5.QtCore import QFileInfo, pyqtSlot, QUrl, Qt, QCoreApplication, QTimer
42 from PyQt5.QtWebKitWidgets
import QWebView
45 from classes
import info, updates
46 from classes
import settings
47 from classes.app
import get_app
48 from classes.logger
import log
49 from classes.query
import File, Clip, Transition, Track
50 from classes.waveform
import get_audio_data
51 from classes.thumbnail
import GenerateThumbnail
52 from classes.conversion
import zoomToSeconds, secondsToZoom
57 import simplejson
as json
60 JS_SCOPE_SELECTOR =
"$('body').scope()"
65 MENU_FADE_OUT_FAST = 3
66 MENU_FADE_OUT_SLOW = 4
67 MENU_FADE_IN_OUT_FAST = 5
68 MENU_FADE_IN_OUT_SLOW = 6
71 MENU_ROTATE_90_RIGHT = 1
72 MENU_ROTATE_90_LEFT = 2
73 MENU_ROTATE_180_FLIP = 3
76 MENU_LAYOUT_CENTER = 1
77 MENU_LAYOUT_TOP_LEFT = 2
78 MENU_LAYOUT_TOP_RIGHT = 3
79 MENU_LAYOUT_BOTTOM_LEFT = 4
80 MENU_LAYOUT_BOTTOM_RIGHT = 5
81 MENU_LAYOUT_ALL_WITH_ASPECT = 6
82 MENU_LAYOUT_ALL_WITHOUT_ASPECT = 7
88 MENU_ANIMATE_IN_50_100 = 1
89 MENU_ANIMATE_IN_75_100 = 2
90 MENU_ANIMATE_IN_100_150 = 3
91 MENU_ANIMATE_OUT_100_75 = 4
92 MENU_ANIMATE_OUT_100_50 = 5
93 MENU_ANIMATE_OUT_150_100 = 6
94 MENU_ANIMATE_CENTER_TOP = 7
95 MENU_ANIMATE_CENTER_LEFT = 8
96 MENU_ANIMATE_CENTER_RIGHT = 9
97 MENU_ANIMATE_CENTER_BOTTOM = 10
98 MENU_ANIMATE_TOP_CENTER = 11
99 MENU_ANIMATE_LEFT_CENTER = 12
100 MENU_ANIMATE_RIGHT_CENTER = 13
101 MENU_ANIMATE_BOTTOM_CENTER = 14
102 MENU_ANIMATE_TOP_BOTTOM = 15
103 MENU_ANIMATE_LEFT_RIGHT = 16
104 MENU_ANIMATE_RIGHT_LEFT = 17
105 MENU_ANIMATE_BOTTOM_TOP = 18
106 MENU_ANIMATE_RANDOM = 19
109 MENU_VOLUME_FADE_IN_FAST = 2
110 MENU_VOLUME_FADE_IN_SLOW = 3
111 MENU_VOLUME_FADE_OUT_FAST = 4
112 MENU_VOLUME_FADE_OUT_SLOW = 5
113 MENU_VOLUME_FADE_IN_OUT_FAST = 6
114 MENU_VOLUME_FADE_IN_OUT_SLOW = 7
115 MENU_VOLUME_LEVEL_100 = 100
116 MENU_VOLUME_LEVEL_90 = 90
117 MENU_VOLUME_LEVEL_80 = 80
118 MENU_VOLUME_LEVEL_70 = 70
119 MENU_VOLUME_LEVEL_60 = 60
120 MENU_VOLUME_LEVEL_50 = 50
121 MENU_VOLUME_LEVEL_40 = 40
122 MENU_VOLUME_LEVEL_30 = 30
123 MENU_VOLUME_LEVEL_20 = 20
124 MENU_VOLUME_LEVEL_10 = 10
125 MENU_VOLUME_LEVEL_0 = 0
130 MENU_TIME_FORWARD = 1
131 MENU_TIME_BACKWARD = 2
133 MENU_TIME_FREEZE_ZOOM = 4
137 MENU_COPY_KEYFRAMES_ALL = 1
138 MENU_COPY_KEYFRAMES_ALPHA = 2
139 MENU_COPY_KEYFRAMES_SCALE = 3
140 MENU_COPY_KEYFRAMES_ROTATE = 4
141 MENU_COPY_KEYFRAMES_LOCATION = 5
142 MENU_COPY_KEYFRAMES_TIME = 6
143 MENU_COPY_KEYFRAMES_VOLUME = 7
144 MENU_COPY_EFFECTS = 8
147 MENU_COPY_TRANSITION = 10
148 MENU_COPY_KEYFRAMES_BRIGHTNESS = 11
149 MENU_COPY_KEYFRAMES_CONTRAST = 12
151 MENU_SLICE_KEEP_BOTH = 0
152 MENU_SLICE_KEEP_LEFT = 1
153 MENU_SLICE_KEEP_RIGHT = 2
155 MENU_SPLIT_AUDIO_SINGLE = 0
156 MENU_SPLIT_AUDIO_MULTIPLE = 1
164 html_path = os.path.join(info.PATH,
'timeline',
'index.html')
176 log.error(
"TimelineWebView::eval_js() called before document ready event. Script queued: %s" % code)
177 QTimer.singleShot(50, partial(self.
eval_js, code))
181 return self.page().mainFrame().evaluateJavaScript(code)
186 action = deepcopy(action)
187 action.old_values = {}
190 if action.type ==
"load":
193 self.
eval_js(JS_SCOPE_SELECTOR +
".SetTrackLabel('" + _(
"Track %s") +
"');")
196 code = JS_SCOPE_SELECTOR +
".LoadJson(" + action.json() +
");"
199 code = JS_SCOPE_SELECTOR +
".ApplyJsonDiff([" + action.json() +
"]);"
203 if action.type ==
"load":
205 initial_scale =
get_app().project.get([
"scale"])
or 15
209 @pyqtSlot(str, bool, bool, bool)
212 def update_clip_data(self, clip_json, only_basic_props=True, ignore_reader=False, ignore_refresh=False):
216 if not isinstance(clip_json, dict):
217 clip_data = json.loads(clip_json)
219 clip_data = clip_json
225 existing_clip = Clip.get(id=clip_data[
"id"])
226 if not existing_clip:
228 existing_clip = Clip()
231 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"]:
236 existing_clip.data = clip_data
240 existing_clip.data = {}
241 existing_clip.data[
"id"] = clip_data[
"id"]
242 existing_clip.data[
"layer"] = clip_data[
"layer"]
243 existing_clip.data[
"position"] = clip_data[
"position"]
244 existing_clip.data[
"image"] = clip_data[
"image"]
245 existing_clip.data[
"start"] = clip_data[
"start"]
246 existing_clip.data[
"end"] = clip_data[
"end"]
249 if ignore_reader
and "reader" in existing_clip.data:
250 existing_clip.data.pop(
"reader")
256 if not ignore_refresh:
257 get_app().window.refreshFrameSignal.emit()
258 get_app().window.propertyTableView.select_frame(self.window.preview_thread.player.Position())
266 fps = clip_data[
"reader"][
"fps"]
267 fps_float = float(fps[
"num"]) / float(fps[
"den"])
270 start_frame = round(float(clip_data[
"start"]) * fps_float) + 1
273 thumb_path = os.path.join(info.THUMBNAIL_PATH,
"{}-{}.png".format(clip_data[
"id"], start_frame))
274 log.info(
'Updating thumbnail image: %s' % thumb_path)
277 if not os.path.exists(thumb_path):
280 file = File.get(id=clip_data[
"file_id"])
287 file_path = file.absolute_path()
291 if file.data[
"media_type"] ==
"video":
292 overlay_path = os.path.join(info.IMAGES_PATH,
"overlay.png")
295 GenerateThumbnail(file_path, thumb_path, start_frame, 98, 64, os.path.join(info.IMAGES_PATH,
"mask.png"), overlay_path)
298 clip_data[
"image"] = thumb_path
304 transition_details = json.loads(transition_json)
307 fps =
get_app().project.get([
"fps"])
308 fps_float = float(fps[
"num"]) / float(fps[
"den"])
311 transition_reader = openshot.QtImageReader(
312 os.path.join(info.PATH,
"transitions",
"common",
"fade.svg"))
315 transition_object = openshot.Mask()
318 brightness = transition_object.brightness
319 brightness.AddPoint(1, 1.0, openshot.BEZIER)
320 brightness.AddPoint(round(transition_details[
"end"] * fps_float) + 1, -1.0, openshot.BEZIER)
321 contrast = openshot.Keyframe(3.0)
325 "id":
get_app().project.generate_id(),
326 "layer": transition_details[
"layer"],
327 "title":
"Transition",
329 "position": transition_details[
"position"],
330 "start": transition_details[
"start"],
331 "end": transition_details[
"end"],
332 "brightness": json.loads(brightness.Json()),
333 "contrast": json.loads(contrast.Json()),
334 "reader": json.loads(transition_reader.Json()),
335 "replace_image":
False
342 @pyqtSlot(str, bool, bool)
348 if not isinstance(transition_json, dict):
349 transition_data = json.loads(transition_json)
351 transition_data = transition_json
354 existing_item = Transition.get(id=transition_data[
"id"])
356 if not existing_item:
358 existing_item = Transition()
360 existing_item.data = transition_data
363 fps =
get_app().project.get([
"fps"])
364 fps_float = float(fps[
"num"]) / float(fps[
"den"])
365 duration = existing_item.data[
"end"] - existing_item.data[
"start"]
373 brightness = existing_item.data[
"brightness"]
374 if len(brightness[
"Points"]) > 1:
376 brightness[
"Points"][-1][
"co"][
"X"] = round(duration * fps_float) + 1
379 contrast = existing_item.data[
"contrast"]
380 if len(contrast[
"Points"]) > 1:
382 contrast[
"Points"][-1][
"co"][
"X"] = round(duration * fps_float) + 1
385 b = openshot.Keyframe()
386 b.AddPoint(1, 1.0, openshot.BEZIER)
387 b.AddPoint(round(duration * fps_float) + 1, -1.0, openshot.BEZIER)
388 brightness = json.loads(b.Json())
392 existing_item.data = {}
393 existing_item.data[
"id"] = transition_data[
"id"]
394 existing_item.data[
"layer"] = transition_data[
"layer"]
395 existing_item.data[
"position"] = transition_data[
"position"]
396 existing_item.data[
"start"] = transition_data[
"start"]
397 existing_item.data[
"end"] = transition_data[
"end"]
399 log.info(
'transition start: %s' % transition_data[
"start"])
400 log.info(
'transition end: %s' % transition_data[
"end"])
403 existing_item.data[
"brightness"] = brightness
405 existing_item.data[
"contrast"] = contrast
411 if not ignore_refresh:
412 get_app().window.refreshFrameSignal.emit()
413 get_app().window.propertyTableView.select_frame(self.window.preview_thread.player.Position())
422 log.info(
'ShowPlayheadMenu: %s' % position)
428 intersecting_clips = Clip.filter(intersect=position)
429 intersecting_trans = Transition.filter(intersect=position)
432 if intersecting_clips
or intersecting_trans:
434 clip_ids = [c.id
for c
in intersecting_clips]
435 trans_ids = [t.id
for t
in intersecting_trans]
438 Slice_Menu = QMenu(_(
"Slice All"), self)
439 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
440 Slice_Keep_Both.setShortcut(QKeySequence(self.window.getShortcutByName(
"sliceAllKeepBothSides")))
441 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, clip_ids, trans_ids, position))
442 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
443 Slice_Keep_Left.setShortcut(QKeySequence(self.window.getShortcutByName(
"sliceAllKeepLeftSide")))
444 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, clip_ids, trans_ids, position))
445 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
446 Slice_Keep_Right.setShortcut(QKeySequence(self.window.getShortcutByName(
"sliceAllKeepRightSide")))
447 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, clip_ids, trans_ids, position))
448 menu.addMenu(Slice_Menu)
449 return menu.popup(QCursor.pos())
453 log.info(
'ShowEffectMenu: %s' % effect_id)
456 self.window.addSelection(effect_id,
'effect',
True)
460 menu.addAction(self.window.actionProperties)
464 menu.addAction(self.window.actionRemoveEffect)
465 return menu.popup(QCursor.pos())
467 @pyqtSlot(float, int)
469 log.info(
'ShowTimelineMenu: position: %s, layer: %s' % (position, layer_id))
476 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
477 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
481 if len(clipboard_clip_ids) + len(clipboard_tran_ids) > 0:
483 Paste_Clip = menu.addAction(_(
"Paste"))
484 Paste_Clip.setShortcut(QKeySequence(self.window.getShortcutByName(
"pasteAll")))
485 Paste_Clip.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, float(position), int(layer_id), [], []))
487 return menu.popup(QCursor.pos())
491 log.info(
'ShowClipMenu: %s' % clip_id)
497 clip = Clip.get(id=clip_id)
503 if clip_id
not in self.window.selected_clips:
504 self.window.addSelection(clip_id,
'clip')
506 clip_ids = self.window.selected_clips
507 tran_ids = self.window.selected_transitions
510 fps =
get_app().project.get([
"fps"])
511 fps_float = float(fps[
"num"]) / float(fps[
"den"])
514 playhead_position = float(self.window.preview_thread.current_frame) / fps_float
517 translations = [_(
"Start of Clip"), _(
"End of Clip"), _(
"Entire Clip"), _(
"Normal"), _(
"Fast"), _(
"Slow"), _(
"Forward"), _(
"Backward")]
523 if len(tran_ids) + len(clip_ids) > 1:
525 Copy_All = menu.addAction(_(
"Copy"))
526 Copy_All.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
527 Copy_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_ALL, clip_ids, tran_ids))
530 Copy_Menu = QMenu(_(
"Copy"), self)
531 Copy_Clip = Copy_Menu.addAction(_(
"Clip"))
532 Copy_Clip.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
533 Copy_Clip.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_CLIP, [clip_id], []))
535 Keyframe_Menu = QMenu(_(
"Keyframes"), self)
536 Copy_Keyframes_All = Keyframe_Menu.addAction(_(
"All"))
537 Copy_Keyframes_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALL, [clip_id], []))
538 Keyframe_Menu.addSeparator()
539 Copy_Keyframes_Alpha = Keyframe_Menu.addAction(_(
"Alpha"))
540 Copy_Keyframes_Alpha.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALPHA, [clip_id], []))
541 Copy_Keyframes_Scale = Keyframe_Menu.addAction(_(
"Scale"))
542 Copy_Keyframes_Scale.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_SCALE, [clip_id], []))
543 Copy_Keyframes_Rotate = Keyframe_Menu.addAction(_(
"Rotation"))
544 Copy_Keyframes_Rotate.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ROTATE, [clip_id], []))
545 Copy_Keyframes_Locate = Keyframe_Menu.addAction(_(
"Location"))
546 Copy_Keyframes_Locate.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_LOCATION, [clip_id], []))
547 Copy_Keyframes_Time = Keyframe_Menu.addAction(_(
"Time"))
548 Copy_Keyframes_Time.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_TIME, [clip_id], []))
549 Copy_Keyframes_Volume = Keyframe_Menu.addAction(_(
"Volume"))
550 Copy_Keyframes_Volume.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_VOLUME, [clip_id], []))
553 Copy_Effects = Copy_Menu.addAction(_(
"Effects"))
554 Copy_Effects.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_EFFECTS, [clip_id], []))
555 Copy_Menu.addMenu(Keyframe_Menu)
556 menu.addMenu(Copy_Menu)
560 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
561 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
563 if self.
copy_clipboard and len(clipboard_clip_ids) + len(clipboard_tran_ids) == 0:
565 Paste_Clip = menu.addAction(_(
"Paste"))
566 Paste_Clip.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, 0.0, 0, clip_ids, []))
571 if len(clip_ids) > 1:
572 Alignment_Menu = QMenu(_(
"Align"), self)
573 Align_Left = Alignment_Menu.addAction(_(
"Left"))
574 Align_Left.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_LEFT, clip_ids, tran_ids))
575 Align_Right = Alignment_Menu.addAction(_(
"Right"))
576 Align_Right.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_RIGHT, clip_ids, tran_ids))
579 menu.addMenu(Alignment_Menu)
582 Fade_Menu = QMenu(_(
"Fade"), self)
583 Fade_None = Fade_Menu.addAction(_(
"No Fade"))
584 Fade_None.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_NONE, clip_ids))
585 Fade_Menu.addSeparator()
586 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
587 Position_Menu = QMenu(_(position), self)
589 if position ==
"Start of Clip":
590 Fade_In_Fast = Position_Menu.addAction(_(
"Fade In (Fast)"))
591 Fade_In_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_FAST, clip_ids, position))
592 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Slow)"))
593 Fade_In_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_SLOW, clip_ids, position))
595 elif position ==
"End of Clip":
596 Fade_Out_Fast = Position_Menu.addAction(_(
"Fade Out (Fast)"))
597 Fade_Out_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_FAST, clip_ids, position))
598 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Slow)"))
599 Fade_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_SLOW, clip_ids, position))
602 Fade_In_Out_Fast = Position_Menu.addAction(_(
"Fade In and Out (Fast)"))
603 Fade_In_Out_Fast.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_OUT_FAST, clip_ids, position))
604 Fade_In_Out_Slow = Position_Menu.addAction(_(
"Fade In and Out (Slow)"))
605 Fade_In_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_OUT_SLOW, clip_ids, position))
606 Position_Menu.addSeparator()
607 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Entire Clip)"))
608 Fade_In_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_IN_SLOW, clip_ids, position))
609 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Entire Clip)"))
610 Fade_Out_Slow.triggered.connect(partial(self.
Fade_Triggered, MENU_FADE_OUT_SLOW, clip_ids, position))
612 Fade_Menu.addMenu(Position_Menu)
613 menu.addMenu(Fade_Menu)
617 Animate_Menu = QMenu(_(
"Animate"), self)
618 Animate_None = Animate_Menu.addAction(_(
"No Animation"))
619 Animate_None.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_NONE, clip_ids))
620 Animate_Menu.addSeparator()
621 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
622 Position_Menu = QMenu(_(position), self)
625 Scale_Menu = QMenu(_(
"Zoom"), self)
626 Animate_In_50_100 = Scale_Menu.addAction(_(
"Zoom In (50% to 100%)"))
627 Animate_In_50_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_50_100, clip_ids, position))
628 Animate_In_75_100 = Scale_Menu.addAction(_(
"Zoom In (75% to 100%)"))
629 Animate_In_75_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_75_100, clip_ids, position))
630 Animate_In_100_150 = Scale_Menu.addAction(_(
"Zoom In (100% to 150%)"))
631 Animate_In_100_150.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_IN_100_150, clip_ids, position))
632 Animate_Out_100_75 = Scale_Menu.addAction(_(
"Zoom Out (100% to 75%)"))
633 Animate_Out_100_75.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_100_75, clip_ids, position))
634 Animate_Out_100_50 = Scale_Menu.addAction(_(
"Zoom Out (100% to 50%)"))
635 Animate_Out_100_50.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_100_50, clip_ids, position))
636 Animate_Out_150_100 = Scale_Menu.addAction(_(
"Zoom Out (150% to 100%)"))
637 Animate_Out_150_100.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_OUT_150_100, clip_ids, position))
638 Position_Menu.addMenu(Scale_Menu)
641 Center_Edge_Menu = QMenu(_(
"Center to Edge"), self)
642 Animate_Center_Top = Center_Edge_Menu.addAction(_(
"Center to Top"))
643 Animate_Center_Top.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_TOP, clip_ids, position))
644 Animate_Center_Left = Center_Edge_Menu.addAction(_(
"Center to Left"))
645 Animate_Center_Left.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_LEFT, clip_ids, position))
646 Animate_Center_Right = Center_Edge_Menu.addAction(_(
"Center to Right"))
647 Animate_Center_Right.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_RIGHT, clip_ids, position))
648 Animate_Center_Bottom = Center_Edge_Menu.addAction(_(
"Center to Bottom"))
649 Animate_Center_Bottom.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_CENTER_BOTTOM, clip_ids, position))
650 Position_Menu.addMenu(Center_Edge_Menu)
653 Edge_Center_Menu = QMenu(_(
"Edge to Center"), self)
654 Animate_Top_Center = Edge_Center_Menu.addAction(_(
"Top to Center"))
655 Animate_Top_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_TOP_CENTER, clip_ids, position))
656 Animate_Left_Center = Edge_Center_Menu.addAction(_(
"Left to Center"))
657 Animate_Left_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_LEFT_CENTER, clip_ids, position))
658 Animate_Right_Center = Edge_Center_Menu.addAction(_(
"Right to Center"))
659 Animate_Right_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RIGHT_CENTER, clip_ids, position))
660 Animate_Bottom_Center = Edge_Center_Menu.addAction(_(
"Bottom to Center"))
661 Animate_Bottom_Center.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_BOTTOM_CENTER, clip_ids, position))
662 Position_Menu.addMenu(Edge_Center_Menu)
665 Edge_Edge_Menu = QMenu(_(
"Edge to Edge"), self)
666 Animate_Top_Bottom = Edge_Edge_Menu.addAction(_(
"Top to Bottom"))
667 Animate_Top_Bottom.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_TOP_BOTTOM, clip_ids, position))
668 Animate_Left_Right = Edge_Edge_Menu.addAction(_(
"Left to Right"))
669 Animate_Left_Right.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_LEFT_RIGHT, clip_ids, position))
670 Animate_Right_Left = Edge_Edge_Menu.addAction(_(
"Right to Left"))
671 Animate_Right_Left.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RIGHT_LEFT, clip_ids, position))
672 Animate_Bottom_Top = Edge_Edge_Menu.addAction(_(
"Bottom to Top"))
673 Animate_Bottom_Top.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_BOTTOM_TOP, clip_ids, position))
674 Position_Menu.addMenu(Edge_Edge_Menu)
677 Position_Menu.addSeparator()
678 Random = Position_Menu.addAction(_(
"Random"))
679 Random.triggered.connect(partial(self.
Animate_Triggered, MENU_ANIMATE_RANDOM, clip_ids, position))
682 Animate_Menu.addMenu(Position_Menu)
685 menu.addMenu(Animate_Menu)
688 Rotation_Menu = QMenu(_(
"Rotate"), self)
689 Rotation_None = Rotation_Menu.addAction(_(
"No Rotation"))
690 Rotation_None.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_NONE, clip_ids))
691 Rotation_Menu.addSeparator()
692 Rotation_90_Right = Rotation_Menu.addAction(_(
"Rotate 90 (Right)"))
693 Rotation_90_Right.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_90_RIGHT, clip_ids))
694 Rotation_90_Left = Rotation_Menu.addAction(_(
"Rotate 90 (Left)"))
695 Rotation_90_Left.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_90_LEFT, clip_ids))
696 Rotation_180_Flip = Rotation_Menu.addAction(_(
"Rotate 180 (Flip)"))
697 Rotation_180_Flip.triggered.connect(partial(self.
Rotate_Triggered, MENU_ROTATE_180_FLIP, clip_ids))
698 menu.addMenu(Rotation_Menu)
701 Layout_Menu = QMenu(_(
"Layout"), self)
702 Layout_None = Layout_Menu.addAction(_(
"Reset Layout"))
703 Layout_None.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_NONE, clip_ids))
704 Layout_Menu.addSeparator()
705 Layout_Center = Layout_Menu.addAction(_(
"1/4 Size - Center"))
706 Layout_Center.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_CENTER, clip_ids))
707 Layout_Top_Left = Layout_Menu.addAction(_(
"1/4 Size - Top Left"))
708 Layout_Top_Left.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_TOP_LEFT, clip_ids))
709 Layout_Top_Right = Layout_Menu.addAction(_(
"1/4 Size - Top Right"))
710 Layout_Top_Right.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_TOP_RIGHT, clip_ids))
711 Layout_Bottom_Left = Layout_Menu.addAction(_(
"1/4 Size - Bottom Left"))
712 Layout_Bottom_Left.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_BOTTOM_LEFT, clip_ids))
713 Layout_Bottom_Right = Layout_Menu.addAction(_(
"1/4 Size - Bottom Right"))
714 Layout_Bottom_Right.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_BOTTOM_RIGHT, clip_ids))
715 Layout_Menu.addSeparator()
716 Layout_Bottom_All_With_Aspect = Layout_Menu.addAction(_(
"Show All (Maintain Ratio)"))
717 Layout_Bottom_All_With_Aspect.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_ALL_WITH_ASPECT, clip_ids))
718 Layout_Bottom_All_Without_Aspect = Layout_Menu.addAction(_(
"Show All (Distort)"))
719 Layout_Bottom_All_Without_Aspect.triggered.connect(partial(self.
Layout_Triggered, MENU_LAYOUT_ALL_WITHOUT_ASPECT, clip_ids))
720 menu.addMenu(Layout_Menu)
723 Time_Menu = QMenu(_(
"Time"), self)
724 Time_None = Time_Menu.addAction(_(
"Reset Time"))
725 Time_None.triggered.connect(partial(self.
Time_Triggered, MENU_TIME_NONE, clip_ids,
'1X'))
726 Time_Menu.addSeparator()
727 for speed, speed_values
in [(
"Normal", [
'1X']), (
"Fast", [
'2X',
'4X',
'8X',
'16X']), (
"Slow", [
'1/2X',
'1/4X',
'1/8X',
'1/16X'])]:
728 Speed_Menu = QMenu(_(speed), self)
730 for direction, direction_value
in [(
"Forward", MENU_TIME_FORWARD), (
"Backward", MENU_TIME_BACKWARD)]:
731 Direction_Menu = QMenu(_(direction), self)
733 for actual_speed
in speed_values:
735 Time_Option = Direction_Menu.addAction(_(actual_speed))
736 Time_Option.triggered.connect(partial(self.
Time_Triggered, direction_value, clip_ids, actual_speed))
739 Speed_Menu.addMenu(Direction_Menu)
741 Time_Menu.addMenu(Speed_Menu)
744 Time_Menu.addSeparator()
745 for freeze_type, trigger_type
in [(_(
"Freeze"), MENU_TIME_FREEZE), (_(
"Freeze && Zoom"), MENU_TIME_FREEZE_ZOOM)]:
746 Freeze_Menu = QMenu(freeze_type, self)
748 for freeze_seconds
in [2, 4, 6, 8, 10, 20, 30]:
750 Time_Option = Freeze_Menu.addAction(_(
'{} seconds').format(freeze_seconds))
751 Time_Option.triggered.connect(partial(self.
Time_Triggered, trigger_type, clip_ids, freeze_seconds, playhead_position))
754 Time_Menu.addMenu(Freeze_Menu)
757 menu.addMenu(Time_Menu)
760 Volume_Menu = QMenu(_(
"Volume"), self)
761 Volume_None = Volume_Menu.addAction(_(
"Reset Volume"))
762 Volume_None.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_NONE, clip_ids))
763 Volume_Menu.addSeparator()
764 for position
in [
"Start of Clip",
"End of Clip",
"Entire Clip"]:
765 Position_Menu = QMenu(_(position), self)
767 if position ==
"Start of Clip":
768 Fade_In_Fast = Position_Menu.addAction(_(
"Fade In (Fast)"))
769 Fade_In_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_FAST, clip_ids, position))
770 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Slow)"))
771 Fade_In_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_SLOW, clip_ids, position))
773 elif position ==
"End of Clip":
774 Fade_Out_Fast = Position_Menu.addAction(_(
"Fade Out (Fast)"))
775 Fade_Out_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_FAST, clip_ids, position))
776 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Slow)"))
777 Fade_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_SLOW, clip_ids, position))
780 Fade_In_Out_Fast = Position_Menu.addAction(_(
"Fade In and Out (Fast)"))
781 Fade_In_Out_Fast.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_OUT_FAST, clip_ids, position))
782 Fade_In_Out_Slow = Position_Menu.addAction(_(
"Fade In and Out (Slow)"))
783 Fade_In_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_OUT_SLOW, clip_ids, position))
784 Position_Menu.addSeparator()
785 Fade_In_Slow = Position_Menu.addAction(_(
"Fade In (Entire Clip)"))
786 Fade_In_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_IN_SLOW, clip_ids, position))
787 Fade_Out_Slow = Position_Menu.addAction(_(
"Fade Out (Entire Clip)"))
788 Fade_Out_Slow.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_FADE_OUT_SLOW, clip_ids, position))
791 Position_Menu.addSeparator()
792 Volume_100 = Position_Menu.addAction(_(
"Level 100%"))
793 Volume_100.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_100, clip_ids, position))
794 Volume_90 = Position_Menu.addAction(_(
"Level 90%"))
795 Volume_90.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_90, clip_ids, position))
796 Volume_80 = Position_Menu.addAction(_(
"Level 80%"))
797 Volume_80.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_80, clip_ids, position))
798 Volume_70 = Position_Menu.addAction(_(
"Level 70%"))
799 Volume_70.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_70, clip_ids, position))
800 Volume_60 = Position_Menu.addAction(_(
"Level 60%"))
801 Volume_60.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_60, clip_ids, position))
802 Volume_50 = Position_Menu.addAction(_(
"Level 50%"))
803 Volume_50.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_50, clip_ids, position))
804 Volume_40 = Position_Menu.addAction(_(
"Level 40%"))
805 Volume_40.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_40, clip_ids, position))
806 Volume_30 = Position_Menu.addAction(_(
"Level 30%"))
807 Volume_30.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_30, clip_ids, position))
808 Volume_20 = Position_Menu.addAction(_(
"Level 20%"))
809 Volume_20.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_20, clip_ids, position))
810 Volume_10 = Position_Menu.addAction(_(
"Level 10%"))
811 Volume_10.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_10, clip_ids, position))
812 Volume_0 = Position_Menu.addAction(_(
"Level 0%"))
813 Volume_0.triggered.connect(partial(self.
Volume_Triggered, MENU_VOLUME_LEVEL_0, clip_ids, position))
815 Volume_Menu.addMenu(Position_Menu)
816 menu.addMenu(Volume_Menu)
819 Split_Audio_Channels_Menu = QMenu(_(
"Separate Audio"), self)
820 Split_Single_Clip = Split_Audio_Channels_Menu.addAction(_(
"Single Clip (all channels)"))
821 Split_Single_Clip.triggered.connect(partial(self.
Split_Audio_Triggered, MENU_SPLIT_AUDIO_SINGLE, clip_ids))
822 Split_Multiple_Clips = Split_Audio_Channels_Menu.addAction(_(
"Multiple Clips (each channel)"))
823 Split_Multiple_Clips.triggered.connect(partial(self.
Split_Audio_Triggered, MENU_SPLIT_AUDIO_MULTIPLE, clip_ids))
824 menu.addMenu(Split_Audio_Channels_Menu)
828 start_of_clip = float(clip.data[
"start"])
829 end_of_clip = float(clip.data[
"end"])
830 position_of_clip = float(clip.data[
"position"])
831 if playhead_position >= position_of_clip
and playhead_position <= (position_of_clip + (end_of_clip - start_of_clip)):
833 Slice_Menu = QMenu(_(
"Slice"), self)
834 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
835 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, [clip_id], [], playhead_position))
836 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
837 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, [clip_id], [], playhead_position))
838 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
839 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, [clip_id], [], playhead_position))
840 menu.addMenu(Slice_Menu)
843 Transform_Action = self.window.actionTransform
844 Transform_Action.triggered.connect(partial(self.
Transform_Triggered, MENU_TRANSFORM, clip_ids))
845 menu.addAction(Transform_Action)
849 Waveform_Menu = QMenu(_(
"Display"), self)
850 ShowWaveform = Waveform_Menu.addAction(_(
"Show Waveform"))
852 HideWaveform = Waveform_Menu.addAction(_(
"Show Thumbnail"))
854 menu.addMenu(Waveform_Menu)
857 menu.addAction(self.window.actionProperties)
861 menu.addAction(self.window.actionRemoveClip)
864 return menu.popup(QCursor.pos())
867 print(
"Transform_Triggered")
872 get_app().window.TransformSignal.emit(clip_ids[0])
875 get_app().window.TransformSignal.emit(
"")
882 for clip_id
in clip_ids:
885 clip = Clip.get(id=clip_id)
890 file_path = clip.data[
"reader"][
"path"]
894 clips =
get_app().window.timeline_sync.timeline.Clips()
895 for clip_object
in clips:
896 if clip_object.Id() == clip_id:
899 if c
and c.Reader()
and not c.Reader().info.has_single_image:
901 channel_filter = c.channel_filter.GetInt(1)
904 get_app().setOverrideCursor(QCursor(Qt.WaitCursor))
907 channel_filter = channel_filter
915 for clip_id
in clip_ids:
918 clip = Clip.get(id=clip_id)
922 cmd = JS_SCOPE_SELECTOR +
".hideAudioData('" + clip_id +
"');"
923 self.page().mainFrame().evaluateJavaScript(cmd)
928 log.info(
"Waveform_Ready for clip ID: %s" % (clip_id))
931 serialized_audio_data = json.dumps(audio_data)
937 cmd = JS_SCOPE_SELECTOR +
".setAudioData('" + clip_id +
"', " + serialized_audio_data +
");"
938 self.page().mainFrame().evaluateJavaScript(cmd)
941 get_app().restoreOverrideCursor()
944 self.redraw_audio_timer.start()
950 cmd = JS_SCOPE_SELECTOR +
".updateThumbnail('" + clip_id +
"');"
951 self.page().mainFrame().evaluateJavaScript(cmd)
956 log.info(
"Split_Audio_Triggered")
962 for clip_id
in clip_ids:
965 clip = Clip.get(id=clip_id)
971 all_tracks =
get_app().project.get([
"layers"])
974 p = openshot.Point(1, -1.0, openshot.CONSTANT)
975 p_object = json.loads(p.Json())
976 clip.data[
"has_audio"] = {
"Points" : [p_object]}
985 clip_title = clip.data[
"title"]
987 if action == MENU_SPLIT_AUDIO_SINGLE:
989 p = openshot.Point(1, -1.0, openshot.CONSTANT)
990 p_object = json.loads(p.Json())
991 clip.data[
"channel_filter"] = {
"Points" : [p_object]}
994 p = openshot.Point(1, 0.0, openshot.CONSTANT)
995 p_object = json.loads(p.Json())
996 clip.data[
"has_video"] = {
"Points" : [p_object]}
999 next_track_number = clip.data[
'layer']
1001 for track
in reversed(sorted(all_tracks, key=itemgetter(
'number'))):
1003 next_track_number = track.get(
"number")
1005 if track.get(
"number") == clip.data[
'layer']:
1010 clip.data[
'layer'] = next_track_number
1013 channel_label = _(
"(all channels)")
1014 clip.data[
"title"] = clip_title +
" " + channel_label
1019 log.info(
"Generate waveform for split audio track clip id: %s" % clip.id)
1022 if action == MENU_SPLIT_AUDIO_MULTIPLE:
1024 channels = int(clip.data[
"reader"][
"channels"])
1027 for channel
in range(0, channels):
1028 log.info(
"Adding clip for channel %s" % channel)
1031 p = openshot.Point(1, channel, openshot.CONSTANT)
1032 p_object = json.loads(p.Json())
1033 clip.data[
"channel_filter"] = {
"Points" : [p_object]}
1036 p = openshot.Point(1, 0.0, openshot.CONSTANT)
1037 p_object = json.loads(p.Json())
1038 clip.data[
"has_video"] = {
"Points" : [p_object]}
1041 next_track_number = clip.data[
'layer']
1043 for track
in reversed(sorted(all_tracks, key=itemgetter(
'number'))):
1045 next_track_number = track.get(
"number")
1047 if track.get(
"number") == clip.data[
'layer']:
1052 clip.data[
'layer'] = max(next_track_number, 0)
1055 channel_label = _(
"(channel %s)") % (channel + 1)
1056 clip.data[
"title"] = clip_title +
" " + channel_label
1062 log.info(
"Generate waveform for split audio track clip id: %s" % clip.id)
1067 clip.type =
'insert'
1070 for clip_id
in clip_ids:
1073 clip = Clip.get(id=clip_id)
1079 p = openshot.Point(1, 0.0, openshot.CONSTANT)
1080 p_object = json.loads(p.Json())
1081 clip.data[
"has_audio"] = {
"Points" : [p_object]}
1084 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1093 for clip_id
in clip_ids:
1096 clip = Clip.get(id=clip_id)
1101 new_gravity = openshot.GRAVITY_CENTER
1102 if action == MENU_LAYOUT_CENTER:
1103 new_gravity = openshot.GRAVITY_CENTER
1104 if action == MENU_LAYOUT_TOP_LEFT:
1105 new_gravity = openshot.GRAVITY_TOP_LEFT
1106 elif action == MENU_LAYOUT_TOP_RIGHT:
1107 new_gravity = openshot.GRAVITY_TOP_RIGHT
1108 elif action == MENU_LAYOUT_BOTTOM_LEFT:
1109 new_gravity = openshot.GRAVITY_BOTTOM_LEFT
1110 elif action == MENU_LAYOUT_BOTTOM_RIGHT:
1111 new_gravity = openshot.GRAVITY_BOTTOM_RIGHT
1113 if action == MENU_LAYOUT_NONE:
1115 clip.data[
"scale"] = openshot.SCALE_FIT
1116 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1119 p = openshot.Point(1, 1.0, openshot.BEZIER)
1120 p_object = json.loads(p.Json())
1121 clip.data[
"scale_x"] = {
"Points" : [p_object]}
1122 clip.data[
"scale_y"] = {
"Points" : [p_object]}
1125 p = openshot.Point(1, 0.0, openshot.BEZIER)
1126 p_object = json.loads(p.Json())
1127 clip.data[
"location_x"] = {
"Points" : [p_object]}
1128 clip.data[
"location_y"] = {
"Points" : [p_object]}
1130 if action == MENU_LAYOUT_CENTER
or \
1131 action == MENU_LAYOUT_TOP_LEFT
or \
1132 action == MENU_LAYOUT_TOP_RIGHT
or \
1133 action == MENU_LAYOUT_BOTTOM_LEFT
or \
1134 action == MENU_LAYOUT_BOTTOM_RIGHT:
1136 clip.data[
"scale"] = openshot.SCALE_FIT
1137 clip.data[
"gravity"] = new_gravity
1140 p = openshot.Point(1, 0.5, openshot.BEZIER)
1141 p_object = json.loads(p.Json())
1142 clip.data[
"scale_x"] = {
"Points" : [p_object]}
1143 clip.data[
"scale_y"] = {
"Points" : [p_object]}
1146 p = openshot.Point(1, 0.0, openshot.BEZIER)
1147 p_object = json.loads(p.Json())
1148 clip.data[
"location_x"] = {
"Points" : [p_object]}
1149 clip.data[
"location_y"] = {
"Points" : [p_object]}
1152 if action == MENU_LAYOUT_ALL_WITH_ASPECT:
1156 elif action == MENU_LAYOUT_ALL_WITHOUT_ASPECT:
1162 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1170 for clip_id
in clip_ids:
1173 clip = Clip.get(id=clip_id)
1179 fps =
get_app().project.get([
"fps"])
1180 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1183 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1184 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1188 start_animation = start_of_clip
1189 end_animation = end_of_clip
1190 if position ==
"Start of Clip":
1191 start_animation = start_of_clip
1192 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1193 elif position ==
"End of Clip":
1194 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1195 end_animation = end_of_clip
1197 if action == MENU_ANIMATE_NONE:
1199 default_zoom = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1200 default_zoom_object = json.loads(default_zoom.Json())
1201 default_loc = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1202 default_loc_object = json.loads(default_loc.Json())
1203 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1204 clip.data[
"scale_x"] = {
"Points" : [default_zoom_object]}
1205 clip.data[
"scale_y"] = {
"Points" : [default_zoom_object]}
1206 clip.data[
"location_x"] = {
"Points" : [default_loc_object]}
1207 clip.data[
"location_y"] = {
"Points" : [default_loc_object]}
1209 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]:
1213 if action == MENU_ANIMATE_IN_50_100:
1215 elif action == MENU_ANIMATE_IN_75_100:
1217 elif action == MENU_ANIMATE_IN_100_150:
1219 elif action == MENU_ANIMATE_OUT_100_75:
1221 elif action == MENU_ANIMATE_OUT_100_50:
1223 elif action == MENU_ANIMATE_OUT_150_100:
1227 start = openshot.Point(start_animation, start_scale, openshot.BEZIER)
1228 start_object = json.loads(start.Json())
1229 end = openshot.Point(end_animation, end_scale, openshot.BEZIER)
1230 end_object = json.loads(end.Json())
1231 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1232 clip.data[
"scale_x"][
"Points"].append(start_object)
1233 clip.data[
"scale_x"][
"Points"].append(end_object)
1234 clip.data[
"scale_y"][
"Points"].append(start_object)
1235 clip.data[
"scale_y"][
"Points"].append(end_object)
1238 if action
in [MENU_ANIMATE_CENTER_TOP, MENU_ANIMATE_CENTER_LEFT, MENU_ANIMATE_CENTER_RIGHT, MENU_ANIMATE_CENTER_BOTTOM,
1239 MENU_ANIMATE_TOP_CENTER, MENU_ANIMATE_LEFT_CENTER, MENU_ANIMATE_RIGHT_CENTER, MENU_ANIMATE_BOTTOM_CENTER,
1240 MENU_ANIMATE_TOP_BOTTOM, MENU_ANIMATE_LEFT_RIGHT, MENU_ANIMATE_RIGHT_LEFT, MENU_ANIMATE_BOTTOM_TOP]:
1242 animate_start_x = 0.0
1244 animate_start_y = 0.0
1247 if action == MENU_ANIMATE_CENTER_TOP:
1248 animate_end_y = -1.0
1249 elif action == MENU_ANIMATE_CENTER_LEFT:
1250 animate_end_x = -1.0
1251 elif action == MENU_ANIMATE_CENTER_RIGHT:
1253 elif action == MENU_ANIMATE_CENTER_BOTTOM:
1257 elif action == MENU_ANIMATE_TOP_CENTER:
1258 animate_start_y = -1.0
1259 elif action == MENU_ANIMATE_LEFT_CENTER:
1260 animate_start_x = -1.0
1261 elif action == MENU_ANIMATE_RIGHT_CENTER:
1262 animate_start_x = 1.0
1263 elif action == MENU_ANIMATE_BOTTOM_CENTER:
1264 animate_start_y = 1.0
1267 elif action == MENU_ANIMATE_TOP_BOTTOM:
1268 animate_start_y = -1.0
1270 elif action == MENU_ANIMATE_LEFT_RIGHT:
1271 animate_start_x = -1.0
1273 elif action == MENU_ANIMATE_RIGHT_LEFT:
1274 animate_start_x = 1.0
1275 animate_end_x = -1.0
1276 elif action == MENU_ANIMATE_BOTTOM_TOP:
1277 animate_start_y = 1.0
1278 animate_end_y = -1.0
1281 start_x = openshot.Point(start_animation, animate_start_x, openshot.BEZIER)
1282 start_x_object = json.loads(start_x.Json())
1283 end_x = openshot.Point(end_animation, animate_end_x, openshot.BEZIER)
1284 end_x_object = json.loads(end_x.Json())
1285 start_y = openshot.Point(start_animation, animate_start_y, openshot.BEZIER)
1286 start_y_object = json.loads(start_y.Json())
1287 end_y = openshot.Point(end_animation, animate_end_y, openshot.BEZIER)
1288 end_y_object = json.loads(end_y.Json())
1289 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1290 clip.data[
"location_x"][
"Points"].append(start_x_object)
1291 clip.data[
"location_x"][
"Points"].append(end_x_object)
1292 clip.data[
"location_y"][
"Points"].append(start_y_object)
1293 clip.data[
"location_y"][
"Points"].append(end_y_object)
1295 if action == MENU_ANIMATE_RANDOM:
1297 animate_start_x = uniform(-0.5, 0.5)
1298 animate_end_x = uniform(-0.15, 0.15)
1299 animate_start_y = uniform(-0.5, 0.5)
1300 animate_end_y = uniform(-0.15, 0.15)
1303 start_scale = uniform(0.5, 1.5)
1304 end_scale = uniform(0.85, 1.15)
1307 start = openshot.Point(start_animation, start_scale, openshot.BEZIER)
1308 start_object = json.loads(start.Json())
1309 end = openshot.Point(end_animation, end_scale, openshot.BEZIER)
1310 end_object = json.loads(end.Json())
1311 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1312 clip.data[
"scale_x"][
"Points"].append(start_object)
1313 clip.data[
"scale_x"][
"Points"].append(end_object)
1314 clip.data[
"scale_y"][
"Points"].append(start_object)
1315 clip.data[
"scale_y"][
"Points"].append(end_object)
1318 start_x = openshot.Point(start_animation, animate_start_x, openshot.BEZIER)
1319 start_x_object = json.loads(start_x.Json())
1320 end_x = openshot.Point(end_animation, animate_end_x, openshot.BEZIER)
1321 end_x_object = json.loads(end_x.Json())
1322 start_y = openshot.Point(start_animation, animate_start_y, openshot.BEZIER)
1323 start_y_object = json.loads(start_y.Json())
1324 end_y = openshot.Point(end_animation, animate_end_y, openshot.BEZIER)
1325 end_y_object = json.loads(end_y.Json())
1326 clip.data[
"gravity"] = openshot.GRAVITY_CENTER
1327 clip.data[
"location_x"][
"Points"].append(start_x_object)
1328 clip.data[
"location_x"][
"Points"].append(end_x_object)
1329 clip.data[
"location_y"][
"Points"].append(start_y_object)
1330 clip.data[
"location_y"][
"Points"].append(end_y_object)
1333 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1345 for clip_id
in clip_ids:
1348 clip = Clip.get(id=clip_id)
1355 if action == MENU_COPY_CLIP
or action == MENU_COPY_ALL:
1357 elif action == MENU_COPY_KEYFRAMES_ALL:
1363 self.
copy_clipboard[clip_id][
'location_x'] = clip.data[
'location_x']
1364 self.
copy_clipboard[clip_id][
'location_y'] = clip.data[
'location_y']
1367 elif action == MENU_COPY_KEYFRAMES_ALPHA:
1369 elif action == MENU_COPY_KEYFRAMES_SCALE:
1373 elif action == MENU_COPY_KEYFRAMES_ROTATE:
1376 elif action == MENU_COPY_KEYFRAMES_LOCATION:
1378 self.
copy_clipboard[clip_id][
'location_x'] = clip.data[
'location_x']
1379 self.
copy_clipboard[clip_id][
'location_y'] = clip.data[
'location_y']
1380 elif action == MENU_COPY_KEYFRAMES_TIME:
1382 elif action == MENU_COPY_KEYFRAMES_VOLUME:
1384 elif action == MENU_COPY_EFFECTS:
1388 for tran_id
in tran_ids:
1391 tran = Transition.get(id=tran_id)
1398 if action == MENU_COPY_TRANSITION
or action == MENU_COPY_ALL:
1400 elif action == MENU_COPY_KEYFRAMES_ALL:
1403 elif action == MENU_COPY_KEYFRAMES_BRIGHTNESS:
1405 elif action == MENU_COPY_KEYFRAMES_CONTRAST:
1415 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
1416 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
1419 if len(clipboard_clip_ids) + len(clipboard_tran_ids):
1420 left_most_position = -1.0
1423 for clip_id
in clipboard_clip_ids:
1426 clip.data = self.copy_clipboard.get(clip_id, {})
1427 if clip.data[
'position'] < left_most_position
or left_most_position == -1.0:
1428 left_most_position = clip.data[
'position']
1429 if clip.data[
'layer'] > top_most_layer
or top_most_layer == -1.0:
1430 top_most_layer = clip.data[
'layer']
1432 for tran_id
in clipboard_tran_ids:
1435 tran.data = self.copy_transition_clipboard.get(tran_id, {})
1436 if tran.data[
'position'] < left_most_position
or left_most_position == -1.0:
1437 left_most_position = tran.data[
'position']
1438 if tran.data[
'layer'] > top_most_layer
or top_most_layer == -1.0:
1439 top_most_layer = tran.data[
'layer']
1443 layer_id = top_most_layer
1446 position_diff = position - left_most_position
1447 layer_diff = layer_id - top_most_layer
1450 for clip_id
in clipboard_clip_ids:
1453 clip.data = self.copy_clipboard.get(clip_id, {})
1456 clip.type =
'insert'
1460 clip.data[
'position'] += position_diff
1461 clip.data[
'layer'] += layer_diff
1467 for tran_id
in clipboard_tran_ids:
1470 tran.data = self.copy_transition_clipboard.get(tran_id, {})
1473 tran.type =
'insert'
1477 tran.data[
'position'] += position_diff
1478 tran.data[
'layer'] += layer_diff
1485 for clip_id
in clip_ids:
1488 clip = Clip.get(id=clip_id)
1504 for tran_id
in tran_ids:
1507 tran = Transition.get(id=tran_id)
1524 log.info(
"Nudging clip(s) and/or transition(s)")
1529 fps =
get_app().project.get([
"fps"])
1530 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1531 nudgeDistance = float(action) / float(fps_float)
1532 nudgeDistance /= 2.0
1533 if abs(nudgeDistance) < 0.01:
1534 nudgeDistance = 0.01 * action
1535 log.info(
"Nudging by %s sec" % nudgeDistance)
1538 for clip_id
in clip_ids:
1540 clip = Clip.get(id=clip_id)
1545 position = float(clip.data[
"position"])
1546 start_of_clip = float(clip.data[
"start"])
1547 end_of_clip = float(clip.data[
"end"])
1549 if position < left_edge
or left_edge == -1.0:
1550 left_edge = position
1551 if position + (end_of_clip - start_of_clip) > right_edge
or right_edge == -1.0:
1552 right_edge = position + (end_of_clip - start_of_clip)
1555 if left_edge + nudgeDistance < 0.0:
1556 log.info(
"Cannot nudge beyond start of timeline")
1560 for tran_id
in tran_ids:
1562 tran = Transition.get(id=tran_id)
1567 position = float(tran.data[
"position"])
1568 start_of_tran = float(tran.data[
"start"])
1569 end_of_tran = float(tran.data[
"end"])
1571 if position < left_edge
or left_edge == -1.0:
1572 left_edge = position
1573 if position + (end_of_tran - start_of_tran) > right_edge
or right_edge == -1.0:
1574 right_edge = position + (end_of_tran - start_of_tran)
1577 if left_edge + nudgeDistance < 0.0:
1578 log.info(
"Cannot nudge beyond start of timeline")
1582 for clip_id
in clip_ids:
1584 clip = Clip.get(id=clip_id)
1590 clip.data[
'position'] += nudgeDistance
1593 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1596 for tran_id
in tran_ids:
1598 tran = Transition.get(id=tran_id)
1604 tran.data[
'position'] += nudgeDistance
1614 prop_name =
"position"
1619 for clip_id
in clip_ids:
1621 clip = Clip.get(id=clip_id)
1626 position = float(clip.data[
"position"])
1627 start_of_clip = float(clip.data[
"start"])
1628 end_of_clip = float(clip.data[
"end"])
1630 if position < left_edge
or left_edge == -1.0:
1631 left_edge = position
1632 if position + (end_of_clip - start_of_clip) > right_edge
or right_edge == -1.0:
1633 right_edge = position + (end_of_clip - start_of_clip)
1636 for tran_id
in tran_ids:
1638 tran = Transition.get(id=tran_id)
1643 position = float(tran.data[
"position"])
1644 start_of_tran = float(tran.data[
"start"])
1645 end_of_tran = float(tran.data[
"end"])
1647 if position < left_edge
or left_edge == -1.0:
1648 left_edge = position
1649 if position + (end_of_tran - start_of_tran) > right_edge
or right_edge == -1.0:
1650 right_edge = position + (end_of_tran - start_of_tran)
1654 for clip_id
in clip_ids:
1656 clip = Clip.get(id=clip_id)
1661 if action == MENU_ALIGN_LEFT:
1662 clip.data[
'position'] = left_edge
1663 elif action == MENU_ALIGN_RIGHT:
1664 position = float(clip.data[
"position"])
1665 start_of_clip = float(clip.data[
"start"])
1666 end_of_clip = float(clip.data[
"end"])
1667 right_clip_edge = position + (end_of_clip - start_of_clip)
1669 clip.data[
'position'] = position + (right_edge - right_clip_edge)
1672 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1675 for tran_id
in tran_ids:
1677 tran = Transition.get(id=tran_id)
1682 if action == MENU_ALIGN_LEFT:
1683 tran.data[
'position'] = left_edge
1684 elif action == MENU_ALIGN_RIGHT:
1685 position = float(tran.data[
"position"])
1686 start_of_tran = float(tran.data[
"start"])
1687 end_of_tran = float(tran.data[
"end"])
1688 right_tran_edge = position + (end_of_tran - start_of_tran)
1690 tran.data[
'position'] = position + (right_edge - right_tran_edge)
1702 fps =
get_app().project.get([
"fps"])
1703 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1706 for clip_id
in clip_ids:
1709 clip = Clip.get(id=clip_id)
1714 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1715 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1719 start_animation = start_of_clip
1720 end_animation = end_of_clip
1721 if position ==
"Start of Clip" and action
in [MENU_FADE_IN_FAST, MENU_FADE_OUT_FAST]:
1722 start_animation = start_of_clip
1723 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1724 elif position ==
"Start of Clip" and action
in [MENU_FADE_IN_SLOW, MENU_FADE_OUT_SLOW]:
1725 start_animation = start_of_clip
1726 end_animation = min(start_of_clip + (3.0 * fps_float), end_of_clip)
1727 elif position ==
"End of Clip" and action
in [MENU_FADE_IN_FAST, MENU_FADE_OUT_FAST]:
1728 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1729 end_animation = end_of_clip
1730 elif position ==
"End of Clip" and action
in [MENU_FADE_IN_SLOW, MENU_FADE_OUT_SLOW]:
1731 start_animation = max(1.0, end_of_clip - (3.0 * fps_float))
1732 end_animation = end_of_clip
1735 if position ==
"Entire Clip" and action == MENU_FADE_IN_OUT_FAST:
1737 self.
Fade_Triggered(MENU_FADE_IN_FAST, clip_ids,
"Start of Clip")
1740 elif position ==
"Entire Clip" and action == MENU_FADE_IN_OUT_SLOW:
1742 self.
Fade_Triggered(MENU_FADE_IN_SLOW, clip_ids,
"Start of Clip")
1746 if action == MENU_FADE_NONE:
1748 p = openshot.Point(1, 1.0, openshot.BEZIER)
1749 p_object = json.loads(p.Json())
1750 clip.data[prop_name] = {
"Points" : [p_object]}
1752 if action
in [MENU_FADE_IN_FAST, MENU_FADE_IN_SLOW]:
1754 start = openshot.Point(start_animation, 0.0, openshot.BEZIER)
1755 start_object = json.loads(start.Json())
1756 end = openshot.Point(end_animation, 1.0, openshot.BEZIER)
1757 end_object = json.loads(end.Json())
1758 clip.data[prop_name][
"Points"].append(start_object)
1759 clip.data[prop_name][
"Points"].append(end_object)
1761 if action
in [MENU_FADE_OUT_FAST, MENU_FADE_OUT_SLOW]:
1763 start = openshot.Point(start_animation, 1.0, openshot.BEZIER)
1764 start_object = json.loads(start.Json())
1765 end = openshot.Point(end_animation, 0.0, openshot.BEZIER)
1766 end_object = json.loads(end.Json())
1767 clip.data[prop_name][
"Points"].append(start_object)
1768 clip.data[prop_name][
"Points"].append(end_object)
1771 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1773 @pyqtSlot(str, str, float)
1779 slice_mode = MENU_SLICE_KEEP_BOTH
1780 if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
1781 slice_mode = MENU_SLICE_KEEP_RIGHT
1782 elif int(QCoreApplication.instance().keyboardModifiers() & Qt.ShiftModifier) > 0:
1783 slice_mode = MENU_SLICE_KEEP_LEFT
1787 QTimer.singleShot(0, partial(self.
Slice_Triggered, slice_mode, [clip_id], [], cursor_position))
1790 QTimer.singleShot(0, partial(self.
Slice_Triggered, slice_mode, [], [trans_id], cursor_position))
1796 fps =
get_app().project.get([
"fps"])
1797 fps_num = float(fps[
"num"])
1798 fps_den = float(fps[
"den"])
1799 fps_float = fps_num / fps_den
1800 frame_duration = fps_den / fps_num
1804 playhead_position = float(round((playhead_position * fps_num) / fps_den ) * fps_den ) / fps_num
1807 for clip_id
in clip_ids:
1810 clip = Clip.get(id=clip_id)
1818 if action == MENU_SLICE_KEEP_LEFT
or action == MENU_SLICE_KEEP_BOTH:
1820 position_of_clip = float(clip.data[
"position"])
1821 start_of_clip = float(clip.data[
"start"])
1824 clip.data[
"end"] = start_of_clip + (playhead_position - position_of_clip)
1826 elif action == MENU_SLICE_KEEP_RIGHT:
1828 position_of_clip = float(clip.data[
"position"])
1829 start_of_clip = float(clip.data[
"start"])
1832 clip.data[
"position"] = playhead_position
1833 clip.data[
"start"] = start_of_clip + (playhead_position - position_of_clip)
1838 if action == MENU_SLICE_KEEP_BOTH:
1841 right_clip = Clip.get(id=clip_id)
1847 right_clip.id =
None
1848 right_clip.type =
'insert'
1849 right_clip.data.pop(
'id')
1850 right_clip.key.pop(1)
1853 right_clip.data[
"position"] = (round(float(playhead_position) * fps_float) + 1) / fps_float
1854 right_clip.data[
"start"] = (round(float(clip.data[
"end"]) * fps_float) + 2) / fps_float
1863 self.
update_clip_data(right_clip.data, only_basic_props=
False, ignore_reader=
True)
1867 self.
waveform_cache[right_clip.id] = self.waveform_cache.get(clip_id,
'[]')
1870 cmd = JS_SCOPE_SELECTOR +
".setAudioData('" + right_clip.id +
"', " + self.waveform_cache.get(right_clip.id) +
");"
1871 self.page().mainFrame().evaluateJavaScript(cmd)
1874 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
1877 self.redraw_audio_timer.start()
1880 for trans_id
in trans_ids:
1882 trans = Transition.get(id=trans_id)
1887 if action == MENU_SLICE_KEEP_LEFT
or action == MENU_SLICE_KEEP_BOTH:
1889 position_of_tran = float(trans.data[
"position"])
1892 trans.data[
"end"] = playhead_position - position_of_tran
1894 elif action == MENU_SLICE_KEEP_RIGHT:
1896 position_of_tran = float(trans.data[
"position"])
1897 end_of_tran = float(trans.data[
"end"])
1900 trans.data[
"position"] = playhead_position
1901 trans.data[
"end"] = end_of_tran - (playhead_position - position_of_tran)
1903 if action == MENU_SLICE_KEEP_BOTH:
1906 right_tran = Transition.get(id=trans_id)
1912 right_tran.id =
None
1913 right_tran.type =
'insert'
1914 right_tran.data.pop(
'id')
1915 right_tran.key.pop(1)
1918 position_of_tran = float(right_tran.data[
"position"])
1919 end_of_tran = float(right_tran.data[
"end"])
1922 right_tran.data[
"position"] = playhead_position + frame_duration
1923 right_tran.data[
"end"] = end_of_tran - (playhead_position - position_of_tran) + frame_duration
1938 prop_name =
"volume"
1941 fps =
get_app().project.get([
"fps"])
1942 fps_float = float(fps[
"num"]) / float(fps[
"den"])
1945 for clip_id
in clip_ids:
1948 clip = Clip.get(id=clip_id)
1953 start_of_clip = round(float(clip.data[
"start"]) * fps_float) + 1
1954 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
1958 start_animation = start_of_clip
1959 end_animation = end_of_clip
1960 if position ==
"Start of Clip" and action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_OUT_FAST]:
1961 start_animation = start_of_clip
1962 end_animation = min(start_of_clip + (1.0 * fps_float), end_of_clip)
1963 elif position ==
"Start of Clip" and action
in [MENU_VOLUME_FADE_IN_SLOW, MENU_VOLUME_FADE_OUT_SLOW]:
1964 start_animation = start_of_clip
1965 end_animation = min(start_of_clip + (3.0 * fps_float), end_of_clip)
1966 elif position ==
"End of Clip" and action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_OUT_FAST]:
1967 start_animation = max(1.0, end_of_clip - (1.0 * fps_float))
1968 end_animation = end_of_clip
1969 elif position ==
"End of Clip" and action
in [MENU_VOLUME_FADE_IN_SLOW, MENU_VOLUME_FADE_OUT_SLOW]:
1970 start_animation = max(1.0, end_of_clip - (3.0 * fps_float))
1971 end_animation = end_of_clip
1972 elif position ==
"Start of Clip":
1974 start_animation = start_of_clip
1975 end_animation = start_of_clip
1976 elif position ==
"End of Clip":
1978 start_animation = end_of_clip
1979 end_animation = end_of_clip
1982 if position ==
"Entire Clip" and action == MENU_VOLUME_FADE_IN_OUT_FAST:
1987 elif position ==
"Entire Clip" and action == MENU_VOLUME_FADE_IN_OUT_SLOW:
1993 if action == MENU_VOLUME_NONE:
1995 p = openshot.Point(1, 1.0, openshot.BEZIER)
1996 p_object = json.loads(p.Json())
1997 clip.data[prop_name] = {
"Points" : [p_object]}
1999 if action
in [MENU_VOLUME_FADE_IN_FAST, MENU_VOLUME_FADE_IN_SLOW]:
2001 start = openshot.Point(start_animation, 0.0, openshot.BEZIER)
2002 start_object = json.loads(start.Json())
2003 end = openshot.Point(end_animation, 1.0, openshot.BEZIER)
2004 end_object = json.loads(end.Json())
2005 clip.data[prop_name][
"Points"].append(start_object)
2006 clip.data[prop_name][
"Points"].append(end_object)
2008 if action
in [MENU_VOLUME_FADE_OUT_FAST, MENU_VOLUME_FADE_OUT_SLOW]:
2010 start = openshot.Point(start_animation, 1.0, openshot.BEZIER)
2011 start_object = json.loads(start.Json())
2012 end = openshot.Point(end_animation, 0.0, openshot.BEZIER)
2013 end_object = json.loads(end.Json())
2014 clip.data[prop_name][
"Points"].append(start_object)
2015 clip.data[prop_name][
"Points"].append(end_object)
2017 if action
in [MENU_VOLUME_LEVEL_100, MENU_VOLUME_LEVEL_90, MENU_VOLUME_LEVEL_80, MENU_VOLUME_LEVEL_70,
2018 MENU_VOLUME_LEVEL_60, MENU_VOLUME_LEVEL_50, MENU_VOLUME_LEVEL_40, MENU_VOLUME_LEVEL_30,
2019 MENU_VOLUME_LEVEL_20, MENU_VOLUME_LEVEL_10, MENU_VOLUME_LEVEL_0]:
2021 p = openshot.Point(start_animation, float(action) / 100.0, openshot.BEZIER)
2022 p_object = json.loads(p.Json())
2023 clip.data[prop_name][
"Points"].append(p_object)
2026 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2029 has_audio_data = bool(self.
eval_js(JS_SCOPE_SELECTOR +
".hasAudioData('" + clip.id +
"');"))
2038 prop_name =
"rotation"
2041 fps =
get_app().project.get([
"fps"])
2042 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2045 for clip_id
in clip_ids:
2048 clip = Clip.get(id=clip_id)
2053 if action == MENU_ROTATE_NONE:
2055 p = openshot.Point(1, 0.0, openshot.BEZIER)
2056 p_object = json.loads(p.Json())
2057 clip.data[prop_name] = {
"Points" : [p_object]}
2059 if action == MENU_ROTATE_90_RIGHT:
2061 p = openshot.Point(1, 90.0, openshot.BEZIER)
2062 p_object = json.loads(p.Json())
2063 clip.data[prop_name] = {
"Points" : [p_object]}
2065 if action == MENU_ROTATE_90_LEFT:
2067 p = openshot.Point(1, -90.0, openshot.BEZIER)
2068 p_object = json.loads(p.Json())
2069 clip.data[prop_name] = {
"Points" : [p_object]}
2071 if action == MENU_ROTATE_180_FLIP:
2073 p = openshot.Point(1, 180.0, openshot.BEZIER)
2074 p_object = json.loads(p.Json())
2075 clip.data[prop_name] = {
"Points" : [p_object]}
2078 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2087 fps =
get_app().project.get([
"fps"])
2088 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2091 for clip_id
in clip_ids:
2094 clip = Clip.get(id=clip_id)
2100 if "original_data" not in clip.data.keys():
2101 clip.data[
"original_data"] = {
"end": clip.data[
"end"],
2102 "duration": clip.data[
"duration"],
2103 "video_length": clip.data[
"reader"][
"video_length"]}
2109 if action
in [MENU_TIME_FREEZE, MENU_TIME_FREEZE_ZOOM]:
2111 freeze_seconds = float(speed)
2113 original_duration = clip.data[
"duration"]
2114 if "original_data" in clip.data.keys():
2115 original_duration = clip.data[
"original_data"][
"duration"]
2117 print(
'ORIGINAL DURATION: %s' % original_duration)
2121 clip.data[
"end"] = float(clip.data[
"end"]) + freeze_seconds
2122 clip.data[
"duration"] = float(clip.data[
"duration"]) + freeze_seconds
2123 clip.data[
"reader"][
"video_length"] = float(clip.data[
"reader"][
"video_length"]) + freeze_seconds
2126 freeze_length_frames = round(freeze_seconds * fps_float) + 1
2127 start_animation_seconds = float(clip.data[
"start"]) + (playhead_position - float(clip.data[
"position"]))
2128 start_animation_frames = round(start_animation_seconds * fps_float) + 1
2129 start_animation_frames_value = start_animation_frames
2130 end_animation_seconds = start_animation_seconds + freeze_seconds
2131 end_animation_frames = round(end_animation_seconds * fps_float) + 1
2132 end_of_clip_seconds = float(clip.data[
"duration"])
2133 end_of_clip_frames = round((end_of_clip_seconds) * fps_float) + 1
2134 end_of_clip_frames_value = round((original_duration) * fps_float) + 1
2137 start_volume_value = 1.0
2140 if len(clip.data[
"time"][
"Points"]) > 1:
2143 del clip.data[
"time"][
"Points"][-1]
2147 clips =
get_app().window.timeline_sync.timeline.Clips()
2148 for clip_object
in clips:
2149 if clip_object.Id() == clip_id:
2154 start_animation_frames_value = c.time.GetLong(start_animation_frames)
2157 if len(clip.data[
"volume"][
"Points"]) > 1:
2160 clips =
get_app().window.timeline_sync.timeline.Clips()
2161 for clip_object
in clips:
2162 if clip_object.Id() == clip_id:
2167 start_volume_value = c.volume.GetValue(start_animation_frames)
2170 p = openshot.Point(start_animation_frames, start_animation_frames_value, openshot.LINEAR)
2171 p_object = json.loads(p.Json())
2172 clip.data[prop_name][
"Points"].append(p_object)
2173 p1 = openshot.Point(end_animation_frames, start_animation_frames_value, openshot.LINEAR)
2174 p1_object = json.loads(p1.Json())
2175 clip.data[prop_name][
"Points"].append(p1_object)
2176 p2 = openshot.Point(end_of_clip_frames, end_of_clip_frames_value, openshot.LINEAR)
2177 p2_object = json.loads(p2.Json())
2178 clip.data[prop_name][
"Points"].append(p2_object)
2181 p = openshot.Point(start_animation_frames - 1, start_volume_value, openshot.LINEAR)
2182 p_object = json.loads(p.Json())
2183 clip.data[
'volume'][
"Points"].append(p_object)
2184 p = openshot.Point(start_animation_frames, 0.0, openshot.LINEAR)
2185 p_object = json.loads(p.Json())
2186 clip.data[
'volume'][
"Points"].append(p_object)
2187 p2 = openshot.Point(end_animation_frames - 1, 0.0, openshot.LINEAR)
2188 p2_object = json.loads(p2.Json())
2189 clip.data[
'volume'][
"Points"].append(p2_object)
2190 p3 = openshot.Point(end_animation_frames, start_volume_value, openshot.LINEAR)
2191 p3_object = json.loads(p3.Json())
2192 clip.data[
'volume'][
"Points"].append(p3_object)
2195 if action == MENU_TIME_FREEZE_ZOOM:
2196 p = openshot.Point(start_animation_frames, 1.0, openshot.BEZIER)
2197 p_object = json.loads(p.Json())
2198 clip.data[
'scale_x'][
"Points"].append(p_object)
2199 p = openshot.Point(start_animation_frames, 1.0, openshot.BEZIER)
2200 p_object = json.loads(p.Json())
2201 clip.data[
'scale_y'][
"Points"].append(p_object)
2203 diff_halfed = (end_animation_frames - start_animation_frames) / 2.0
2204 p1 = openshot.Point(start_animation_frames + diff_halfed, 1.05, openshot.BEZIER)
2205 p1_object = json.loads(p1.Json())
2206 clip.data[
'scale_x'][
"Points"].append(p1_object)
2207 p1 = openshot.Point(start_animation_frames + diff_halfed, 1.05, openshot.BEZIER)
2208 p1_object = json.loads(p1.Json())
2209 clip.data[
'scale_y'][
"Points"].append(p1_object)
2211 p1 = openshot.Point(end_animation_frames, 1.0, openshot.BEZIER)
2212 p1_object = json.loads(p1.Json())
2213 clip.data[
'scale_x'][
"Points"].append(p1_object)
2214 p1 = openshot.Point(end_animation_frames, 1.0, openshot.BEZIER)
2215 p1_object = json.loads(p1.Json())
2216 clip.data[
'scale_y'][
"Points"].append(p1_object)
2221 speed_label = speed.replace(
'X',
'')
2222 speed_parts = speed_label.split(
'/')
2224 if len(speed_parts) == 2:
2225 speed_factor = float(speed_parts[0]) / float(speed_parts[1])
2226 even_multiple = int(speed_parts[1])
2228 speed_factor = float(speed_label)
2229 even_multiple = int(speed_factor)
2232 p = openshot.Point(start_animation, 0.0, openshot.LINEAR)
2233 p_object = json.loads(p.Json())
2234 clip.data[prop_name] = {
"Points" : [p_object]}
2237 if "original_data" in clip.data.keys():
2238 clip.data[
"end"] = clip.data[
"original_data"][
"end"]
2239 clip.data[
"duration"] = clip.data[
"original_data"][
"duration"]
2240 clip.data[
"reader"][
"video_length"] = clip.data[
"original_data"][
"video_length"]
2241 clip.data.pop(
"original_data")
2244 end_of_clip = round(float(clip.data[
"end"]) * fps_float) + 1
2247 start_animation = round(float(clip.data[
"start"]) * fps_float) + 1
2248 duration_animation = self.
round_to_multiple(end_of_clip - start_animation, even_multiple)
2249 end_animation = start_animation + duration_animation
2251 if action == MENU_TIME_FORWARD:
2253 start = openshot.Point(start_animation, start_animation, openshot.LINEAR)
2254 start_object = json.loads(start.Json())
2255 clip.data[prop_name] = {
"Points" : [start_object]}
2256 end = openshot.Point(start_animation + (duration_animation / speed_factor), end_animation, openshot.LINEAR)
2257 end_object = json.loads(end.Json())
2258 clip.data[prop_name][
"Points"].append(end_object)
2261 clip.data[
"end"] = (start_animation + (duration_animation / speed_factor)) / fps_float
2262 clip.data[
"duration"] = self.
round_to_multiple(clip.data[
"duration"] / speed_factor, even_multiple)
2263 clip.data[
"reader"][
"video_length"] = str(self.
round_to_multiple(float(clip.data[
"reader"][
"video_length"]) / speed_factor, even_multiple))
2265 if action == MENU_TIME_BACKWARD:
2267 start = openshot.Point(start_animation, end_animation, openshot.LINEAR)
2268 start_object = json.loads(start.Json())
2269 clip.data[prop_name] = {
"Points" : [start_object]}
2270 end = openshot.Point(start_animation + (duration_animation / speed_factor), start_animation, openshot.LINEAR)
2271 end_object = json.loads(end.Json())
2272 clip.data[prop_name][
"Points"].append(end_object)
2275 clip.data[
"end"] = (start_animation + (duration_animation / speed_factor)) / fps_float
2276 clip.data[
"duration"] = self.
round_to_multiple(clip.data[
"duration"] / speed_factor, even_multiple)
2277 clip.data[
"reader"][
"video_length"] = str(self.
round_to_multiple(float(clip.data[
"reader"][
"video_length"]) / speed_factor, even_multiple))
2280 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2285 return number - (number % multiple)
2290 from math
import sqrt
2293 available_clips = []
2294 start_position = float(clip.data[
"position"])
2295 for c
in Clip.filter():
2296 if float(c.data[
"position"]) >= (start_position - 0.5)
and float(c.data[
"position"]) <= (start_position + 0.5):
2298 available_clips.append(c)
2301 number_of_clips = len(available_clips)
2302 number_of_rows = int(sqrt(number_of_clips))
2303 max_clips_on_row = float(number_of_clips) / float(number_of_rows)
2306 if max_clips_on_row > float(int(max_clips_on_row)):
2307 max_clips_on_row = int(max_clips_on_row + 1)
2309 max_clips_on_row = int(max_clips_on_row)
2312 height = 1.0 / float(number_of_rows)
2313 width = 1.0 / float(max_clips_on_row)
2318 for row
in range(0, number_of_rows):
2321 column_string =
" - - - "
2322 for col
in range(0, max_clips_on_row):
2323 if clip_index < number_of_clips:
2325 X = float(col) * width
2326 Y = float(row) * height
2329 selected_clip = available_clips[clip_index]
2330 selected_clip.data[
"gravity"] = openshot.GRAVITY_TOP_LEFT
2333 selected_clip.data[
"scale"] = openshot.SCALE_STRETCH
2335 selected_clip.data[
"scale"] = openshot.SCALE_FIT
2338 w = openshot.Point(1, width, openshot.BEZIER)
2339 w_object = json.loads(w.Json())
2340 selected_clip.data[
"scale_x"] = {
"Points" : [w_object]}
2341 h = openshot.Point(1, height, openshot.BEZIER)
2342 h_object = json.loads(h.Json())
2343 selected_clip.data[
"scale_y"] = {
"Points" : [h_object]}
2344 x_point = openshot.Point(1, X, openshot.BEZIER)
2345 x_object = json.loads(x_point.Json())
2346 selected_clip.data[
"location_x"] = {
"Points" : [x_object]}
2347 y_point = openshot.Point(1, Y, openshot.BEZIER)
2348 y_object = json.loads(y_point.Json())
2349 selected_clip.data[
"location_y"] = {
"Points" : [y_object]}
2351 log.info(
'Updating clip id: %s' % selected_clip.data[
"id"])
2352 log.info(
'width: %s, height: %s' % (width, height))
2358 self.
update_clip_data(selected_clip.data, only_basic_props=
False, ignore_reader=
True)
2363 log.info(
"Reverse_Transition_Triggered")
2366 for tran_id
in tran_ids:
2369 tran = Transition.get(id=tran_id)
2375 tran_data_copy = deepcopy(tran.data)
2376 new_index = len(tran.data[
"brightness"][
"Points"])
2377 for point
in tran.data[
"brightness"][
"Points"]:
2379 tran_data_copy[
"brightness"][
"Points"][new_index][
"co"][
"Y"] = point[
"co"][
"Y"]
2380 if "handle_left" in point:
2381 tran_data_copy[
"brightness"][
"Points"][new_index][
"handle_left"][
"Y"] = point[
"handle_left"][
"Y"]
2382 tran_data_copy[
"brightness"][
"Points"][new_index][
"handle_right"][
"Y"] = point[
"handle_right"][
"Y"]
2389 log.info(
'ShowTransitionMenu: %s' % tran_id)
2395 tran = Transition.get(id=tran_id)
2401 if tran_id
not in self.window.selected_transitions:
2402 self.window.addSelection(tran_id,
'transition')
2404 tran_ids = self.window.selected_transitions
2405 clip_ids = self.window.selected_clips
2408 fps =
get_app().project.get([
"fps"])
2409 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2412 playhead_position = float(self.window.preview_thread.current_frame) / fps_float
2417 if len(tran_ids) + len(clip_ids) > 1:
2419 Copy_All = menu.addAction(_(
"Copy"))
2420 Copy_All.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
2421 Copy_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_ALL, clip_ids, tran_ids))
2424 Copy_Menu = QMenu(_(
"Copy"), self)
2425 Copy_Tran = Copy_Menu.addAction(_(
"Transition"))
2426 Copy_Tran.setShortcut(QKeySequence(self.window.getShortcutByName(
"copyAll")))
2427 Copy_Tran.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_TRANSITION, [], [tran_id]))
2429 Keyframe_Menu = QMenu(_(
"Keyframes"), self)
2430 Copy_Keyframes_All = Keyframe_Menu.addAction(_(
"All"))
2431 Copy_Keyframes_All.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_ALL, [], [tran_id]))
2432 Keyframe_Menu.addSeparator()
2433 Copy_Keyframes_Brightness = Keyframe_Menu.addAction(_(
"Brightness"))
2434 Copy_Keyframes_Brightness.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_BRIGHTNESS, [], [tran_id]))
2435 Copy_Keyframes_Scale = Keyframe_Menu.addAction(_(
"Contrast"))
2436 Copy_Keyframes_Scale.triggered.connect(partial(self.
Copy_Triggered, MENU_COPY_KEYFRAMES_CONTRAST, [], [tran_id]))
2439 Copy_Menu.addMenu(Keyframe_Menu)
2440 menu.addMenu(Copy_Menu)
2444 clipboard_clip_ids = [k
for k, v
in self.copy_clipboard.items()
if v.get(
'id')]
2445 clipboard_tran_ids = [k
for k, v
in self.copy_transition_clipboard.items()
if v.get(
'id')]
2449 Paste_Tran = menu.addAction(_(
"Paste"))
2450 Paste_Tran.triggered.connect(partial(self.
Paste_Triggered, MENU_PASTE, 0.0, 0, [], tran_ids))
2455 if len(clip_ids) > 1:
2456 Alignment_Menu = QMenu(_(
"Align"), self)
2457 Align_Left = Alignment_Menu.addAction(_(
"Left"))
2458 Align_Left.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_LEFT, clip_ids, tran_ids))
2459 Align_Right = Alignment_Menu.addAction(_(
"Right"))
2460 Align_Right.triggered.connect(partial(self.
Align_Triggered, MENU_ALIGN_RIGHT, clip_ids, tran_ids))
2463 menu.addMenu(Alignment_Menu)
2467 start_of_tran = float(tran.data[
"start"])
2468 end_of_tran = float(tran.data[
"end"])
2469 position_of_tran = float(tran.data[
"position"])
2470 if playhead_position >= position_of_tran
and playhead_position <= (position_of_tran + (end_of_tran - start_of_tran)):
2472 Slice_Menu = QMenu(_(
"Slice"), self)
2473 Slice_Keep_Both = Slice_Menu.addAction(_(
"Keep Both Sides"))
2474 Slice_Keep_Both.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_BOTH, [], [tran_id], playhead_position))
2475 Slice_Keep_Left = Slice_Menu.addAction(_(
"Keep Left Side"))
2476 Slice_Keep_Left.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_LEFT, [], [tran_id], playhead_position))
2477 Slice_Keep_Right = Slice_Menu.addAction(_(
"Keep Right Side"))
2478 Slice_Keep_Right.triggered.connect(partial(self.
Slice_Triggered, MENU_SLICE_KEEP_RIGHT, [], [tran_id], playhead_position))
2479 menu.addMenu(Slice_Menu)
2482 Reverse_Transition = menu.addAction(_(
"Reverse Transition"))
2487 menu.addAction(self.window.actionProperties)
2491 menu.addAction(self.window.actionRemoveTransition)
2494 return menu.popup(QCursor.pos())
2498 log.info(
'ShowTrackMenu: %s' % layer_id)
2500 if layer_id
not in self.window.selected_tracks:
2501 self.window.selected_tracks = [layer_id]
2504 track = Track.get(id=layer_id)
2505 locked = track.data.get(
"lock",
False)
2508 menu.addAction(self.window.actionAddTrackAbove)
2509 menu.addAction(self.window.actionAddTrackBelow)
2510 menu.addAction(self.window.actionRenameTrack)
2512 menu.addAction(self.window.actionUnlockTrack)
2513 self.window.actionRemoveTrack.setEnabled(
False)
2515 menu.addAction(self.window.actionLockTrack)
2516 self.window.actionRemoveTrack.setEnabled(
True)
2518 menu.addAction(self.window.actionRemoveTrack)
2519 return menu.popup(QCursor.pos())
2523 log.info(
'ShowMarkerMenu: %s' % marker_id)
2525 if marker_id
not in self.window.selected_markers:
2526 self.window.selected_markers = [marker_id]
2529 menu.addAction(self.window.actionRemoveMarker)
2530 return menu.popup(QCursor.pos())
2536 clip = Clip.get(id=clip_id)
2541 preview_path = clip.data[
'reader'][
'path']
2544 frame_number = max(frame_number, 1)
2545 frame_number = min(frame_number, int(clip.data[
'reader'][
'video_length']))
2548 self.window.LoadFileSignal.emit(preview_path)
2549 self.window.SpeedSignal.emit(0)
2552 self.window.SeekSignal.emit(frame_number)
2554 @pyqtSlot(float, int, str)
2558 self.window.LoadFileSignal.emit(
'')
2565 self.window.previewFrame(position_seconds, position_frames, time_code)
2573 code = JS_SCOPE_SELECTOR +
".MovePlayheadToFrame(" + str(position_frames) +
");"
2582 self.
eval_js(JS_SCOPE_SELECTOR +
".SetSnappingMode(%s);" % int(enable_snapping))
2590 self.
eval_js(JS_SCOPE_SELECTOR +
".SetRazorMode(%s);" % int(enable_razor))
2592 @pyqtSlot(str, str, bool)
2598 self.window.addSelection(item_id, item_type, clear_existing)
2606 self.window.removeSelection(item_id, item_type)
2620 self.window.zoomScaleLabel.setText(_(
"{} seconds").format(newScale))
2623 cursor_y = self.mapFromGlobal(self.cursor().pos()).y()
2625 cursor_x = self.mapFromGlobal(self.cursor().pos()).x()
2630 cmd = JS_SCOPE_SELECTOR +
".setScale(" + str(newScale) +
"," + str(cursor_x) +
");"
2631 self.page().mainFrame().evaluateJavaScript(cmd)
2634 self.redraw_audio_timer.start()
2637 get_app().updates.ignore_history =
True
2638 get_app().updates.update([
"scale"], newScale)
2639 get_app().updates.ignore_history =
False
2644 key_value = event.key()
2645 if (key_value == Qt.Key_Shift
or key_value == Qt.Key_Control):
2648 return QWebView.keyPressEvent(self, event)
2656 if int(QCoreApplication.instance().keyboardModifiers() & Qt.ControlModifier) > 0:
2659 steps = int(event.angleDelta().y() / tick_scale)
2660 self.window.sliderZoom.setValue(self.window.sliderZoom.value() - self.window.sliderZoom.pageStep() * steps)
2667 self.page().mainFrame().addToJavaScriptWindowObject(
'timeline', self)
2668 self.page().mainFrame().addToJavaScriptWindowObject(
'mainWindow', self.
window)
2677 if not self.
new_item and not event.mimeData().hasUrls()
and event.mimeData().html():
2685 data = json.loads(event.mimeData().text())
2698 elif not self.
new_item and event.mimeData().hasUrls():
2714 file = File.get(id=file_id)
2720 if (file.data[
"media_type"] ==
"video" or file.data[
"media_type"] ==
"image"):
2722 thumb_path = os.path.join(info.THUMBNAIL_PATH,
"%s.png" % file.data[
"id"])
2725 thumb_path = os.path.join(info.PATH,
"images",
"AudioThumbnail.png")
2728 path, filename = os.path.split(file.data[
"path"])
2731 file_path = file.absolute_path()
2734 c = openshot.Clip(file_path)
2737 new_clip = json.loads(c.Json())
2738 new_clip[
"file_id"] = file.id
2739 new_clip[
"title"] = filename
2740 new_clip[
"image"] = thumb_path
2744 if not new_clip.get(
"reader"):
2749 end_frame = new_clip[
"reader"][
"duration"]
2750 if 'start' in file.data.keys():
2751 new_clip[
"start"] = file.data[
'start']
2752 if 'end' in file.data.keys():
2753 new_clip[
"end"] = file.data[
'end']
2756 top_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2757 new_clip[
"layer"] = top_layer
2760 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2761 new_clip[
"position"] = js_position
2764 new_clip[
"duration"] = new_clip[
"reader"][
"duration"]
2765 if file.data[
"media_type"] ==
"image":
2766 new_clip[
"end"] = self.settings_obj.get(
"default-image-length")
2769 file_properties_fps = float(file.data[
"fps"][
"num"]) / float(file.data[
"fps"][
"den"])
2770 file_fps = float(new_clip[
"reader"][
"fps"][
"num"]) / float(new_clip[
"reader"][
"fps"][
"den"])
2771 fps_diff = file_fps / file_properties_fps
2772 new_clip[
"reader"][
"fps"][
"num"] = file.data[
"fps"][
"num"]
2773 new_clip[
"reader"][
"fps"][
"den"] = file.data[
"fps"][
"den"]
2775 new_clip[
"reader"][
"duration"] *= fps_diff
2776 new_clip[
"end"] *= fps_diff
2777 new_clip[
"duration"] *= fps_diff
2786 code = JS_SCOPE_SELECTOR +
".StartManualMove('" + self.
item_type +
"', '" + self.
item_id +
"');"
2794 get_app().updates.update([
"duration"], new_duration)
2798 log.info(
"addTransition...")
2801 top_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2804 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2807 fps =
get_app().project.get([
"fps"])
2808 fps_float = float(fps[
"num"]) / float(fps[
"den"])
2811 transition_reader = openshot.QtImageReader(file_ids[0])
2813 brightness = openshot.Keyframe()
2814 brightness.AddPoint(1, 1.0, openshot.BEZIER)
2815 brightness.AddPoint(round(10 * fps_float) + 1, -1.0, openshot.BEZIER)
2816 contrast = openshot.Keyframe(3.0)
2819 transitions_data = {
2820 "id":
get_app().project.generate_id(),
2822 "title":
"Transition",
2824 "position": js_position,
2827 "brightness": json.loads(brightness.Json()),
2828 "contrast": json.loads(contrast.Json()),
2829 "reader": json.loads(transition_reader.Json()),
2830 "replace_image":
False
2837 self.
item_id = transitions_data.get(
'id')
2840 code = JS_SCOPE_SELECTOR +
".StartManualMove('" + self.
item_type +
"', '" + self.
item_id +
"');"
2845 log.info(
"addEffect: %s at %s" % (effect_names, position))
2847 name = effect_names[0]
2850 closest_layer = int(self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptTrack(" + str(position.y()) +
");"))
2853 js_position = self.
eval_js(JS_SCOPE_SELECTOR +
".GetJavaScriptPosition(" + str(position.x()) +
");")
2856 possible_clips = Clip.filter(layer=closest_layer)
2857 for clip
in possible_clips:
2858 if js_position == 0
or (clip.data[
"position"] <= js_position <= clip.data[
"position"] + (
2859 clip.data[
"end"] - clip.data[
"start"])):
2860 log.info(
"Applying effect to clip")
2864 effect = openshot.EffectInfo().CreateEffect(name)
2867 effect.Id(
get_app().project.generate_id())
2868 effect_json = json.loads(effect.Json())
2871 clip.data[
"effects"].append(effect_json)
2874 self.
update_clip_data(clip.data, only_basic_props=
False, ignore_reader=
True)
2885 if self.
item_type in [
"clip",
"transition"]:
2886 code = JS_SCOPE_SELECTOR +
".MoveItem(" + str(pos.x()) +
", " + str(pos.y()) +
", '" + self.
item_type +
"');"
2891 log.info(
"Dropping item on timeline - item_id: %s, item_type: %s" % (self.
item_id, self.
item_type))
2902 data = json.loads(event.mimeData().text())
2907 get_app().window.filesTreeView.dropEvent(event)
2910 for uri
in event.mimeData().urls():
2911 filepath = uri.toLocalFile()
2912 if os.path.exists(filepath)
and os.path.isfile(filepath):
2914 log.info(
'Adding clip for {}'.format(os.path.basename(filepath)))
2915 for file
in File.filter(path=filepath):
2928 get_app().window.refreshFrameSignal.emit()
2929 get_app().window.propertyTableView.select_frame(self.window.preview_thread.player.Position())
2934 log.info(
'dragLeaveEvent - Undo drop')
2936 get_app().window.actionRemoveClip.trigger()
2938 get_app().window.actionRemoveTransition.trigger()
2951 log.info(
'redraw_audio_onTimeout')
2954 self.redraw_audio_timer.stop()
2957 cmd = JS_SCOPE_SELECTOR +
".reDrawAllAudioData();"
2958 self.page().mainFrame().evaluateJavaScript(cmd)
2965 cmd = JS_SCOPE_SELECTOR +
".ClearAllSelections();"
2966 self.page().mainFrame().evaluateJavaScript(cmd)
2973 cmd = JS_SCOPE_SELECTOR +
".SelectAll();"
2974 self.page().mainFrame().evaluateJavaScript(cmd)
2982 cache_object =
get_app().window.timeline_sync.timeline.GetCache()
2983 if cache_object
and cache_object.Count() > 0:
2985 cache_json =
get_app().window.timeline_sync.timeline.GetCache().Json()
2986 cache_dict = json.loads(cache_json)
2987 cache_version = cache_dict[
"version"]
2993 cmd = JS_SCOPE_SELECTOR +
".RenderCache(" + cache_json +
");"
2994 self.page().mainFrame().evaluateJavaScript(cmd)
3000 QWebView.__init__(self)
3002 self.setAcceptDrops(
True)
3007 self.settings().setObjectCacheCapacities(0, 0, 0);
3013 get_app().updates.add_listener(self)
3016 self.setUrl(QUrl.fromLocalFile(QFileInfo(self.
html_path).absoluteFilePath()))
3019 self.page().mainFrame().javaScriptWindowObjectCleared.connect(self.
setup_js_data)
3022 window.sliderZoom.valueChanged.connect(self.
update_zoom)
3044 self.redraw_audio_timer.setInterval(300)
3050 self.cache_renderer.setInterval(0.5 * 1000)
3054 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 Thumbnail_Updated
Callback when thumbnail needs to be updated.
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.