30 from collections
import OrderedDict
35 from classes
import updates
36 from classes
import info
37 from classes.query
import Clip, Transition, Effect, File
38 from classes.logger
import log
39 from classes.app
import get_app
45 import simplejson
as json
50 QStandardItemModel.__init__(self)
59 selected_row = self.itemFromIndex(item).row()
60 property_names.append(self.item(selected_row, 0).data())
61 data.setText(json.dumps(property_names))
72 if action.key
and action.key[0]
in [
"clips",
"effects"]
and action.type
in [
"update",
"insert"]:
73 log.info(action.values)
84 self.update_timer.start()
96 log.info(
"Update item: %s" % item_type)
98 if item_type ==
"clip":
100 clips =
get_app().window.timeline_sync.timeline.Clips()
102 if clip.Id() == item_id:
107 self.selected.append((c, item_type))
109 if item_type ==
"transition":
111 trans =
get_app().window.timeline_sync.timeline.Effects()
113 if tran.Id() == item_id:
118 self.selected.append((t, item_type))
120 if item_type ==
"effect":
122 clips =
get_app().window.timeline_sync.timeline.Clips()
124 for effect
in clip.Effects():
125 if effect.Id() == item_id:
133 self.selected.append((e, item_type))
157 if item_type ==
"effect":
159 effect = Effect.get(id=clip.Id())
164 parent_clip_id = effect.parent[
"id"]
167 clips =
get_app().window.timeline_sync.timeline.Clips()
169 if c.Id() == parent_clip_id:
175 fps =
get_app().project.get([
"fps"])
176 fps_float = float(fps[
"num"]) / float(fps[
"den"])
179 requested_time = float(frame_number - 1) / fps_float
182 time_diff = (requested_time - clip.Position()) + clip.Start()
186 min_frame_number = round((clip.Start() * fps_float)) + 1
187 max_frame_number = round((clip.End() * fps_float)) + 1
206 property = self.model.item(item.row(), 0).data()
207 property_name = property[1][
"name"]
208 property_type = property[1][
"type"]
209 closest_point_x = property[1][
"closest_point_x"]
210 property_type = property[1][
"type"]
211 property_key = property[0]
212 clip_id, item_type = item.data()
218 if item_type ==
"clip":
220 c = Clip.get(id=clip_id)
221 elif item_type ==
"transition":
223 c = Transition.get(id=clip_id)
224 elif item_type ==
"effect":
226 c = Effect.get(id=clip_id)
230 if property_key
in c.data:
231 log.info(
"remove keyframe: %s" % c.data)
235 if property_type ==
"color":
236 keyframe_list = [c.data[property_key][
"red"], c.data[property_key][
"blue"], c.data[property_key][
"green"]]
238 keyframe_list = [c.data[property_key]]
241 for keyframe
in keyframe_list:
246 point_to_delete =
None
247 for point
in keyframe[
"Points"]:
251 point_to_delete = point
253 if point[
"co"][
"X"] == closest_point_x:
254 closest_point = point
257 if not point_to_delete:
258 point_to_delete = closest_point
263 log.info(
"Found point to delete at X=%s" % point_to_delete[
"co"][
"X"])
264 keyframe[
"Points"].remove(point_to_delete)
267 c.data = {property_key: c.data[property_key]}
275 get_app().window.refreshFrameSignal.emit()
278 self.parent.clearSelection()
282 def color_update(self, item, new_color, interpolation=-1, interpolation_details=[]):
285 property = self.model.item(item.row(), 0).data()
286 property_type = property[1][
"type"]
287 closest_point_x = property[1][
"closest_point_x"]
288 previous_point_x = property[1][
"previous_point_x"]
289 property_key = property[0]
290 clip_id, item_type = item.data()
292 if property_type ==
"color":
297 if item_type ==
"clip":
299 c = Clip.get(id=clip_id)
300 elif item_type ==
"transition":
302 c = Transition.get(id=clip_id)
303 elif item_type ==
"effect":
305 c = Effect.get(id=clip_id)
309 if property_key
in c.data:
310 log.info(
"color update: %s" % c.data)
313 for color, new_value
in [(
"red", new_color.red()), (
"blue", new_color.blue()), (
"green", new_color.green())]:
318 for point
in c.data[property_key][color][
"Points"]:
319 log.info(
"looping points: co.X = %s" % point[
"co"][
"X"])
320 if interpolation == -1
and point[
"co"][
"X"] == self.
frame_number:
325 point[
"co"][
"Y"] = new_value
326 log.info(
"updating point: co.X = %s to value: %s" % (point[
"co"][
"X"], float(new_value)))
329 elif interpolation > -1
and point[
"co"][
"X"] == previous_point_x:
333 point[
"interpolation"] = interpolation
334 if interpolation == 0:
335 point[
"handle_right"] = point.get(
"handle_right")
or {
"Y": 0.0,
"X": 0.0}
336 point[
"handle_right"][
"X"] = interpolation_details[0]
337 point[
"handle_right"][
"Y"] = interpolation_details[1]
339 log.info(
"updating interpolation mode point: co.X = %s to %s" % (point[
"co"][
"X"], interpolation))
340 log.info(
"use interpolation preset: %s" % str(interpolation_details))
342 elif interpolation > -1
and point[
"co"][
"X"] == closest_point_x:
346 point[
"interpolation"] = interpolation
347 if interpolation == 0:
348 point[
"handle_left"] = point.get(
"handle_left")
or {
"Y": 0.0,
"X": 0.0}
349 point[
"handle_left"][
"X"] = interpolation_details[2]
350 point[
"handle_left"][
"Y"] = interpolation_details[3]
352 log.info(
"updating interpolation mode point: co.X = %s to %s" % (point[
"co"][
"X"], interpolation))
353 log.info(
"use interpolation preset: %s" % str(interpolation_details))
358 log.info(
"Created new point at X=%s" % self.
frame_number)
359 c.data[property_key][color][
"Points"].append({
'co': {
'X': self.
frame_number,
'Y': new_value},
'interpolation': 1})
362 c.data = {property_key: c.data[property_key]}
370 get_app().window.refreshFrameSignal.emit()
373 self.parent.clearSelection()
377 def value_updated(self, item, interpolation=-1, value=None, interpolation_details=[]):
386 property = self.model.item(item.row(), 0).data()
387 property_name = property[1][
"name"]
388 closest_point_x = property[1][
"closest_point_x"]
389 previous_point_x = property[1][
"previous_point_x"]
390 property_type = property[1][
"type"]
391 property_key = property[0]
392 clip_id, item_type = item.data()
400 elif property_type ==
"string":
402 new_value = item.text()
403 elif property_type ==
"bool":
405 if item.text() == _(
"False"):
409 elif property_type ==
"int":
411 new_value = QLocale().system().toInt(item.text())[0]
414 new_value = QLocale().system().toFloat(item.text())[0]
418 log.info(
"%s for %s changed to %s at frame %s with interpolation: %s at closest x: %s" % (property_key, clip_id, new_value, self.
frame_number, interpolation, closest_point_x))
425 if item_type ==
"clip":
427 c = Clip.get(id=clip_id)
428 elif item_type ==
"transition":
430 c = Transition.get(id=clip_id)
431 elif item_type ==
"effect":
433 c = Effect.get(id=clip_id)
437 if property_key
in c.data:
438 log.info(
"value updated: %s" % c.data)
441 if property_type !=
"reader" and type(c.data[property_key]) == dict:
445 point_to_delete =
None
446 for point
in c.data[property_key][
"Points"]:
447 log.info(
"looping points: co.X = %s" % point[
"co"][
"X"])
448 if interpolation == -1
and point[
"co"][
"X"] == self.
frame_number:
453 if new_value !=
None:
454 point[
"co"][
"Y"] = float(new_value)
455 log.info(
"updating point: co.X = %s to value: %s" % (point[
"co"][
"X"], float(new_value)))
457 point_to_delete = point
460 elif interpolation > -1
and point[
"co"][
"X"] == previous_point_x:
464 point[
"interpolation"] = interpolation
465 if interpolation == 0:
466 point[
"handle_right"] = point.get(
"handle_right")
or {
"Y": 0.0,
"X": 0.0}
467 point[
"handle_right"][
"X"] = interpolation_details[0]
468 point[
"handle_right"][
"Y"] = interpolation_details[1]
470 log.info(
"updating interpolation mode point: co.X = %s to %s" % (point[
"co"][
"X"], interpolation))
471 log.info(
"use interpolation preset: %s" % str(interpolation_details))
473 elif interpolation > -1
and point[
"co"][
"X"] == closest_point_x:
477 point[
"interpolation"] = interpolation
478 if interpolation == 0:
479 point[
"handle_left"] = point.get(
"handle_left")
or {
"Y": 0.0,
"X": 0.0}
480 point[
"handle_left"][
"X"] = interpolation_details[2]
481 point[
"handle_left"][
"Y"] = interpolation_details[3]
483 log.info(
"updating interpolation mode point: co.X = %s to %s" % (point[
"co"][
"X"], interpolation))
484 log.info(
"use interpolation preset: %s" % str(interpolation_details))
489 log.info(
"Found point to delete at X=%s" % point_to_delete[
"co"][
"X"])
490 c.data[property_key][
"Points"].remove(point_to_delete)
493 elif not found_point
and new_value !=
None:
495 log.info(
"Created new point at X=%s" % self.
frame_number)
496 c.data[property_key][
"Points"].append({
'co': {
'X': self.
frame_number,
'Y': new_value},
'interpolation': 1})
500 if property_type ==
"int":
503 c.data[property_key] = int(new_value)
505 elif property_type ==
"float":
508 c.data[property_key] = new_value
510 elif property_type ==
"bool":
513 c.data[property_key] = bool(new_value)
515 elif property_type ==
"string":
518 c.data[property_key] = str(new_value)
520 elif property_type ==
"reader":
526 clip_object = openshot.Clip(value)
528 c.data[property_key] = json.loads(clip_object.Reader().Json())
532 log.info(
'Failed to load %s into Clip object for reader property' % value)
535 c.data = {property_key: c.data.get(property_key)}
543 get_app().window.refreshFrameSignal.emit()
546 self.parent.clearSelection()
549 log.info(
"updating clip properties model.")
554 self.update_timer.stop()
566 raw_properties = json.loads(c.PropertiesJSON(self.
frame_number))
567 all_properties = OrderedDict(sorted(raw_properties.items(), key=
lambda x: x[1][
'name']))
568 log.info(
"Getting properties for frame %s: %s" % (self.
frame_number, str(all_properties)))
585 self.model.setHorizontalHeaderLabels([_(
"Property"), _(
"Value")])
589 for property
in all_properties.items():
590 label = property[1][
"name"]
592 value = property[1][
"value"]
593 type = property[1][
"type"]
594 memo = property[1][
"memo"]
595 readonly = property[1][
"readonly"]
596 keyframe = property[1][
"keyframe"]
597 points = property[1][
"points"]
598 interpolation = property[1][
"interpolation"]
599 closest_point_x = property[1][
"closest_point_x"]
600 choices = property[1][
"choices"]
603 transparency_label = _(
"Transparency")
605 selected_choice =
None
607 selected_choice = [c
for c
in choices
if c[
"selected"] ==
True][0][
"name"]
610 if filter
and filter.lower()
not in name.lower():
622 col = QStandardItem(
"Property")
623 col.setText(_(label))
624 col.setData(property)
625 if keyframe
and points > 1:
626 col.setBackground(QColor(
"green"))
628 col.setBackground(QColor(42, 130, 218))
630 col.setFlags(Qt.ItemIsEnabled)
632 col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable)
636 col = QStandardItem(
"Value")
638 col.setText(_(selected_choice))
639 elif type ==
"string":
645 col.setText(_(
"True"))
647 col.setText(_(
"False"))
648 elif type ==
"color":
651 elif type ==
"reader":
652 reader_json = json.loads(memo
or "{}")
653 reader_path = reader_json.get(
"path",
"/")
654 (dirName, fileName) = os.path.split(reader_path)
655 col.setText(fileName)
658 col.setText(
"%d" % value)
661 col.setText(QLocale().system().toString(float(value),
"f", precision=2))
662 col.setData((c.Id(), item_type))
665 my_icon = QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % interpolation))
666 col.setData(my_icon, Qt.DecorationRole)
670 col.setBackground(QColor(
"green"))
672 col.setBackground(QColor(42, 130, 218))
676 red = property[1][
"red"][
"value"]
677 green = property[1][
"green"][
"value"]
678 blue = property[1][
"blue"][
"value"]
679 col.setBackground(QColor(red, green, blue))
681 if readonly
or type ==
"color" or choices:
682 col.setFlags(Qt.ItemIsEnabled)
684 col.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsUserCheckable | Qt.ItemIsEditable)
688 self.model.appendRow(row)
693 col = self.
items[name][
"row"][0]
694 col.setData(property)
697 if keyframe
and points > 1:
698 col.setBackground(QColor(
"green"))
700 col.setBackground(QColor(42, 130, 218))
702 col.setBackground(QStandardItem(
"Empty").background())
708 col = self.
items[name][
"row"][1]
710 col.setText(_(selected_choice))
711 elif type ==
"string":
717 col.setText(_(
"True"))
719 col.setText(_(
"False"))
720 elif type ==
"color":
724 col.setText(
"%d" % value)
725 elif type ==
"reader":
726 reader_json = json.loads(property[1].get(
"memo",
"{}"))
727 reader_path = reader_json.get(
"path",
"/")
728 (dirName, fileName) = os.path.split(reader_path)
729 col.setText(
"%s" % fileName)
732 col.setText(QLocale().system().toString(float(value),
"f", precision=2))
736 my_icon = QPixmap(os.path.join(info.IMAGES_PATH,
"keyframe-%s.png" % interpolation))
737 col.setData(my_icon, Qt.DecorationRole)
741 col.setBackground(QColor(
"green"))
743 col.setBackground(QColor(42, 130, 218))
747 col.setBackground(QStandardItem(
"Empty").background())
751 col.setData(my_icon, Qt.DecorationRole)
755 red = property[1][
"red"][
"value"]
756 green = property[1][
"green"][
"value"]
757 blue = property[1][
"blue"][
"value"]
758 col.setBackground(QColor(red, green, blue))
764 self.
items[name] = {
"row": row,
"property": property}
777 self.model.setHorizontalHeaderLabels([_(
"Property"), _(
"Value")])
799 self.model.setColumnCount(2)
804 self.update_timer.setInterval(100)
806 self.update_timer.stop()
814 get_app().updates.add_listener(self)
def get_app
Returns the current QApplication instance of OpenShot.
def value_updated
Table cell change event - also handles context menu to update interpolation value.
def remove_keyframe
Remove an existing keyframe (if any)
def color_update
Insert/Update a color keyframe for the selected row.
Interface for classes that listen for changes (insert, update, and delete).