31 from random
import shuffle, randint, uniform
36 from classes
import settings
37 from classes
import info, ui_util
38 from classes.logger
import log
39 from classes.query
import Track, Clip, Transition
40 from classes.app
import get_app
42 from windows.views.add_to_timeline_treeview
import TimelineTreeView
49 import simplejson
as json
56 ui_path = os.path.join(info.PATH,
'windows',
'ui',
'add-to-timeline.ui')
61 log.info(
"btnMoveUpClicked")
64 files = self.treeFiles.timeline_model.files
67 if self.treeFiles.selected:
68 selected_index = self.treeFiles.selected.row()
71 if not files
or selected_index ==
None:
75 new_index = max(selected_index - 1, 0)
79 files.insert(new_index, files.pop(selected_index))
82 self.treeFiles.refresh_view()
85 idx = self.treeFiles.timeline_model.model.index(new_index, 0)
86 self.treeFiles.setCurrentIndex(idx)
91 log.info(
"btnMoveDownClicked")
94 files = self.treeFiles.timeline_model.files
97 if self.treeFiles.selected:
98 selected_index = self.treeFiles.selected.row()
101 if not files
or selected_index ==
None:
105 new_index = min(selected_index + 1, len(files) - 1)
109 files.insert(new_index, files.pop(selected_index))
112 self.treeFiles.refresh_view()
115 idx = self.treeFiles.timeline_model.model.index(new_index, 0)
116 self.treeFiles.setCurrentIndex(idx)
121 log.info(
"btnShuffleClicked")
124 files = shuffle(self.treeFiles.timeline_model.files)
127 self.treeFiles.refresh_view()
132 log.info(
"btnRemoveClicked")
135 files = self.treeFiles.timeline_model.files
137 selected_index =
None
138 if self.treeFiles.selected:
139 selected_index = self.treeFiles.selected.row()
142 if not files
or selected_index ==
None:
146 files.pop(selected_index)
149 self.treeFiles.refresh_view()
152 new_index = max(len(files) - 1, 0)
155 idx = self.treeFiles.timeline_model.model.index(new_index, 0)
156 self.treeFiles.setCurrentIndex(idx)
167 start_position = self.txtStartTime.value()
168 track_num = self.cmbTrack.currentData()
169 fade_value = self.cmbFade.currentData()
170 fade_length = self.txtFadeLength.value()
171 transition_path = self.cmbTransition.currentData()
172 transition_length = self.txtTransitionLength.value()
173 image_length = self.txtImageLength.value()
174 zoom_value = self.cmbZoom.currentData()
177 position = start_position
179 random_transition =
False
180 if transition_path ==
"random":
181 random_transition =
True
184 fps =
get_app().project.get([
"fps"])
185 fps_float = float(fps[
"num"]) / float(fps[
"den"])
188 for file
in self.treeFiles.timeline_model.files:
193 if (file.data[
"media_type"] ==
"video" or file.data[
"media_type"] ==
"image"):
195 thumb_path = os.path.join(info.THUMBNAIL_PATH,
"%s.png" % file.data[
"id"])
198 thumb_path = os.path.join(info.PATH,
"images",
"AudioThumbnail.png")
201 path, filename = os.path.split(file.data[
"path"])
204 file_path = file.absolute_path()
207 c = openshot.Clip(file_path)
210 new_clip = json.loads(c.Json())
211 new_clip[
"position"] = position
212 new_clip[
"layer"] = track_num
213 new_clip[
"file_id"] = file.id
214 new_clip[
"title"] = filename
215 new_clip[
"image"] = thumb_path
219 if not new_clip.get(
"reader"):
223 file_properties_fps = float(file.data[
"fps"][
"num"]) / float(file.data[
"fps"][
"den"])
224 file_fps = float(new_clip[
"reader"][
"fps"][
"num"]) / float(new_clip[
"reader"][
"fps"][
"den"])
225 fps_diff = file_fps / file_properties_fps
226 new_clip[
"reader"][
"fps"][
"num"] = file.data[
"fps"][
"num"]
227 new_clip[
"reader"][
"fps"][
"den"] = file.data[
"fps"][
"den"]
229 new_clip[
"reader"][
"duration"] *= fps_diff
230 new_clip[
"end"] *= fps_diff
231 new_clip[
"duration"] *= fps_diff
235 end_time = new_clip[
"reader"][
"duration"]
237 if 'start' in file.data.keys():
238 start_time = file.data[
'start']
239 new_clip[
"start"] = start_time
240 if 'end' in file.data.keys():
241 end_time = file.data[
'end']
242 new_clip[
"end"] = end_time
245 new_clip[
"duration"] = new_clip[
"reader"][
"duration"]
246 if file.data[
"media_type"] ==
"image":
247 end_time = image_length
248 new_clip[
"end"] = end_time
251 if not transition_path:
252 if fade_value !=
None:
254 position = max(start_position, new_clip[
"position"] - fade_length)
255 new_clip[
"position"] = position
257 if fade_value ==
'Fade In' or fade_value ==
'Fade In & Out':
258 start = openshot.Point(round(start_time * fps_float) + 1, 0.0, openshot.BEZIER)
259 start_object = json.loads(start.Json())
260 end = openshot.Point(min(round((start_time + fade_length) * fps_float) + 1, round(end_time * fps_float) + 1), 1.0, openshot.BEZIER)
261 end_object = json.loads(end.Json())
262 new_clip[
'alpha'][
"Points"].append(start_object)
263 new_clip[
'alpha'][
"Points"].append(end_object)
265 if fade_value ==
'Fade Out' or fade_value ==
'Fade In & Out':
266 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)
267 start_object = json.loads(start.Json())
268 end = openshot.Point(round(end_time * fps_float) + 1, 0.0, openshot.BEZIER)
269 end_object = json.loads(end.Json())
270 new_clip[
'alpha'][
"Points"].append(start_object)
271 new_clip[
'alpha'][
"Points"].append(end_object)
274 if zoom_value !=
None:
276 if zoom_value ==
"Random":
277 animate_start_x = uniform(-0.5, 0.5)
278 animate_end_x = uniform(-0.15, 0.15)
279 animate_start_y = uniform(-0.5, 0.5)
280 animate_end_y = uniform(-0.15, 0.15)
283 start_scale = uniform(0.5, 1.5)
284 end_scale = uniform(0.85, 1.15)
286 elif zoom_value ==
"Zoom In":
287 animate_start_x = 0.0
289 animate_start_y = 0.0
296 elif zoom_value ==
"Zoom Out":
297 animate_start_x = 0.0
299 animate_start_y = 0.0
307 start = openshot.Point(round(start_time * fps_float) + 1, start_scale, openshot.BEZIER)
308 start_object = json.loads(start.Json())
309 end = openshot.Point(round(end_time * fps_float) + 1, end_scale, openshot.BEZIER)
310 end_object = json.loads(end.Json())
311 new_clip[
"gravity"] = openshot.GRAVITY_CENTER
312 new_clip[
"scale_x"][
"Points"].append(start_object)
313 new_clip[
"scale_x"][
"Points"].append(end_object)
314 new_clip[
"scale_y"][
"Points"].append(start_object)
315 new_clip[
"scale_y"][
"Points"].append(end_object)
318 start_x = openshot.Point(round(start_time * fps_float) + 1, animate_start_x, openshot.BEZIER)
319 start_x_object = json.loads(start_x.Json())
320 end_x = openshot.Point(round(end_time * fps_float) + 1, animate_end_x, openshot.BEZIER)
321 end_x_object = json.loads(end_x.Json())
322 start_y = openshot.Point(round(start_time * fps_float) + 1, animate_start_y, openshot.BEZIER)
323 start_y_object = json.loads(start_y.Json())
324 end_y = openshot.Point(round(end_time * fps_float) + 1, animate_end_y, openshot.BEZIER)
325 end_y_object = json.loads(end_y.Json())
326 new_clip[
"gravity"] = openshot.GRAVITY_CENTER
327 new_clip[
"location_x"][
"Points"].append(start_x_object)
328 new_clip[
"location_x"][
"Points"].append(end_x_object)
329 new_clip[
"location_y"][
"Points"].append(start_y_object)
330 new_clip[
"location_y"][
"Points"].append(end_y_object)
335 if random_transition:
340 transition_reader = openshot.QtImageReader(transition_path)
342 brightness = openshot.Keyframe()
343 brightness.AddPoint(1, 1.0, openshot.BEZIER)
344 brightness.AddPoint(round(min(transition_length, end_time - start_time) * fps_float) + 1, -1.0, openshot.BEZIER)
345 contrast = openshot.Keyframe(3.0)
350 "title":
"Transition",
353 "end": min(transition_length, end_time - start_time),
354 "brightness": json.loads(brightness.Json()),
355 "contrast": json.loads(contrast.Json()),
356 "reader": json.loads(transition_reader.Json()),
357 "replace_image":
False
361 position = max(start_position, position - transition_length)
362 transitions_data[
"position"] = position
363 new_clip[
"position"] = position
367 tran.data = transitions_data
376 position += (end_time - start_time)
380 super(AddToTimeline, self).
accept()
390 fade_value = self.cmbFade.currentData()
391 fade_length = self.txtFadeLength.value()
392 transition_path = self.cmbTransition.currentData()
393 transition_length = self.txtTransitionLength.value()
396 for file
in self.treeFiles.timeline_model.files:
398 duration = file.data[
"duration"]
399 if file.data[
"media_type"] ==
"image":
400 duration = self.txtImageLength.value()
404 if not transition_path:
406 if fade_value !=
None:
408 duration -= fade_length
411 duration -= transition_length
417 fps =
get_app().project.get([
"fps"])
420 total_parts = self.
secondsToTime(total, fps[
"num"], fps[
"den"])
421 timestamp =
"%s:%s:%s:%s" % (total_parts[
"hour"], total_parts[
"min"], total_parts[
"sec"], total_parts[
"frame"])
422 self.lblTotalLengthValue.setText(timestamp)
425 format_mask =
'%%0%sd' % pad_length
426 return format_mask % value
430 milliseconds = secs * 1000
431 sec = math.floor(milliseconds/1000)
432 milli = milliseconds % 1000
433 min = math.floor(sec/60)
435 hour = math.floor(min/60)
437 day = math.floor(hour/24)
439 week = math.floor(day/7)
442 frame = round((milli / 1000.0) * (fps_num / fps_den)) + 1
443 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) };
451 super(AddToTimeline, self).
reject()
455 QDialog.__init__(self)
475 self.vboxTreeParent.insertWidget(0, self.
treeFiles)
478 self.treeFiles.timeline_model.update_model(files)
481 self.treeFiles.refresh_view()
484 self.txtStartTime.setValue(position)
487 self.txtImageLength.setValue(self.settings.get(
"default-image-length"))
488 self.txtImageLength.valueChanged.connect(self.
updateTotal)
489 self.cmbTransition.currentIndexChanged.connect(self.
updateTotal)
490 self.cmbFade.currentIndexChanged.connect(self.
updateTotal)
491 self.txtFadeLength.valueChanged.connect(self.
updateTotal)
492 self.txtTransitionLength.valueChanged.connect(self.
updateTotal)
495 tracks = Track.filter()
496 for track
in reversed(tracks):
498 track_name = track.data[
'label']
or _(
"Track %s") % track.data[
'number']
499 self.cmbTrack.addItem(track_name, track.data[
'number'])
502 self.cmbFade.addItem(_(
'None'),
None)
503 self.cmbFade.addItem(_(
'Fade In'),
'Fade In')
504 self.cmbFade.addItem(_(
'Fade Out'),
'Fade Out')
505 self.cmbFade.addItem(_(
'Fade In & Out'),
'Fade In & Out')
508 self.cmbZoom.addItem(_(
'None'),
None)
509 self.cmbZoom.addItem(_(
'Random'),
'Random')
510 self.cmbZoom.addItem(_(
'Zoom In'),
'Zoom In')
511 self.cmbZoom.addItem(_(
'Zoom Out'),
'Zoom Out')
514 transitions_dir = os.path.join(info.PATH,
"transitions")
515 common_dir = os.path.join(transitions_dir,
"common")
516 extra_dir = os.path.join(transitions_dir,
"extra")
517 transition_groups = [{
"type":
"common",
"dir": common_dir,
"files": os.listdir(common_dir)},
518 {
"type":
"extra",
"dir": extra_dir,
"files": os.listdir(extra_dir)}]
520 self.cmbTransition.addItem(_(
'None'),
None)
521 self.cmbTransition.addItem(_(
'Random'),
'random')
523 for group
in transition_groups:
526 files = group[
"files"]
528 for filename
in sorted(files):
529 path = os.path.join(dir, filename)
530 (fileBaseName, fileExtension) = os.path.splitext(filename)
533 if filename[0] ==
"." or "thumbs.db" in filename.lower():
538 name_parts = fileBaseName.split(
"_")
539 if name_parts[-1].isdigit():
540 suffix_number = name_parts[-1]
543 trans_name = fileBaseName.replace(
"_",
" ").capitalize()
547 trans_name = trans_name.replace(suffix_number,
"%s")
548 trans_name = _(trans_name) % suffix_number
550 trans_name = _(trans_name)
553 thumb_path = os.path.join(info.IMAGES_PATH,
"cache",
"{}.png".format(fileBaseName))
556 if not os.path.exists(thumb_path):
558 thumb_path = os.path.join(info.CACHE_PATH,
"{}.png".format(fileBaseName))
561 self.transitions.append(path)
562 self.cmbTransition.addItem(QIcon(thumb_path), _(trans_name), path)
569 self.btnBox.accepted.connect(self.
accept)
570 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.