31 from operator
import itemgetter
32 from random
import shuffle, randint, uniform
37 from classes
import settings
38 from classes
import info, ui_util
39 from classes.logger
import log
40 from classes.query
import Track, Clip, Transition
41 from classes.app
import get_app
43 from windows.views.add_to_timeline_treeview
import TimelineTreeView
50 import simplejson
as json
57 ui_path = os.path.join(info.PATH,
'windows',
'ui',
'add-to-timeline.ui')
62 log.info(
"btnMoveUpClicked")
65 files = self.treeFiles.timeline_model.files
68 if self.treeFiles.selected:
69 selected_index = self.treeFiles.selected.row()
72 if not files
or selected_index ==
None:
76 new_index = max(selected_index - 1, 0)
80 files.insert(new_index, files.pop(selected_index))
83 self.treeFiles.refresh_view()
86 idx = self.treeFiles.timeline_model.model.index(new_index, 0)
87 self.treeFiles.setCurrentIndex(idx)
92 log.info(
"btnMoveDownClicked")
95 files = self.treeFiles.timeline_model.files
98 if self.treeFiles.selected:
99 selected_index = self.treeFiles.selected.row()
102 if not files
or selected_index ==
None:
106 new_index = min(selected_index + 1, len(files) - 1)
110 files.insert(new_index, files.pop(selected_index))
113 self.treeFiles.refresh_view()
116 idx = self.treeFiles.timeline_model.model.index(new_index, 0)
117 self.treeFiles.setCurrentIndex(idx)
122 log.info(
"btnShuffleClicked")
125 files = shuffle(self.treeFiles.timeline_model.files)
128 self.treeFiles.refresh_view()
133 log.info(
"btnRemoveClicked")
136 files = self.treeFiles.timeline_model.files
138 selected_index =
None
139 if self.treeFiles.selected:
140 selected_index = self.treeFiles.selected.row()
143 if not files
or selected_index ==
None:
147 files.pop(selected_index)
150 self.treeFiles.refresh_view()
153 new_index = max(len(files) - 1, 0)
156 idx = self.treeFiles.timeline_model.model.index(new_index, 0)
157 self.treeFiles.setCurrentIndex(idx)
168 start_position = self.txtStartTime.value()
169 track_num = self.cmbTrack.currentData()
170 fade_value = self.cmbFade.currentData()
171 fade_length = self.txtFadeLength.value()
172 transition_path = self.cmbTransition.currentData()
173 transition_length = self.txtTransitionLength.value()
174 image_length = self.txtImageLength.value()
175 zoom_value = self.cmbZoom.currentData()
178 position = start_position
180 random_transition =
False
181 if transition_path ==
"random":
182 random_transition =
True
185 fps =
get_app().project.get([
"fps"])
186 fps_float = float(fps[
"num"]) / float(fps[
"den"])
189 for file
in self.treeFiles.timeline_model.files:
194 if (file.data[
"media_type"] ==
"video" or file.data[
"media_type"] ==
"image"):
196 thumb_path = os.path.join(info.THUMBNAIL_PATH,
"%s.png" % file.data[
"id"])
199 thumb_path = os.path.join(info.PATH,
"images",
"AudioThumbnail.png")
202 path, filename = os.path.split(file.data[
"path"])
205 file_path = file.absolute_path()
208 c = openshot.Clip(file_path)
211 new_clip = json.loads(c.Json())
212 new_clip[
"position"] = position
213 new_clip[
"layer"] = track_num
214 new_clip[
"file_id"] = file.id
215 new_clip[
"title"] = filename
216 new_clip[
"image"] = thumb_path
220 if not new_clip.get(
"reader"):
224 file_properties_fps = float(file.data[
"fps"][
"num"]) / float(file.data[
"fps"][
"den"])
225 file_fps = float(new_clip[
"reader"][
"fps"][
"num"]) / float(new_clip[
"reader"][
"fps"][
"den"])
226 fps_diff = file_fps / file_properties_fps
227 new_clip[
"reader"][
"fps"][
"num"] = file.data[
"fps"][
"num"]
228 new_clip[
"reader"][
"fps"][
"den"] = file.data[
"fps"][
"den"]
230 new_clip[
"reader"][
"duration"] *= fps_diff
231 new_clip[
"end"] *= fps_diff
232 new_clip[
"duration"] *= fps_diff
236 end_time = new_clip[
"reader"][
"duration"]
238 if 'start' in file.data.keys():
239 start_time = file.data[
'start']
240 new_clip[
"start"] = start_time
241 if 'end' in file.data.keys():
242 end_time = file.data[
'end']
243 new_clip[
"end"] = end_time
246 new_clip[
"duration"] = new_clip[
"reader"][
"duration"]
247 if file.data[
"media_type"] ==
"image":
248 end_time = image_length
249 new_clip[
"end"] = end_time
252 if not transition_path:
253 if fade_value !=
None:
255 position = max(start_position, new_clip[
"position"] - fade_length)
256 new_clip[
"position"] = position
258 if fade_value ==
'Fade In' or fade_value ==
'Fade In & Out':
259 start = openshot.Point(round(start_time * fps_float) + 1, 0.0, openshot.BEZIER)
260 start_object = json.loads(start.Json())
261 end = openshot.Point(min(round((start_time + fade_length) * fps_float) + 1, round(end_time * fps_float) + 1), 1.0, openshot.BEZIER)
262 end_object = json.loads(end.Json())
263 new_clip[
'alpha'][
"Points"].append(start_object)
264 new_clip[
'alpha'][
"Points"].append(end_object)
266 if fade_value ==
'Fade Out' or fade_value ==
'Fade In & Out':
267 start = openshot.Point(max(round((end_time * fps_float) + 1) - (round(fade_length * fps_float) + 1), round(start_time * fps_float) + 1), 1.0, openshot.BEZIER)
268 start_object = json.loads(start.Json())
269 end = openshot.Point(round(end_time * fps_float) + 1, 0.0, openshot.BEZIER)
270 end_object = json.loads(end.Json())
271 new_clip[
'alpha'][
"Points"].append(start_object)
272 new_clip[
'alpha'][
"Points"].append(end_object)
275 if zoom_value !=
None:
277 if zoom_value ==
"Random":
278 animate_start_x = uniform(-0.5, 0.5)
279 animate_end_x = uniform(-0.15, 0.15)
280 animate_start_y = uniform(-0.5, 0.5)
281 animate_end_y = uniform(-0.15, 0.15)
284 start_scale = uniform(0.5, 1.5)
285 end_scale = uniform(0.85, 1.15)
287 elif zoom_value ==
"Zoom In":
288 animate_start_x = 0.0
290 animate_start_y = 0.0
297 elif zoom_value ==
"Zoom Out":
298 animate_start_x = 0.0
300 animate_start_y = 0.0
308 start = openshot.Point(round(start_time * fps_float) + 1, start_scale, openshot.BEZIER)
309 start_object = json.loads(start.Json())
310 end = openshot.Point(round(end_time * fps_float) + 1, end_scale, openshot.BEZIER)
311 end_object = json.loads(end.Json())
312 new_clip[
"gravity"] = openshot.GRAVITY_CENTER
313 new_clip[
"scale_x"][
"Points"].append(start_object)
314 new_clip[
"scale_x"][
"Points"].append(end_object)
315 new_clip[
"scale_y"][
"Points"].append(start_object)
316 new_clip[
"scale_y"][
"Points"].append(end_object)
319 start_x = openshot.Point(round(start_time * fps_float) + 1, animate_start_x, openshot.BEZIER)
320 start_x_object = json.loads(start_x.Json())
321 end_x = openshot.Point(round(end_time * fps_float) + 1, animate_end_x, openshot.BEZIER)
322 end_x_object = json.loads(end_x.Json())
323 start_y = openshot.Point(round(start_time * fps_float) + 1, animate_start_y, openshot.BEZIER)
324 start_y_object = json.loads(start_y.Json())
325 end_y = openshot.Point(round(end_time * fps_float) + 1, animate_end_y, openshot.BEZIER)
326 end_y_object = json.loads(end_y.Json())
327 new_clip[
"gravity"] = openshot.GRAVITY_CENTER
328 new_clip[
"location_x"][
"Points"].append(start_x_object)
329 new_clip[
"location_x"][
"Points"].append(end_x_object)
330 new_clip[
"location_y"][
"Points"].append(start_y_object)
331 new_clip[
"location_y"][
"Points"].append(end_y_object)
336 if random_transition:
341 transition_reader = openshot.QtImageReader(transition_path)
343 brightness = openshot.Keyframe()
344 brightness.AddPoint(1, 1.0, openshot.BEZIER)
345 brightness.AddPoint(round(min(transition_length, end_time - start_time) * fps_float) + 1, -1.0, openshot.BEZIER)
346 contrast = openshot.Keyframe(3.0)
351 "title":
"Transition",
354 "end": min(transition_length, end_time - start_time),
355 "brightness": json.loads(brightness.Json()),
356 "contrast": json.loads(contrast.Json()),
357 "reader": json.loads(transition_reader.Json()),
358 "replace_image":
False
362 position = max(start_position, position - transition_length)
363 transitions_data[
"position"] = position
364 new_clip[
"position"] = position
368 tran.data = transitions_data
377 position += (end_time - start_time)
381 super(AddToTimeline, self).
accept()
391 fade_value = self.cmbFade.currentData()
392 fade_length = self.txtFadeLength.value()
393 transition_path = self.cmbTransition.currentData()
394 transition_length = self.txtTransitionLength.value()
397 for file
in self.treeFiles.timeline_model.files:
399 duration = file.data[
"duration"]
400 if file.data[
"media_type"] ==
"image":
401 duration = self.txtImageLength.value()
405 if not transition_path:
407 if fade_value !=
None:
409 duration -= fade_length
412 duration -= transition_length
418 fps =
get_app().project.get([
"fps"])
421 total_parts = self.
secondsToTime(total, fps[
"num"], fps[
"den"])
422 timestamp =
"%s:%s:%s:%s" % (total_parts[
"hour"], total_parts[
"min"], total_parts[
"sec"], total_parts[
"frame"])
423 self.lblTotalLengthValue.setText(timestamp)
426 format_mask =
'%%0%sd' % pad_length
427 return format_mask % value
431 milliseconds = secs * 1000
432 sec = math.floor(milliseconds/1000)
433 milli = milliseconds % 1000
434 min = math.floor(sec/60)
436 hour = math.floor(min/60)
438 day = math.floor(hour/24)
440 week = math.floor(day/7)
443 frame = round((milli / 1000.0) * (fps_num / fps_den)) + 1
444 return {
"week":self.
padNumber(week,2),
"day":self.
padNumber(day,2),
"hour":self.
padNumber(hour,2),
"min":self.
padNumber(min,2),
"sec":self.
padNumber(sec,2),
"milli":self.
padNumber(milli,2),
"frame":self.
padNumber(frame,2) };
452 super(AddToTimeline, self).
reject()
456 QDialog.__init__(self)
476 self.vboxTreeParent.insertWidget(0, self.
treeFiles)
479 self.treeFiles.timeline_model.update_model(files)
482 self.treeFiles.refresh_view()
485 self.txtStartTime.setValue(position)
488 self.txtImageLength.setValue(self.settings.get(
"default-image-length"))
489 self.txtImageLength.valueChanged.connect(self.
updateTotal)
490 self.cmbTransition.currentIndexChanged.connect(self.
updateTotal)
491 self.cmbFade.currentIndexChanged.connect(self.
updateTotal)
492 self.txtFadeLength.valueChanged.connect(self.
updateTotal)
493 self.txtTransitionLength.valueChanged.connect(self.
updateTotal)
496 all_tracks =
get_app().project.get([
"layers"])
497 display_count = len(all_tracks)
498 for track
in reversed(sorted(all_tracks, key=itemgetter(
'number'))):
500 track_name = track.get(
'label')
or _(
"Track %s") % display_count
501 self.cmbTrack.addItem(track_name, track.get(
'number'))
505 self.cmbFade.addItem(_(
'None'),
None)
506 self.cmbFade.addItem(_(
'Fade In'),
'Fade In')
507 self.cmbFade.addItem(_(
'Fade Out'),
'Fade Out')
508 self.cmbFade.addItem(_(
'Fade In & Out'),
'Fade In & Out')
511 self.cmbZoom.addItem(_(
'None'),
None)
512 self.cmbZoom.addItem(_(
'Random'),
'Random')
513 self.cmbZoom.addItem(_(
'Zoom In'),
'Zoom In')
514 self.cmbZoom.addItem(_(
'Zoom Out'),
'Zoom Out')
517 transitions_dir = os.path.join(info.PATH,
"transitions")
518 common_dir = os.path.join(transitions_dir,
"common")
519 extra_dir = os.path.join(transitions_dir,
"extra")
520 transition_groups = [{
"type":
"common",
"dir": common_dir,
"files": os.listdir(common_dir)},
521 {
"type":
"extra",
"dir": extra_dir,
"files": os.listdir(extra_dir)}]
523 self.cmbTransition.addItem(_(
'None'),
None)
524 self.cmbTransition.addItem(_(
'Random'),
'random')
526 for group
in transition_groups:
529 files = group[
"files"]
531 for filename
in sorted(files):
532 path = os.path.join(dir, filename)
533 (fileBaseName, fileExtension) = os.path.splitext(filename)
536 if filename[0] ==
"." or "thumbs.db" in filename.lower():
541 name_parts = fileBaseName.split(
"_")
542 if name_parts[-1].isdigit():
543 suffix_number = name_parts[-1]
546 trans_name = fileBaseName.replace(
"_",
" ").capitalize()
550 trans_name = trans_name.replace(suffix_number,
"%s")
551 trans_name = _(trans_name) % suffix_number
553 trans_name = _(trans_name)
556 thumb_path = os.path.join(info.IMAGES_PATH,
"cache",
"{}.png".format(fileBaseName))
559 if not os.path.exists(thumb_path):
561 thumb_path = os.path.join(info.CACHE_PATH,
"{}.png".format(fileBaseName))
564 self.transitions.append(path)
565 self.cmbTransition.addItem(QIcon(thumb_path), _(trans_name), path)
572 self.btnBox.accepted.connect(self.
accept)
573 self.btnBox.rejected.connect(self.
reject)
def track_metric_screen
Track a GUI screen being shown.
def get_app
Returns the current QApplication instance of OpenShot.
def btnMoveDownClicked
Callback for move up button click.
def btnRemoveClicked
Callback for move up button click.
def btnMoveUpClicked
Callback for move up button click.
def ImageLengthChanged
Handle callback for image length being changed.
def load_ui
Load a Qt *.ui file, and also load an XML parsed version.
def accept
Ok button clicked.
def updateTotal
Calculate the total length of what's about to be added to the timeline.
def init_ui
Initialize all child widgets and action of a window or dialog.
def btnShuffleClicked
Callback for move up button click.
def reject
Cancel button clicked.
def get_settings
Get the current QApplication's settings instance.