def getMenu(self): # Build menu for selection button menu = QMenu(self) # Get translation object _ = get_app()._tr # Look up item for more info if self.item_type == "clip": self.item_name = Clip.get(id=self.item_id).title() elif self.item_type == "transition": self.item_name = Transition.get(id=self.item_id).title() elif self.item_type == "effect": self.item_name = Effect.get(id=self.item_id).title() # Add selected clips for item_id in get_app().window.selected_clips: clip = Clip.get(id=item_id) item_name = clip.title() item_icon = QIcon(QPixmap(clip.data.get('image'))) action = menu.addAction(item_name) action.setIcon(item_icon) action.setData({'item_id':item_id, 'item_type':'clip'}) action.triggered.connect(self.Action_Triggered) # Add effects for these clips (if any) for effect in clip.data.get('effects'): item_name = Effect.get(id=effect.get('id')).title() item_icon = QIcon(QPixmap(os.path.join(info.PATH, "effects", "icons", "%s.png" % effect.get('class_name').lower()))) action = menu.addAction(' > %s' % _(item_name)) action.setIcon(item_icon) action.setData({'item_id': effect.get('id'), 'item_type': 'effect'}) action.triggered.connect(self.Action_Triggered) # Add selected transitions for item_id in get_app().window.selected_transitions: trans = Transition.get(id=item_id) item_name = _(trans.title()) item_icon = QIcon(QPixmap(trans.data.get('reader',{}).get('path'))) action = menu.addAction(_(item_name)) action.setIcon(item_icon) action.setData({'item_id': item_id, 'item_type': 'transition'}) action.triggered.connect(self.Action_Triggered) # Add selected effects for item_id in get_app().window.selected_effects: effect = Effect.get(id=item_id) item_name = _(effect.title()) item_icon = QIcon(QPixmap(os.path.join(info.PATH, "effects", "icons", "%s.png" % effect.data.get('class_name').lower()))) action = menu.addAction(_(item_name)) action.setIcon(item_icon) action.setData({'item_id': item_id, 'item_type': 'effect'}) action.triggered.connect(self.Action_Triggered) # Return the menu object return menu
def update_frame(self, frame_number, reload_model=True): # Check for a selected clip if self.selected: clip, item_type = self.selected[0] if not clip: # Ignore null clip return # If effect, find the position of the parent clip if item_type == "effect": # find parent clip effect = Effect.get(id=clip.Id()) if not effect: # Invalid effect return parent_clip_id = effect.parent["id"] # Find this clip object clips = get_app().window.timeline_sync.timeline.Clips() for c in clips: if c.Id() == parent_clip_id: # Override the selected clip object (so the effect gets the correct starting position) clip = c break # Get FPS from project fps = get_app().project.get("fps") fps_float = float(fps["num"]) / float(fps["den"]) # Requested time requested_time = float(frame_number - 1) / fps_float # Determine the frame needed for this clip (based on the position on the timeline) time_diff = (requested_time - clip.Position()) + clip.Start() self.frame_number = round(time_diff * fps_float) + 1 # Calculate biggest and smallest possible frames min_frame_number = round((clip.Start() * fps_float)) + 1 max_frame_number = round((clip.End() * fps_float)) + 1 # Adjust frame number if out of range if self.frame_number < min_frame_number: self.frame_number = min_frame_number if self.frame_number > max_frame_number: self.frame_number = max_frame_number log.info("Update frame to %s" % self.frame_number) # Update the model data if reload_model: self.update_model(get_app().window.txtPropertyFilter.text())
def update_frame(self, frame_number, reload_model=True): # Check for a selected clip if self.selected: clip, item_type = self.selected[0] if not clip: # Ignore null clip return # If effect, find the position of the parent clip if item_type == "effect": # find parent clip effect = Effect.get(id=clip.Id()) if not effect: # Invalid effect return parent_clip_id = effect.parent["id"] # Find this clip object clips = get_app().window.timeline_sync.timeline.Clips() for c in clips: if c.Id() == parent_clip_id: # Override the selected clip object (so the effect gets the correct starting position) clip = c break # Get FPS from project fps = get_app().project.get(["fps"]) fps_float = float(fps["num"]) / float(fps["den"]) # Requested time requested_time = float(frame_number - 1) / fps_float # Determine the frame needed for this clip (based on the position on the timeline) time_diff = (requested_time - clip.Position()) + clip.Start() self.frame_number = round(time_diff * fps_float) + 1 # Calculate biggest and smallest possible frames min_frame_number = round((clip.Start() * fps_float)) + 1 max_frame_number = round((clip.End() * fps_float)) + 1 # Adjust frame number if out of range if self.frame_number < min_frame_number: self.frame_number = min_frame_number if self.frame_number > max_frame_number: self.frame_number = max_frame_number log.info("Update frame to %s" % self.frame_number) # Update the model data if reload_model: self.update_model(get_app().window.txtPropertyFilter.text())
def update_item_timeout(self): # Get the next item id, and type self.item_id = self.next_item_id self.item_type = self.next_item_type self.item_name = None self.item_icon = None # Stop timer self.update_timer.stop() # Get translation object _ = get_app()._tr # Look up item for more info if self.item_type == "clip": clip = Clip.get(id=self.item_id) if clip: self.item_name = clip.title() self.item_icon = QIcon(QPixmap(clip.data.get('image'))) elif self.item_type == "transition": trans = Transition.get(id=self.item_id) if trans: self.item_name = _(trans.title()) self.item_icon = QIcon( QPixmap(trans.data.get('reader', {}).get('path'))) elif self.item_type == "effect": effect = Effect.get(id=self.item_id) if effect: self.item_name = _(effect.title()) self.item_icon = QIcon( QPixmap( os.path.join( info.PATH, "effects", "icons", "%s.png" % effect.data.get('class_name').lower()))) # Truncate long text if self.item_name and len(self.item_name) > 25: self.item_name = "%s..." % self.item_name[:22] # Set label if self.item_id: self.lblSelection.setText("<strong>%s</strong>" % _("Selection:")) self.btnSelectionName.setText(self.item_name) self.btnSelectionName.setVisible(True) if self.item_icon: self.btnSelectionName.setIcon(self.item_icon) else: self.lblSelection.setText("<strong>%s</strong>" % _("No Selection")) self.btnSelectionName.setVisible(False) # Set the menu on the button self.btnSelectionName.setMenu(self.getMenu())
def update_item_timeout(self): # Get the next item id, and type self.item_id = self.next_item_id self.item_type = self.next_item_type self.item_name = None self.item_icon = None # Stop timer self.update_timer.stop() # Get translation object _ = get_app()._tr # Look up item for more info if self.item_type == "clip": clip = Clip.get(id=self.item_id) self.item_name = clip.title() self.item_icon = QIcon(QPixmap(clip.data.get('image'))) elif self.item_type == "transition": trans = Transition.get(id=self.item_id) self.item_name = _(trans.title()) self.item_icon = QIcon(QPixmap(trans.data.get('reader', {}).get('path'))) elif self.item_type == "effect": effect = Effect.get(id=self.item_id) self.item_name = _(effect.title()) self.item_icon = QIcon(QPixmap(os.path.join(info.PATH, "effects", "icons", "%s.png" % effect.data.get('class_name').lower()))) # Truncate long text if self.item_name and len(self.item_name) > 25: self.item_name = "%s..." % self.item_name[:22] # Set label if self.item_id: self.lblSelection.setText("<strong>%s</strong>" % _("Selection:")) self.btnSelectionName.setText(self.item_name) self.btnSelectionName.setVisible(True) if self.item_icon: self.btnSelectionName.setIcon(self.item_icon) else: self.lblSelection.setText("<strong>%s</strong>" % _("No Selection")) self.btnSelectionName.setVisible(False) # Set the menu on the button self.btnSelectionName.setMenu(self.getMenu())
def value_updated(self, item, interpolation=-1, value=None, interpolation_details=[]): """ Table cell change event - also handles context menu to update interpolation value """ if self.ignore_update_signal: return # Get translation method _ = get_app()._tr # Determine what was changed property = self.model.item(item.row(), 0).data() property_name = property[1]["name"] closest_point_x = property[1]["closest_point_x"] previous_point_x = property[1]["previous_point_x"] property_type = property[1]["type"] property_key = property[0] clip_id, item_type = item.data() # Get value (if any) if item.text(): # Set and format value based on property type if value != None: # Override value new_value = value elif property_type == "string": # Use string value new_value = item.text() elif property_type == "bool": # Use boolean value if item.text() == _("False"): new_value = False else: new_value = True elif property_type == "int": # Use int value new_value = QLocale().system().toInt(item.text())[0] else: # Use decimal value new_value = QLocale().system().toFloat(item.text())[0] else: new_value = None 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)) # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Update clip attribute if property_key in c.data: log.info("value updated: %s" % c.data) # Check the type of property (some are keyframe, and some are not) if type(c.data[property_key]) == dict: # Keyframe # Loop through points, find a matching points on this frame found_point = False point_to_delete = None for point in c.data[property_key]["Points"]: log.info("looping points: co.X = %s" % point["co"]["X"]) if interpolation == -1 and point["co"][ "X"] == self.frame_number: # Found point, Update value found_point = True clip_updated = True # Update or delete point if new_value != None: point["co"]["Y"] = float(new_value) log.info( "updating point: co.X = %s to value: %s" % (point["co"]["X"], float(new_value))) else: point_to_delete = point break elif interpolation > -1 and point["co"][ "X"] == previous_point_x: # Only update interpolation type (and the LEFT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_right"] = point.get( "handle_right") or { "Y": 0.0, "X": 0.0 } point["handle_right"][ "X"] = interpolation_details[0] point["handle_right"][ "Y"] = interpolation_details[1] log.info( "updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) log.info("use interpolation preset: %s" % str(interpolation_details)) elif interpolation > -1 and point["co"][ "X"] == closest_point_x: # Only update interpolation type (and the RIGHT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_left"] = point.get( "handle_left") or { "Y": 0.0, "X": 0.0 } point["handle_left"][ "X"] = interpolation_details[2] point["handle_left"][ "Y"] = interpolation_details[3] log.info( "updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) log.info("use interpolation preset: %s" % str(interpolation_details)) # Delete point (if needed) if point_to_delete: clip_updated = True log.info("Found point to delete at X=%s" % point_to_delete["co"]["X"]) c.data[property_key]["Points"].remove(point_to_delete) # Create new point (if needed) elif not found_point and new_value != None: clip_updated = True log.info("Created new point at X=%s" % self.frame_number) c.data[property_key]["Points"].append({ 'co': { 'X': self.frame_number, 'Y': new_value }, 'interpolation': 1 }) elif property_type == "int": # Integer clip_updated = True c.data[property_key] = int(new_value) elif property_type == "float": # Float clip_updated = True c.data[property_key] = new_value elif property_type == "bool": # Boolean clip_updated = True c.data[property_key] = bool(new_value) elif property_type == "string": # String clip_updated = True c.data[property_key] = str(new_value) # Reduce # of clip properties we are saving (performance boost) c.data = {property_key: c.data.get(property_key)} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.refreshFrameSignal.emit() # Clear selection self.parent.clearSelection()
def color_update(self, item, new_color, interpolation=-1, interpolation_details=[]): """Insert/Update a color keyframe for the selected row""" # Determine what was changed property = self.model.item(item.row(), 0).data() property_type = property[1]["type"] closest_point_x = property[1]["closest_point_x"] previous_point_x = property[1]["previous_point_x"] property_key = property[0] clip_id, item_type = item.data() if property_type == "color": # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Update clip attribute if property_key in c.data: log.info("color update: %s" % c.data) # Loop through each keyframe (red, blue, and green) for color, new_value in [("red", new_color.red()), ("blue", new_color.blue()), ("green", new_color.green())]: # Keyframe # Loop through points, find a matching points on this frame found_point = False for point in c.data[property_key][color]["Points"]: log.info("looping points: co.X = %s" % point["co"]["X"]) if interpolation == -1 and point["co"][ "X"] == self.frame_number: # Found point, Update value found_point = True clip_updated = True # Update point point["co"]["Y"] = new_value log.info( "updating point: co.X = %s to value: %s" % (point["co"]["X"], float(new_value))) break elif interpolation > -1 and point["co"][ "X"] == previous_point_x: # Only update interpolation type (and the LEFT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_right"] = point.get( "handle_right") or { "Y": 0.0, "X": 0.0 } point["handle_right"][ "X"] = interpolation_details[0] point["handle_right"][ "Y"] = interpolation_details[1] log.info( "updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) log.info("use interpolation preset: %s" % str(interpolation_details)) elif interpolation > -1 and point["co"][ "X"] == closest_point_x: # Only update interpolation type (and the RIGHT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_left"] = point.get( "handle_left") or { "Y": 0.0, "X": 0.0 } point["handle_left"][ "X"] = interpolation_details[2] point["handle_left"][ "Y"] = interpolation_details[3] log.info( "updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) log.info("use interpolation preset: %s" % str(interpolation_details)) # Create new point (if needed) if not found_point: clip_updated = True log.info("Created new point at X=%s" % self.frame_number) c.data[property_key][color]["Points"].append({ 'co': { 'X': self.frame_number, 'Y': new_value }, 'interpolation': 1 }) # Reduce # of clip properties we are saving (performance boost) c.data = {property_key: c.data[property_key]} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.refreshFrameSignal.emit() # Clear selection self.parent.clearSelection()
def remove_keyframe(self, item): """Remove an existing keyframe (if any)""" # Determine what was changed property = self.model.item(item.row(), 0).data() property_name = property[1]["name"] property_type = property[1]["type"] closest_point_x = property[1]["closest_point_x"] property_type = property[1]["type"] property_key = property[0] clip_id, item_type = item.data() # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Update clip attribute if property_key in c.data: log.info("remove keyframe: %s" % c.data) # Determine type of keyframe (normal or color) keyframe_list = [] if property_type == "color": keyframe_list = [ c.data[property_key]["red"], c.data[property_key]["blue"], c.data[property_key]["green"] ] else: keyframe_list = [c.data[property_key]] # Loop through each keyframe (red, blue, and green) for keyframe in keyframe_list: # Keyframe # Loop through points, find a matching points on this frame closest_point = None point_to_delete = None for point in keyframe["Points"]: if point["co"]["X"] == self.frame_number: # Found point, Update value clip_updated = True point_to_delete = point break if point["co"]["X"] == closest_point_x: closest_point = point # If no point found, use closest point x if not point_to_delete: point_to_delete = closest_point # Delete point (if needed) if point_to_delete: clip_updated = True log.info("Found point to delete at X=%s" % point_to_delete["co"]["X"]) keyframe["Points"].remove(point_to_delete) # Reduce # of clip properties we are saving (performance boost) c.data = {property_key: c.data[property_key]} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.refreshFrameSignal.emit() # Clear selection self.parent.clearSelection()
def mouseMoveEvent(self, event): # Get data model and selection model = self.clip_properties_model.model # Do not change selected row during mouse move if self.lock_selection and self.prev_row: row = self.prev_row else: row = self.indexAt(event.pos()).row() self.prev_row = row self.lock_selection = True if row is None: return if model.item(row, 0): self.selected_label = model.item(row, 0) self.selected_item = model.item(row, 1) # Is the user dragging on the value column if self.selected_label and self.selected_item: # Get the position of the cursor and % value value_column_x = self.columnViewportPosition(1) cursor_value = event.x() - value_column_x cursor_value_percent = cursor_value / self.columnWidth(1) try: cur_property = self.selected_label.data() except Exception: # If item is deleted during this drag... an exception can occur # Just ignore, since this is harmless return property_key = cur_property[0] property_name = cur_property[1]["name"] property_type = cur_property[1]["type"] property_max = cur_property[1]["max"] property_min = cur_property[1]["min"] readonly = cur_property[1]["readonly"] item_id, item_type = self.selected_item.data() # Bail if readonly if readonly: return # Get the original data of this item (prior to any updates, for the undo/redo system) if not self.original_data: # Ignore undo/redo history temporarily (to avoid a huge pile of undo/redo history) get_app().updates.ignore_history = True # Find this clip c = None if item_type == "clip": # Get clip object c = Clip.get(id=item_id) elif item_type == "transition": # Get transition object c = Transition.get(id=item_id) elif item_type == "effect": # Get effect object c = Effect.get(id=item_id) if c: if property_key in c.data: # Grab the original data for this item/property self.original_data = c.data # For numeric values, apply percentage within parameter's allowable range if property_type in ["float", "int"] and property_name != "Track": if self.previous_x == -1: # Start tracking movement (init diff_length and previous_x) self.diff_length = 10 self.previous_x = event.x() # Calculate # of pixels dragged drag_diff = self.previous_x - event.x() # update previous x self.previous_x = event.x() # Ignore small initial movements if abs(drag_diff) < self.diff_length: # Lower threshold to 0 incrementally, to guarantee it'll eventually be exceeded self.diff_length = max(0, self.diff_length - 1) return # Compute size of property's possible values range min_max_range = float(property_max) - float(property_min) if min_max_range < 1000.0: # Small range - use cursor to calculate new value as percentage of total range self.new_value = property_min + (min_max_range * cursor_value_percent) else: # range is unreasonably long (such as position, start, end, etc.... which can be huge #'s) # Get the current value and apply fixed adjustments in response to motion self.new_value = QLocale().system().toDouble( self.selected_item.text())[0] if drag_diff > 0: # Move to the left by a small amount self.new_value -= 0.50 elif drag_diff < 0: # Move to the right by a small amount self.new_value += 0.50 # Clamp value between min and max (just incase user drags too big) self.new_value = max(property_min, self.new_value) self.new_value = min(property_max, self.new_value) # Update value of this property self.clip_properties_model.value_updated( self.selected_item, -1, self.new_value) # Repaint self.viewport().update()
def mouseMoveEvent(self, event): # Get data model and selection model = self.clip_properties_model.model row = self.indexAt(event.pos()).row() column = self.indexAt(event.pos()).column() if model.item(row, 0): self.selected_label = model.item(row, 0) self.selected_item = model.item(row, 1) # Is the user dragging on the value column if self.selected_label and self.selected_item: frame_number = self.clip_properties_model.frame_number # Get the position of the cursor and % value value_column_x = self.columnViewportPosition(1) value_column_y = value_column_x + self.columnWidth(1) cursor_value = event.x() - value_column_x cursor_value_percent = cursor_value / self.columnWidth(1) try: property = self.selected_label.data() except Exception as ex: # If item is deleted during this drag... an exception can occur # Just ignore, since this is harmless return property_key = property[0] property_name = property[1]["name"] property_type = property[1]["type"] property_max = property[1]["max"] property_min = property[1]["min"] property_value = property[1]["value"] readonly = property[1]["readonly"] item_id, item_type = self.selected_item.data() # Bail if readonly if readonly: return # Get the original data of this item (prior to any updates, for the undo/redo system) if not self.original_data: # Ignore undo/redo history temporarily (to avoid a huge pile of undo/redo history) get_app().updates.ignore_history = True # Find this clip c = None if item_type == "clip": # Get clip object c = Clip.get(id=item_id) elif item_type == "transition": # Get transition object c = Transition.get(id=item_id) elif item_type == "effect": # Get effect object c = Effect.get(id=item_id) if c: if property_key in c.data: # Grab the original data for this item/property self.original_data = c.data # Calculate percentage value if property_type in ["float", "int"]: min_max_range = float(property_max) - float(property_min) # Determine if range is unreasonably long (such as position, start, end, etc.... which can be huge #'s) if min_max_range > 1000.0: # Get the current value self.new_value = QLocale().system().toDouble( self.selected_item.text())[0] # Huge range - increment / decrement slowly if self.previous_x == -1: # init previous_x for the first time self.previous_x = event.x() # calculate # of pixels dragged drag_diff = self.previous_x - event.x() if drag_diff > 0: # Move to the left by a small amount self.new_value -= 0.50 elif drag_diff < 0: # Move to the right by a small amount self.new_value += 0.50 # update previous x self.previous_x = event.x() else: # Small range - use cursor % to calculate new value self.new_value = property_min + (min_max_range * cursor_value_percent) # Clamp value between min and max (just incase user drags too big) self.new_value = max(property_min, self.new_value) self.new_value = min(property_max, self.new_value) # Update value of this property self.clip_properties_model.value_updated( self.selected_item, -1, self.new_value) # Repaint self.viewport().update()
def mouseMoveEvent(self, event): # Get data model and selection model = self.clip_properties_model.model row = self.indexAt(event.pos()).row() column = self.indexAt(event.pos()).column() if model.item(row, 0): self.selected_label = model.item(row, 0) self.selected_item = model.item(row, 1) # Is the user dragging on the value column if self.selected_label and self.selected_item: frame_number = self.clip_properties_model.frame_number # Get the position of the cursor and % value value_column_x = self.columnViewportPosition(1) value_column_y = value_column_x + self.columnWidth(1) cursor_value = event.x() - value_column_x cursor_value_percent = cursor_value / self.columnWidth(1) property = self.selected_label.data() property_key = property[0] property_name = property[1]["name"] property_type = property[1]["type"] property_max = property[1]["max"] property_min = property[1]["min"] property_value = property[1]["value"] readonly = property[1]["readonly"] item_id, item_type = self.selected_item.data() # Bail if readonly if readonly: return # Get the original data of this item (prior to any updates, for the undo/redo system) if not self.original_data: # Ignore undo/redo history temporarily (to avoid a huge pile of undo/redo history) get_app().updates.ignore_history = True # Find this clip c = None if item_type == "clip": # Get clip object c = Clip.get(id=item_id) elif item_type == "transition": # Get transition object c = Transition.get(id=item_id) elif item_type == "effect": # Get effect object c = Effect.get(id=item_id) if c: if property_key in c.data: # Grab the original data for this item/property self.original_data = c.data # Calculate percentage value if property_type in ["float", "int"]: min_max_range = float(property_max) - float(property_min) # Determine if range is unreasonably long (such as position, start, end, etc.... which can be huge #'s) if min_max_range > 1000.0: # Get the current value self.new_value = QLocale().system().toDouble(self.selected_item.text())[0] # Huge range - increment / decrement slowly if self.previous_x == -1: # init previous_x for the first time self.previous_x = event.x() # calculate # of pixels dragged drag_diff = self.previous_x - event.x() if drag_diff > 0: # Move to the left by a small amount self.new_value -= 0.50 elif drag_diff < 0: # Move to the right by a small amount self.new_value += 0.50 # update previous x self.previous_x = event.x() else: # Small range - use cursor % to calculate new value self.new_value = property_min + (min_max_range * cursor_value_percent) # Clamp value between min and max (just incase user drags too big) self.new_value = max(property_min, self.new_value) self.new_value = min(property_max, self.new_value) # Update value of this property self.clip_properties_model.value_updated(self.selected_item, -1, self.new_value) # Repaint self.viewport().update()
def value_updated(self, item, interpolation=-1, value=None): """ Table cell change event - also handles context menu to update interpolation value """ if self.ignore_update_signal: return # Get translation method _ = get_app()._tr # Determine what was changed property = self.model.item(item.row(), 0).data() property_name = property[1]["name"] closest_point_x = property[1]["closest_point_x"] property_type = property[1]["type"] property_key = property[0] clip_id, item_type = item.data() # Get value (if any) if item.text(): # Set and format value based on property type if value != None: # Override value new_value = value elif property_type == "string": # Use string value new_value = item.text() elif property_type == "bool": # Use boolean value if item.text() == _("False"): new_value = False else: new_value = True else: # Use numeric value new_value = QLocale().system().toFloat(item.text())[0] else: new_value = None 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)) # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Update clip attribute if property_key in c.data: log.info(c.data) # Check the type of property (some are keyframe, and some are not) if type(c.data[property_key]) == dict: # Keyframe # Loop through points, find a matching points on this frame found_point = False point_to_delete = None for point in c.data[property_key]["Points"]: log.info("looping points: co.X = %s" % point["co"]["X"]) if interpolation == -1 and point["co"]["X"] == self.frame_number: # Found point, Update value found_point = True clip_updated = True # Update or delete point if new_value != None: point["co"]["Y"] = float(new_value) log.info("updating point: co.X = %s to value: %s" % (point["co"]["X"], float(new_value))) else: point_to_delete = point break elif interpolation > -1 and point["co"]["X"] == closest_point_x: # Only update interpolation type found_point = True clip_updated = True point["interpolation"] = interpolation log.info("updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) break # Delete point (if needed) if point_to_delete: clip_updated = True log.info("Found point to delete at X=%s" % point_to_delete["co"]["X"]) c.data[property_key]["Points"].remove(point_to_delete) # Create new point (if needed) elif not found_point and new_value != None: clip_updated = True log.info("Created new point at X=%s" % self.frame_number) c.data[property_key]["Points"].append({'co': {'X': self.frame_number, 'Y': new_value}, 'interpolation': 1}) elif property_type == "int": # Integer clip_updated = True c.data[property_key] = int(new_value) elif property_type == "float": # Float clip_updated = True c.data[property_key] = new_value elif property_type == "bool": # Boolean clip_updated = True c.data[property_key] = bool(new_value) elif property_type == "string": # String clip_updated = True c.data[property_key] = str(new_value) # Reduce # of clip properties we are saving (performance boost) c.data = {property_key: c.data[property_key]} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.preview_thread.refreshFrame() # Clear selection self.parent.clearSelection()
def color_update(self, item, new_color, interpolation=-1): """Insert/Update a color keyframe for the selected row""" # Determine what was changed property = self.model.item(item.row(), 0).data() property_type = property[1]["type"] closest_point_x = property[1]["closest_point_x"] property_key = property[0] clip_id, item_type = item.data() if property_type == "color": # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Update clip attribute if property_key in c.data: log.info(c.data) # Loop through each keyframe (red, blue, and green) for color, new_value in [("red", new_color.red()), ("blue", new_color.blue()), ("green", new_color.green())]: # Keyframe # Loop through points, find a matching points on this frame found_point = False for point in c.data[property_key][color]["Points"]: log.info("looping points: co.X = %s" % point["co"]["X"]) if interpolation == -1 and point["co"]["X"] == self.frame_number: # Found point, Update value found_point = True clip_updated = True # Update point point["co"]["Y"] = new_value log.info("updating point: co.X = %s to value: %s" % (point["co"]["X"], float(new_value))) break elif interpolation > -1 and point["co"]["X"] == closest_point_x: # Only update interpolation type found_point = True clip_updated = True point["interpolation"] = interpolation log.info("updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) break # Create new point (if needed) if not found_point: clip_updated = True log.info("Created new point at X=%s" % self.frame_number) c.data[property_key][color]["Points"].append({'co': {'X': self.frame_number, 'Y': new_value}, 'interpolation': 1}) # Reduce # of clip properties we are saving (performance boost) c.data = {property_key: c.data[property_key]} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.preview_thread.refreshFrame() # Clear selection self.parent.clearSelection()
def remove_keyframe(self, item): """Remove an existing keyframe (if any)""" # Determine what was changed property = self.model.item(item.row(), 0).data() property_name = property[1]["name"] property_type = property[1]["type"] closest_point_x = property[1]["closest_point_x"] property_type = property[1]["type"] property_key = property[0] clip_id, item_type = item.data() # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Update clip attribute if property_key in c.data: log.info(c.data) # Determine type of keyframe (normal or color) keyframe_list = [] if property_type == "color": keyframe_list = [c.data[property_key]["red"], c.data[property_key]["blue"], c.data[property_key]["green"]] else: keyframe_list = [c.data[property_key]] # Loop through each keyframe (red, blue, and green) for keyframe in keyframe_list: # Keyframe # Loop through points, find a matching points on this frame closest_point = None point_to_delete = None for point in keyframe["Points"]: if point["co"]["X"] == self.frame_number: # Found point, Update value clip_updated = True point_to_delete = point break if point["co"]["X"] == closest_point_x: closest_point = point # If no point found, use closest point x if not point_to_delete: point_to_delete = closest_point # Delete point (if needed) if point_to_delete: clip_updated = True log.info("Found point to delete at X=%s" % point_to_delete["co"]["X"]) keyframe["Points"].remove(point_to_delete) # Reduce # of clip properties we are saving (performance boost) c.data = {property_key: c.data[property_key]} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.preview_thread.refreshFrame() # Clear selection self.parent.clearSelection()
def value_updated(self, item, interpolation=-1, value=None, interpolation_details=[]): """ Table cell change event - also handles context menu to update interpolation value """ if self.ignore_update_signal: return # Get translation method _ = get_app()._tr # Determine what was changed property = self.model.item(item.row(), 0).data() closest_point_x = property[1]["closest_point_x"] previous_point_x = property[1]["previous_point_x"] property_type = property[1]["type"] property_key = property[0] object_id = property[1]["object_id"] clip_id, item_type = item.data() # Get value (if any) if item.text(): # Set and format value based on property type if value is not None: # Override value new_value = value elif property_type == "string": # Use string value new_value = item.text() elif property_type == "bool": # Use boolean value if item.text() == _("False"): new_value = False else: new_value = True elif property_type == "int": # Use int value new_value = QLocale().system().toInt(item.text())[0] else: # Use decimal value new_value = QLocale().system().toFloat(item.text())[0] else: new_value = None 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)) # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Create reference clip_data = c.data if object_id: clip_data = c.data.get('objects').get(object_id) # Update clip attribute if property_key in clip_data: log_id = "{}/{}".format(clip_id, object_id) if object_id else clip_id log.debug("%s: update property %s. %s", log_id, property_key, clip_data.get(property_key)) # Check the type of property (some are keyframe, and some are not) if property_type != "reader" and type( clip_data[property_key]) == dict: # Keyframe # Loop through points, find a matching points on this frame found_point = False point_to_delete = None for point in clip_data[property_key].get('Points', []): log.debug("looping points: co.X = %s" % point["co"]["X"]) if interpolation == -1 and point["co"][ "X"] == self.frame_number: # Found point, Update value found_point = True clip_updated = True # Update or delete point if new_value is not None: point["co"]["Y"] = float(new_value) log.debug( "updating point: co.X = %d to value: %.3f", point["co"]["X"], float(new_value)) else: point_to_delete = point break elif interpolation > -1 and point["co"][ "X"] == previous_point_x: # Only update interpolation type (and the LEFT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_right"] = point.get( "handle_right") or { "Y": 0.0, "X": 0.0 } point["handle_right"][ "X"] = interpolation_details[0] point["handle_right"][ "Y"] = interpolation_details[1] log.debug( "updating interpolation mode point: co.X = %d to %d", point["co"]["X"], interpolation) log.debug("use interpolation preset: %s", str(interpolation_details)) elif interpolation > -1 and point["co"][ "X"] == closest_point_x: # Only update interpolation type (and the RIGHT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_left"] = point.get( "handle_left") or { "Y": 0.0, "X": 0.0 } point["handle_left"][ "X"] = interpolation_details[2] point["handle_left"][ "Y"] = interpolation_details[3] log.debug( "updating interpolation mode point: co.X = %d to %d", point["co"]["X"], interpolation) log.debug("use interpolation preset: %s", str(interpolation_details)) # Delete point (if needed) if point_to_delete: clip_updated = True log.debug("Found point to delete at X=%s" % point_to_delete["co"]["X"]) clip_data[property_key]["Points"].remove( point_to_delete) # Create new point (if needed) elif not found_point and new_value is not None: clip_updated = True log.debug("Created new point at X=%d", self.frame_number) clip_data[property_key].setdefault( 'Points', []).append({ 'co': { 'X': self.frame_number, 'Y': new_value }, 'interpolation': 1 }) if not clip_updated: # If no keyframe was found, set a basic property if property_type == "int": clip_updated = True try: clip_data[property_key] = int(new_value) except Exception as ex: log.warn( 'Invalid Integer value passed to property: %s' % ex) elif property_type == "float": clip_updated = True try: clip_data[property_key] = float(new_value) except Exception as ex: log.warn('Invalid Float value passed to property: %s' % ex) elif property_type == "bool": clip_updated = True try: clip_data[property_key] = bool(new_value) except Exception as ex: log.warn( 'Invalid Boolean value passed to property: %s' % ex) elif property_type == "string": clip_updated = True try: clip_data[property_key] = str(new_value) except Exception as ex: log.warn( 'Invalid String value passed to property: %s' % ex) elif property_type in ["font", "caption"]: clip_updated = True try: clip_data[property_key] = str(new_value) except Exception as ex: log.warn( 'Invalid Font/Caption value passed to property: %s' % ex) elif property_type == "reader": # Transition clip_updated = True try: clip_object = openshot.Clip(value) clip_object.Open() clip_data[property_key] = json.loads( clip_object.Reader().Json()) clip_object.Close() clip_object = None except Exception as ex: log.warn( 'Invalid Reader value passed to property: %s (%s)' % (value, ex)) # Reduce # of clip properties we are saving (performance boost) clip_data = {property_key: clip_data.get(property_key)} if object_id: clip_data = {'objects': {object_id: clip_data}} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.refreshFrameSignal.emit() log.info("Item %s: changed %s to %s at frame %s (x: %s)" % (clip_id, property_key, new_value, self.frame_number, closest_point_x)) # Clear selection self.parent.clearSelection()
def value_updated(self, item, interpolation=-1, value=None, interpolation_details=[]): """ Table cell change event - also handles context menu to update interpolation value """ if self.ignore_update_signal: return # Get translation method _ = get_app()._tr # Determine what was changed property = self.model.item(item.row(), 0).data() property_name = property[1]["name"] closest_point_x = property[1]["closest_point_x"] previous_point_x = property[1]["previous_point_x"] property_type = property[1]["type"] property_key = property[0] clip_id, item_type = item.data() # Get value (if any) if item.text(): # Set and format value based on property type if value != None: # Override value new_value = value elif property_type == "string": # Use string value new_value = item.text() elif property_type == "bool": # Use boolean value if item.text() == _("False"): new_value = False else: new_value = True elif property_type == "int": # Use int value new_value = QLocale().system().toInt(item.text())[0] else: # Use decimal value new_value = QLocale().system().toFloat(item.text())[0] else: new_value = None 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)) # Find this clip c = None clip_updated = False if item_type == "clip": # Get clip object c = Clip.get(id=clip_id) elif item_type == "transition": # Get transition object c = Transition.get(id=clip_id) elif item_type == "effect": # Get effect object c = Effect.get(id=clip_id) if c: # Update clip attribute if property_key in c.data: log.info("value updated: %s" % c.data) # Check the type of property (some are keyframe, and some are not) if property_type != "reader" and type(c.data[property_key]) == dict: # Keyframe # Loop through points, find a matching points on this frame found_point = False point_to_delete = None for point in c.data[property_key]["Points"]: log.info("looping points: co.X = %s" % point["co"]["X"]) if interpolation == -1 and point["co"]["X"] == self.frame_number: # Found point, Update value found_point = True clip_updated = True # Update or delete point if new_value != None: point["co"]["Y"] = float(new_value) log.info("updating point: co.X = %s to value: %s" % (point["co"]["X"], float(new_value))) else: point_to_delete = point break elif interpolation > -1 and point["co"]["X"] == previous_point_x: # Only update interpolation type (and the LEFT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_right"] = point.get("handle_right") or {"Y": 0.0, "X": 0.0} point["handle_right"]["X"] = interpolation_details[0] point["handle_right"]["Y"] = interpolation_details[1] log.info("updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) log.info("use interpolation preset: %s" % str(interpolation_details)) elif interpolation > -1 and point["co"]["X"] == closest_point_x: # Only update interpolation type (and the RIGHT side of the curve) found_point = True clip_updated = True point["interpolation"] = interpolation if interpolation == 0: point["handle_left"] = point.get("handle_left") or {"Y": 0.0, "X": 0.0} point["handle_left"]["X"] = interpolation_details[2] point["handle_left"]["Y"] = interpolation_details[3] log.info("updating interpolation mode point: co.X = %s to %s" % (point["co"]["X"], interpolation)) log.info("use interpolation preset: %s" % str(interpolation_details)) # Delete point (if needed) if point_to_delete: clip_updated = True log.info("Found point to delete at X=%s" % point_to_delete["co"]["X"]) c.data[property_key]["Points"].remove(point_to_delete) # Create new point (if needed) elif not found_point and new_value != None: clip_updated = True log.info("Created new point at X=%s" % self.frame_number) c.data[property_key]["Points"].append({'co': {'X': self.frame_number, 'Y': new_value}, 'interpolation': 1}) if not clip_updated: # If no keyframe was found, set a basic property if property_type == "int": # Integer clip_updated = True c.data[property_key] = int(new_value) elif property_type == "float": # Float clip_updated = True c.data[property_key] = new_value elif property_type == "bool": # Boolean clip_updated = True c.data[property_key] = bool(new_value) elif property_type == "string": # String clip_updated = True c.data[property_key] = str(new_value) elif property_type == "reader": # Reader clip_updated = True # Transition try: clip_object = openshot.Clip(value) clip_object.Open() c.data[property_key] = json.loads(clip_object.Reader().Json()) clip_object.Close() clip_object = None except: log.info('Failed to load %s into Clip object for reader property' % value) # Reduce # of clip properties we are saving (performance boost) c.data = {property_key: c.data.get(property_key)} # Save changes if clip_updated: # Save c.save() # Update the preview get_app().window.refreshFrameSignal.emit() # Clear selection self.parent.clearSelection()