=== modified file 'openshot/classes/clip.py' --- openshot/classes/clip.py 2011-08-10 20:50:17 +0000 +++ openshot/classes/clip.py 2011-08-15 22:24:43 +0000 @@ -57,6 +57,10 @@ self.file_object = file_object # the file object that this clip is linked to self.unique_id = str(uuid.uuid1()) self.rotation = 0.0 + self.thumb_location = "" + + # Update the thumbnail of the clip and the location + self.update_thumbnail() # init key-frame dictionary self.keyframes = {"start" : keyframe(0, 100.0, 100.0, 0.0, 0.0, 1.0), @@ -75,7 +79,73 @@ # end_time = 25.0 # position_on_track = 3.0 - + def update_thumbnail(self): + """Updates the thumbnail of the clip to make it reflect the first frame. + Creates a new thumbnail if there is none, gives it a new thumbnail path + if it is empty.""" + + # Initialize variables + project = self.parent.parent.project + thumbnailer = project.thumbnailer + fps = self.file_object.fps + start_frame = int(float(fps) * self.start_time) + file_type = self.file_object.file_type + + # Remove the thumbnail, if it can be removed + self.remove_thumbnail() + + # If it cannot be exchanged for the file thumbnail + if start_frame and (file_type == "video" or file_type == "image sequence"): + + # If it already has a thumbnail location, just update the thumbnail + if self.thumb_location and not self.thumb_location == self.file_object.thumb_location: + (dir_name, file_name) = os.path.split(self.thumb_location) + + # The shortened path to the thumbnail. %d is escaped to provide image sequence support + new_name = "thumbnail/" + file_name.replace("%d","%%d") + + # The whole path. %d shouldn't be escaped here. + path = project.folder + "/thumbnail/" + file_name + + # If the clip needs a new thumbnail location + else: + + # Split the file name + (dir_name, file_name) = os.path.split(self.file_object.name) + (file_base_name, ext) = os.path.splitext(file_name) + + # Escape some characters + ext = ext.replace(".", "") + + # Loop to find an unoccupied name. Start at 2, since the file thumbnail starts at 1 + i = 2 + while(True): + path = project.folder + "/thumbnail/" + file_base_name + "_" + ext + "_" + str(i) + ".png" + if not os.path.exists(path): + break + i += 1 + + # The shortened path to the thumbnail. %d is escaped to provide image sequence support + new_name = "thumbnail/" + file_base_name.replace("%d","%%d") + "_" + ext + "_" + str(i) + ".png" + + # Create the new thumbnail + thumbnailer.get_thumb_at_frame(self.file_object.name, start_frame, new_name) + + # Update the path to the thumbnail + self.thumb_location = path + print "thumb " + self.thumb_location + + elif not file_type == "audio": + # Use the file thumbnail instead, to avoid creating a new + self.thumb_location = self.file_object.thumb_location + + + def remove_thumbnail(self): + """Removes the thumbnail from the hard drive, if it isn't shared with a file""" + # Removes the thumbnail used by this clip if it is valid and isn't used by a file + if self.thumb_location and os.path.exists(self.thumb_location) and not self.thumb_location == self.file_object.thumb_location: + os.remove(self.thumb_location) + def length(self): # calculate the length of this clip (in decimal seconds) length = self.end_time - self.start_time @@ -114,6 +184,50 @@ self.effects.append(new_effect) self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Added effect") + " " + service) + + def get_thumbnail(self, width, height): + """Get and resize the pixbuf thumbnail for a clip""" + + # get the thumbnail (or load default) + try: + if self.thumb_location: + pbThumb = gtk.gdk.pixbuf_new_from_file(self.thumb_location) + pbThumb = pbThumb.add_alpha(False, 255, 255, 255) + + # Mask the corner of the thumbnail image (for a nice rounding effect) + corner_mask = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, 'thumbnail_mask.png')) + corner_mask.composite(pbThumb, + 0, + 0, + 320, + 240, + 0, + 0, + 1.0, + 1.0, + gtk.gdk.INTERP_NEAREST, + 255) + + # replace corner with transparency + pbThumb = pbThumb.add_alpha(True, 255, 0, 202) + + + else: + # Load the No Thumbnail Picture + if self.file_object.file_type == "audio": + pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "AudioThumbnail.png")) + else: + pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "NoThumbnail.png")) + except: + + # Load the No Thumbnail Picture + if self.file_object.file_type == "audio": + pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "AudioThumbnail.png")) + else: + pbThumb = gtk.gdk.pixbuf_new_from_file(os.path.join(self.file_object.project.IMAGE_DIR, "NoThumbnail.png")) + + # resize thumbnail + return pbThumb.scale_simple(width, height, gtk.gdk.INTERP_BILINEAR) def Remove_Effect(self, unique_id): # Remove an effect from the list @@ -1230,7 +1344,7 @@ # /////////////////////////////////////////////////////// if has_regular_images == False: # get the thumbnail image - pbThumb = self.file_object.get_thumbnail(theme_settings["clip"]["thumbnail"]["w"], theme_settings["clip"]["thumbnail"]["h"]) + pbThumb = self.get_thumbnail(theme_settings["clip"]["thumbnail"]["w"], theme_settings["clip"]["thumbnail"]["h"]) # create canvas image object imgThumb = goocanvas.Image (parent = GroupClip, @@ -1976,6 +2090,14 @@ child_num = parent.find_child (item) parent.remove_child (child_num) + # Initialize variables + pixels_per_second = self.parent.parent.get_pixels_per_second() + center_of_clip = (self.position_on_track * pixels_per_second) + ((self.length() * pixels_per_second) / 2) + + # If the clip was dragged on the left side, update the thumbnail to reflect the changes + if event.x_root < center_of_clip: + self.update_thumbnail() + # re-render the clip at it's new size self.RenderClip() === modified file 'openshot/classes/files.py' --- openshot/classes/files.py 2011-08-11 21:59:28 +0000 +++ openshot/classes/files.py 2011-08-15 18:59:49 +0000 @@ -104,6 +104,26 @@ # resize thumbnail return pbThumb.scale_simple(width, height, gtk.gdk.INTERP_BILINEAR) + def update_thumbnail(self): + + # Initialize variables + project = self.project + thumbnailer = project.thumbnailer + file_type = self.file_type + + # Audio files have a common thumbnail + if not file_type == "audio": + + # Split the file name + (dir_name, file_name) = os.path.split(self.name) + (file_base_name, ext) = os.path.splitext(file_name) + ext = ext.replace(".", "") + + # The shortened path to the thumbnail + new_name = "thumbnail/" + file_base_name + "_" + ext + "_1.png" + + # Create the new thumbnail + thumbnailer.get_thumb_at_frame(self.name, new_name=new_name) ######################################################################## class OpenShotFolder: @@ -442,8 +462,10 @@ for clip in reversed(track.clips): # does clip match file if clip.file_object == item: - # delete clip + # delete clip and remove thumbnail track.clips.remove(clip) + clip.remove_thumbnail() + # remove from file collection self.items.remove(item) else: === modified file 'openshot/classes/open_project.py' --- openshot/classes/open_project.py 2011-01-13 07:33:37 +0000 +++ openshot/classes/open_project.py 2011-08-15 22:20:21 +0000 @@ -95,6 +95,26 @@ if missing_transitions: messagebox.show("OpenShot", _("The following transition(s) no longer exist.") + "\n\n" + missing_transitions) + # Recreate the thumbnail folder if it is missing + if not os.path.exists(project_object.folder + "/thumbnail"): + os.makedirs(project_object.folder + "/thumbnail") + + # Recreate missing thumbnails for files + for item in items: + if isinstance(item, files.OpenShotFile): + if not os.path.exists(item.thumb_location): + item.update_thumbnail() + + # Recreate missing thumbnails for clips + for sequence in project_object.sequences: + for track in sequence.tracks: + for clip in track.clips: + # Code to keep pre 1.4.0 .osp files compatible. May be removed later. + if not hasattr(clip, "thumb_location"): + clip.thumb_location = "" + + if not os.path.exists(clip.thumb_location) and not clip.file_object.file_type == "audio": + clip.update_thumbnail() # mark XML as refreshable project_object.set_project_modified(is_modified=False, refresh_xml=True) === modified file 'openshot/windows/ClipProperties.py' --- openshot/windows/ClipProperties.py 2011-08-10 20:13:08 +0000 +++ openshot/windows/ClipProperties.py 2011-08-15 22:20:38 +0000 @@ -891,6 +891,9 @@ # update keyframes clip_object.keyframes = self.keyframes + # Update the thumbnail + clip_object.update_thumbnail() + if localcboDirection.lower() == _("Reverse").lower(): clip_object.reversed = True else: === modified file 'openshot/windows/MainGTK.py' --- openshot/windows/MainGTK.py 2011-08-11 20:33:40 +0000 +++ openshot/windows/MainGTK.py 2011-08-15 19:02:32 +0000 @@ -2253,7 +2253,7 @@ #this will be the new name of the snapshot image file new_name = fileBaseName + str(intNum) + ".png" #extract the frame - self.project.thumbnailer.get_thumb_at_frame(clip.file_object.name, int(frame_position), new_name) + self.project.thumbnailer.get_thumb_at_frame(clip.file_object.name, int(frame_position), new_name, True) #add the file to the project in the project folder self.project.project_folder.AddFile(self.project.folder + "/" + new_name) #refresh the tree @@ -3535,6 +3535,7 @@ # render timeline self.project.Render() + def on_mnuClipEditTitle_activate(self, event, *args): #print "on_mnuClipEditTitle_activate" @@ -3575,6 +3576,9 @@ child_num = parent.find_child (self.selected_clip_item) parent.remove_child (child_num) + # Remove the thumbnail + self.selected_clip.remove_thumbnail() + # mark project as modified self.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Removed clip")) @@ -3696,6 +3700,9 @@ new_clip.keyframes = copy.deepcopy(self.selected_clip.keyframes) new_clip.effects = copy.deepcopy(self.selected_clip.effects) + # Update the thumbnail + new_clip.update_thumbnail() + # mark project as modified self.project.set_project_modified(is_modified=True, refresh_xml=True, type="Duplicated clip")