Merge lp:~fincha/openshot/andy-1.2 into lp:openshot/1.4

Proposed by Andy Finch
Status: Merged
Merge reported by: Jonathan Thomas
Merged at revision: not available
Proposed branch: lp:~fincha/openshot/andy-1.2
Merge into: lp:openshot/1.4
Diff against target: 939 lines (+627/-19) (has conflicts)
14 files modified
openshot/classes/clip.py (+76/-1)
openshot/classes/project.py (+21/-0)
openshot/classes/thumbnail.py (+19/-7)
openshot/effects/bass.xml (+23/-0)
openshot/effects/treble.xml (+22/-0)
openshot/windows/AddFiles.py (+53/-5)
openshot/windows/FileProperties.py (+13/-0)
openshot/windows/ImportTransitions.py (+138/-0)
openshot/windows/MainGTK.py (+75/-4)
openshot/windows/TreeTransitions.py (+28/-1)
openshot/windows/preferences.py (+3/-1)
openshot/windows/ui/ImportTransitions.ui (+134/-0)
openshot/windows/ui/Main.ui (+9/-0)
openshot/windows/ui/Main_clip_properties.ui (+13/-0)
Text conflict in openshot/classes/clip.py
Text conflict in openshot/classes/project.py
Text conflict in openshot/windows/FileProperties.py
To merge this branch: bzr merge lp:~fincha/openshot/andy-1.2
Reviewer Review Type Date Requested Status
Jonathan Thomas Pending
Review via email: mp+29753@code.launchpad.net

Description of the change

Includes the following fixes/changes:

#510755 - 'Replace Clip' option on the right click menu - replaces clip, but preserves current properties.
#510708 - Allow user to import new transitions (done via a gui)
#502861 - Dragging a clip on the Timeline shouldn't change the mute/visible properties (Couldn't actually prevent the change when dragging, but now you can't accidentally change them when right clicking or in razor mode).
#517068 - Add Frame snapshot. Keyboard shortcut 'f' extracts the current frame and adds to the project as an image.

Also added Bass & Treble audio effects - might replace these later with a proper equaliser, if I can get the ladspa audio effects working.

To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openshot/classes/clip.py'
2--- openshot/classes/clip.py 2010-07-06 03:23:04 +0000
3+++ openshot/classes/clip.py 2010-07-12 22:08:40 +0000
4@@ -1308,7 +1308,7 @@
5
6 def on_motion_notify_x (self, item, target, event):
7 """this method allows the clip to be dragged and dropped on a track"""
8-
9+
10 # get the new x,y coordinates from the mouse
11 new_x = float(event.x)
12 new_y = float(event.y)
13@@ -1804,6 +1804,7 @@
14 else:
15 # The clip has moved
16 type_of_event = _("Moved clip")
17+<<<<<<< TREE
18
19 # Animate the clip to it's new position
20 item.animate(distance_from_clip, drop_track.y_top - item.get_bounds().y1 + 2, 1.0, 0.0, False, 200, 4, goocanvas.ANIMATE_FREEZE)
21@@ -1818,6 +1819,12 @@
22 self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = type_of_event)
23
24
25+=======
26+
27+ self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = type_of_event)
28+
29+
30+>>>>>>> MERGE-SOURCE
31 elif isResize:
32
33 # remove clip from goocanvas
34@@ -1885,6 +1892,7 @@
35
36
37 def on_visible_click (self, item, target, event):
38+<<<<<<< TREE
39
40 # get a reference to the language translate method
41 _ = self.parent.parent.project.translate
42@@ -1917,9 +1925,43 @@
43 self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Changed visibility of clip"))
44
45 return False
46+=======
47+ #don't do this if in razor mode
48+ (isArrow, isRazor, isSnap, isResize) = self.parent.parent.project.form.get_toolbar_options()
49+ if isArrow:
50+ # get a reference to the 2 main canvas objects & theme
51+ theme = self.parent.parent.project.theme
52+
53+ # get the parent left group
54+ parent_group = item.get_parent()
55+ canvas = parent_group.get_canvas()
56+ canvas.pointer_ungrab (item, event.time)
57+
58+ if self.play_video == True:
59+ # Load Hover Over
60+ imgTrack_Visible = gtk.image_new_from_file("%s/openshot/themes/%s/not_visible_transparent.png" % (self.parent.parent.project.form.openshot_path, theme))
61+ item.set_properties(pixbuf = imgTrack_Visible.get_pixbuf())
62+
63+ # update play video variable
64+ self.play_video = False
65+
66+ else:
67+ # Load normal image
68+ imgTrack_Visible = gtk.image_new_from_file("%s/openshot/themes/%s/visible_transparent.png" % (self.parent.parent.project.form.openshot_path, theme))
69+ item.set_properties(pixbuf = imgTrack_Visible.get_pixbuf())
70+
71+ # update play video variable
72+ self.play_video = True
73+
74+ # mark project as modified
75+ self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Changed visibility of clip"))
76+
77+ return False
78+>>>>>>> MERGE-SOURCE
79
80
81 def on_audio_click (self, item, target, event):
82+<<<<<<< TREE
83
84 # get a reference to the language translate method
85 _ = self.parent.parent.project.translate
86@@ -1952,6 +1994,39 @@
87 self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Changed audio of clip"))
88
89 return False
90+=======
91+ #don't do this if in razor mode.
92+ (isArrow, isRazor, isSnap, isResize) = self.parent.parent.project.form.get_toolbar_options()
93+ if isArrow:
94+ # get a reference to the 2 main canvas objects & theme
95+ theme = self.parent.parent.project.theme
96+
97+ # get the parent left group
98+ parent_group = item.get_parent()
99+ canvas = parent_group.get_canvas()
100+ canvas.pointer_ungrab (item, event.time)
101+
102+ if self.play_audio == True:
103+ # Load Hover Over
104+ imgTrack_Visible = gtk.image_new_from_file("%s/openshot/themes/%s/speaker_mute_transparent.png" % (self.parent.parent.project.form.openshot_path, theme))
105+ item.set_properties(pixbuf = imgTrack_Visible.get_pixbuf())
106+
107+ # update play video variable
108+ self.play_audio = False
109+
110+ else:
111+ # Load normal image
112+ imgTrack_Visible = gtk.image_new_from_file("%s/openshot/themes/%s/speaker_transparent.png" % (self.parent.parent.project.form.openshot_path, theme))
113+ item.set_properties(pixbuf = imgTrack_Visible.get_pixbuf())
114+
115+ # update play video variable
116+ self.play_audio = True
117+
118+ # mark project as modified
119+ self.parent.parent.project.set_project_modified(is_modified=True, refresh_xml=True, type = _("Changed audio of clip"))
120+
121+ return False
122+>>>>>>> MERGE-SOURCE
123
124 def on_effect_click (self, item, target, event):
125 pass
126
127=== modified file 'openshot/classes/project.py'
128--- openshot/classes/project.py 2010-07-07 00:04:26 +0000
129+++ openshot/classes/project.py 2010-07-12 22:08:40 +0000
130@@ -55,6 +55,8 @@
131 self.USER_DIR = os.path.join(os.path.expanduser("~"), ".openshot")
132 self.THEMES_DIR = os.path.join(self.BASE_DIR, "openshot", "themes")
133 self.USER_PROFILES_DIR = os.path.join(self.USER_DIR, "user_profiles")
134+ self.USER_TRANSITIONS_DIR = os.path.join(self.USER_DIR, "user_transitions")
135+
136
137 # only run the following code if we are really using
138 # this project file...
139@@ -123,6 +125,7 @@
140 pidPath = os.path.join(path, "pid.lock")
141 pid=int(open(pidPath, 'r').read().strip())
142
143+<<<<<<< TREE
144 # list of folders that should not be deleted
145 safe_folders = ["blender", "queue", "user_profiles"]
146
147@@ -138,6 +141,23 @@
148 # remove folder
149 os.removedirs(os.path.join(path, child_path))
150
151+=======
152+ # list of folders that should not be deleted
153+ safe_folders = ["blender", "queue", "user_profiles", "user_transitions"]
154+
155+ # loop through all folders in the USER_DIR
156+ for child_path in os.listdir(path):
157+ if os.path.isdir(os.path.join(path, child_path)):
158+ if child_path not in safe_folders:
159+ # clear all files / folders recursively in the thumbnail folder
160+ if os.getpid() == pid:
161+ # only clear this folder for the primary instance of OpenShot
162+ self.remove_files(os.path.join(path, child_path))
163+
164+ # remove folder
165+ os.removedirs(os.path.join(path, child_path))
166+
167+>>>>>>> MERGE-SOURCE
168 # thumbnail path
169 thumbnail_path = os.path.join(path, "thumbnail")
170
171@@ -193,6 +213,7 @@
172 state['DESKTOP'] = empty_project.DESKTOP
173 state['THEMES_DIR'] = empty_project.THEMES_DIR
174 state['USER_PROFILES_DIR'] = empty_project.USER_PROFILES_DIR
175+ state['USER_TRANSITIONS_DIR'] = empty_project.USER_TRANSITIONS_DIR
176 state['refresh_xml'] = True
177 state['mlt_profile'] = None
178
179
180=== modified file 'openshot/classes/thumbnail.py'
181--- openshot/classes/thumbnail.py 2010-02-27 19:51:35 +0000
182+++ openshot/classes/thumbnail.py 2010-07-12 22:08:40 +0000
183@@ -180,8 +180,10 @@
184 self.profile = None
185 self.f = None
186
187- def get_thumb_at_frame(self, filename, frame=1):
188-
189+ def get_thumb_at_frame(self, filename, frame=1, new_name=""):
190+ '''by passing a value in new_name, this will extract a
191+ full size frame (based on the project profile).'''
192+
193 self.file_name = filename
194
195 project_path = self.project.folder
196@@ -189,14 +191,15 @@
197 (dirName, fileName) = os.path.split(myPath)
198 (fileBaseName, fileExtension)=os.path.splitext(fileName)
199 fileExtension = fileExtension.replace(".", "")
200-
201+
202 mlt.Factory.init()
203
204- # just get 1 thumbnail frame
205- self.thumbnail_path = project_path + "/thumbnail/" + fileBaseName + "_" + fileExtension + "_%d.png"
206-
207+
208 # set the profile
209- self.profile = mlt.Profile("quarter_ntsc")
210+ if new_name == "":
211+ self.profile = mlt.Profile("quarter_ntsc")
212+ else:
213+ self.profile = profiles.mlt_profiles(self.project).get_profile(self.project.project_type)
214
215 # Create the producer
216 self.p = mlt.Producer( self.profile, '%s' % self.file_name )
217@@ -205,6 +208,15 @@
218 if self.p.is_valid() == False:
219 return None
220
221+
222+ if new_name == "":
223+ # just get 1 thumbnail frame
224+ self.thumbnail_path = project_path + "/thumbnail/" + fileBaseName + "_" + fileExtension + "_%d.png"
225+ else:
226+ #for snapshots, use the new file name
227+ #don't use the thumbnail path for the new file
228+ self.thumbnail_path = project_path + "/" + new_name
229+
230 # create the consumer
231 self.c = mlt.Consumer(self.profile, "avformat", self.thumbnail_path)
232
233
234=== added file 'openshot/effects/bass.xml'
235--- openshot/effects/bass.xml 1970-01-01 00:00:00 +0000
236+++ openshot/effects/bass.xml 2010-07-12 22:08:40 +0000
237@@ -0,0 +1,23 @@
238+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
239+<!DOCTYPE openshot-effect>
240+<effect>
241+ <title translatable="True">Bass</title>
242+ <description translatable="True">Sox Bass control</description>
243+ <icon>audio.png</icon>
244+ <category>Audio</category>
245+ <service>sox:bass</service>
246+
247+ <param name="frequency" type="spinner" title="Frequency" description="">
248+ <min>1</min>
249+ <max>5000</max>
250+ <default>100</default>
251+ </param>
252+
253+ <param name="gain" type="spinner" title="Gain" description="">
254+ <min>-20</min>
255+ <max>20</max>
256+ <default>10</default>
257+ </param>
258+
259+
260+</effect>
261
262=== added file 'openshot/effects/treble.xml'
263--- openshot/effects/treble.xml 1970-01-01 00:00:00 +0000
264+++ openshot/effects/treble.xml 2010-07-12 22:08:40 +0000
265@@ -0,0 +1,22 @@
266+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
267+<!DOCTYPE openshot-effect>
268+<effect>
269+ <title translatable="True">Treble</title>
270+ <description translatable="True">Sox Treble control</description>
271+ <icon>audio.png</icon>
272+ <category>Audio</category>
273+ <service>sox:treble</service>
274+
275+ <param name="frequency" type="spinner" title="Frequency" description="">
276+ <min>3000</min>
277+ <max>22000</max>
278+ <default>5000</default>
279+ </param>
280+
281+ <param name="gain" type="spinner" title="Gain" description="">
282+ <min>-20</min>
283+ <max>20</max>
284+ <default>8</default>
285+ </param>
286+
287+</effect>
288
289=== modified file 'openshot/windows/AddFiles.py'
290--- openshot/windows/AddFiles.py 2010-04-03 18:52:42 +0000
291+++ openshot/windows/AddFiles.py 2010-07-12 22:08:40 +0000
292@@ -34,13 +34,10 @@
293 # Add language support
294 _ = Language_Init.Translator(project).lang.gettext
295
296+ self.frmAddFiles.set_title("OpenShot")
297 self.frmAddFiles.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
298 self.frmAddFiles.set_select_multiple(True)
299- #if the video folder exists, default to this
300- #video_dir = os.path.join(os.path.expanduser("~"), "Video")
301- #if video_dir:
302- # self.frmAddFiles.set_current_folder(video_dir)
303-
304+
305 self.form = form
306 self.project = project
307
308@@ -81,6 +78,57 @@
309 #call the open project method when a file is double clicked
310 self.on_btnAdd_clicked(widget, *args)
311
312+class frmReplaceFiles(SimpleGtkBuilderApp):
313+
314+ def __init__(self, path="AddFiles.ui", root="frmAddFiles", domain="OpenShot", form=None, project=None,clip=None, **kwargs):
315+ SimpleGtkBuilderApp.__init__(self, os.path.join(project.UI_DIR, path), root, domain, **kwargs)
316+
317+ # Add language support
318+ _ = Language_Init.Translator(project).lang.gettext
319+
320+ self.frmAddFiles.set_title("OpenShot")
321+ self.frmAddFiles.set_action(gtk.FILE_CHOOSER_ACTION_OPEN)
322+ self.frmAddFiles.set_select_multiple(False)
323+
324+ self.form = form
325+ self.project = project
326+ self.clip = clip
327+
328+ self.frmAddFiles.show_all()
329+
330+ def on_btnCancel_clicked(self, widget, *args):
331+ self.frmAddFiles.destroy()
332+
333+ def on_btnAdd_clicked(self, widget, *args):
334+ replace_clip_with = self.frmAddFiles.get_filename()
335+ try:
336+ #does the new file already exist in the project?
337+ file_object = self.project.project_folder.FindFile(replace_clip_with)
338+ if not file_object:
339+ #add the file to the project
340+ self.project.project_folder.AddFile(replace_clip_with)
341+
342+ #this method does the actual replacement and modifies the project
343+ self.form.replace_clip(self.clip,replace_clip_with)
344+
345+ except:
346+ messagebox.show(_("Error"), _("There was an error importing the selected files"))
347+
348+ #set the last used folder
349+ preferences.Settings.app_state["import_folder"] = self.frmAddFiles.get_current_folder()
350+
351+
352+ self.frmAddFiles.destroy()
353+
354+
355+
356+ def on_frmAddFiles_file_activated(self, widget, *args):
357+ #call the open project method when a file is double clicked
358+ self.on_btnAdd_clicked(widget, *args)
359+
360+ def get_replace_clip_with(self):
361+ return self.replace_clip_with
362+
363
364
365 def main():
366
367=== modified file 'openshot/windows/FileProperties.py'
368--- openshot/windows/FileProperties.py 2010-07-04 19:40:34 +0000
369+++ openshot/windows/FileProperties.py 2010-07-12 22:08:40 +0000
370@@ -39,8 +39,21 @@
371
372 #set the thumbnail - use the preview thumbnail
373 #for video & image files
374+<<<<<<< TREE
375 pixbuf = file.get_thumbnail(112, 83)
376 self.imgPreview.set_from_pixbuf(pixbuf)
377+=======
378+ if file.file_type != "audio":
379+ if file.thumb_location != "":
380+ pixbuf = gtk.gdk.pixbuf_new_from_file(file.thumb_location)
381+ pixbuf = pixbuf.scale_simple(112,83,gtk.gdk.INTERP_BILINEAR)
382+ self.imgPreview.set_from_pixbuf(pixbuf)
383+ else:
384+ #use the generic OpenShot audio thumbnail
385+ pixbuf = gtk.gdk.pixbuf_new_from_file(os.path.join(self.project.IMAGE_DIR, "AudioThumbnail.png"))
386+ pixbuf = pixbuf.scale_simple(112,83,gtk.gdk.INTERP_BILINEAR)
387+ self.imgPreview.set_from_pixbuf(pixbuf)
388+>>>>>>> MERGE-SOURCE
389
390 #set the file type
391 self.lblMimeType.set_label(file.file_type)
392
393=== added file 'openshot/windows/ImportTransitions.py'
394--- openshot/windows/ImportTransitions.py 1970-01-01 00:00:00 +0000
395+++ openshot/windows/ImportTransitions.py 2010-07-12 22:08:40 +0000
396@@ -0,0 +1,138 @@
397+# OpenShot Video Editor is a program that creates, modifies, and edits video files.
398+# Copyright (C) 2009 Jonathan Thomas
399+#
400+# This file is part of OpenShot Video Editor (http://launchpad.net/openshot/).
401+#
402+# OpenShot Video Editor is free software: you can redistribute it and/or modify
403+# it under the terms of the GNU General Public License as published by
404+# the Free Software Foundation, either version 3 of the License, or
405+# (at your option) any later version.
406+#
407+# OpenShot Video Editor is distributed in the hope that it will be useful,
408+# but WITHOUT ANY WARRANTY; without even the implied warranty of
409+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
410+# GNU General Public License for more details.
411+#
412+# You should have received a copy of the GNU General Public License
413+# along with OpenShot Video Editor. If not, see <http://www.gnu.org/licenses/>.
414+
415+import os
416+import gtk
417+import shutil
418+from windows.SimpleGtkBuilderApp import SimpleGtkBuilderApp
419+from classes import project, messagebox
420+from PIL import Image
421+
422+# init the foreign language
423+from language import Language_Init
424+
425+
426+class frmImportTransitions(SimpleGtkBuilderApp):
427+
428+ def __init__(self, path="ImportTransitions.ui", root="frmImportTransitions", domain="OpenShot", form=None, project=None, **kwargs):
429+ SimpleGtkBuilderApp.__init__(self, os.path.join(project.UI_DIR, path), root, domain, **kwargs)
430+
431+ # Add language support
432+ _ = Language_Init.Translator(project).lang.gettext
433+
434+ self.project = project
435+
436+ filter = gtk.FileFilter()
437+ filter.set_name("PNG or PGM files")
438+ filter.add_pattern("*.png")
439+ filter.add_pattern("*.pgm")
440+
441+ self.fileTransition.add_filter(filter)
442+ self.fileIcon.add_filter(filter)
443+
444+ self.transition_file = ""
445+ self.icon_file = ""
446+
447+ self.frmImportTransitions.show_all()
448+
449+ def on_btnCancel_clicked(self, widget, *args):
450+
451+ self.frmImportTransitions.destroy()
452+
453+
454+
455+ def on_fileTransition_file_set(self, widget, *args):
456+
457+ self.transition_file = self.fileTransition.get_filename()
458+
459+ if self.icon_file:
460+ if self.check_filename_ok():
461+ self.btnOK.set_sensitive(True)
462+ else:
463+ messagebox.show("Openshot", _("The Transition and Icon file names must be the same."))
464+
465+
466+
467+ def on_fileIcon_file_set(self, widget, *args):
468+
469+ self.icon_file = self.fileIcon.get_filename()
470+
471+ if self.transition_file:
472+ if self.check_filename_ok():
473+ self.btnOK.set_sensitive(True)
474+ else:
475+ messagebox.show("Openshot", _("The Transition and Icon file names must be the same."))
476+
477+
478+ def on_btnOK_clicked(self, widget, *args):
479+ #check if a transition with this name exists
480+ if self.check_icon_size():
481+ (dirName, filename) = os.path.split(self.transition_file)
482+ if os.path.exists(os.path.join(self.project.USER_TRANSITIONS_DIR,filename)):
483+ messagebox.show("Openshot", _("A Transition with the filename %s already exists. Do you want to replace it?" % filename), gtk.BUTTONS_YES_NO, self.import_transition())
484+ else:
485+ #just import the transition
486+ self.import_transition()
487+ else:
488+ messagebox.show("Openshot", _("The icon file must have a size of 80x62. The Transition will not be imported."))
489+
490+ def check_icon_size(self):
491+ #check the icon is 80x62
492+ try:
493+ im = Image.open(self.icon_file)
494+ except IOError:
495+ print "failed to identify", self.icon_file
496+ else:
497+ w, h = im.size
498+ if w != 80 or h != 62:
499+ return False
500+ else:
501+ return True
502+
503+ def check_filename_ok(self):
504+ #check both filenames match
505+ (dirName, self.iconfilename) = os.path.split(self.icon_file)
506+ (iconBaseName, fileExtension)=os.path.splitext(self.iconfilename)
507+
508+ (dirName, self.transfilename) = os.path.split(self.transition_file)
509+ (transBaseName, fileExtension)=os.path.splitext(self.transfilename)
510+ if iconBaseName == transBaseName:
511+ return True
512+ else:
513+ return False
514+
515+
516+ def import_transition(self):
517+ if not os.path.exists(self.project.USER_TRANSITIONS_DIR):
518+ os.makedirs(self.project.USER_TRANSITIONS_DIR)
519+ os.makedirs(os.path.join(self.project.USER_TRANSITIONS_DIR, "icons"))
520+ try:
521+ shutil.copyfile(self.transition_file, os.path.join(self.project.USER_TRANSITIONS_DIR, self.transfilename))
522+ shutil.copyfile(self.icon_file, os.path.join(self.project.USER_TRANSITIONS_DIR, "icons", self.iconfilename))
523+ messagebox.show("Openshot", _("Transition Imported successfully! Restart Openshot for the changes to take effect."))
524+ self.frmImportTransitions.destroy()
525+ except:
526+ messagebox.show("Openshot Error!", _("There was an error importing the Transition!"))
527+
528+
529+def main():
530+ import_transitions = frmImportTransitions()
531+ import_transitions.run()
532+
533+if __name__ == "__main__":
534+ main()
535\ No newline at end of file
536
537=== modified file 'openshot/windows/MainGTK.py'
538--- openshot/windows/MainGTK.py 2010-07-07 06:25:46 +0000
539+++ openshot/windows/MainGTK.py 2010-07-12 22:08:40 +0000
540@@ -31,7 +31,7 @@
541 from classes import files, lock, messagebox, open_project, project, timeline, tree, video, inputbox, av_formats, clip
542 from windows import About, FileProperties, NewProject, OpenProject, preferences, Profiles
543 from windows.SimpleGtkBuilderApp import SimpleGtkBuilderApp
544-from windows import AddFiles, ClipProperties, ExportVideo, ImportImageSeq, Titles, TransitionProperties, TreeFiles, TreeTransitions, TreeEffects, TreeHistory, BlenderGenerator, AddToTimeline
545+from windows import AddFiles, ClipProperties, ExportVideo, ImportImageSeq, Titles, TransitionProperties, TreeFiles, TreeTransitions, TreeEffects, TreeHistory, BlenderGenerator, AddToTimeline, ImportTransitions
546
547 # init the foreign language
548 from language import Language_Init
549@@ -519,8 +519,10 @@
550 # Strip 'file://' from the beginning
551 file_to_open = uri[7:]
552
553+
554 # Open the project file
555 self.open_project(file_to_open)
556+
557
558
559 def open_project(self, file_to_open):
560@@ -541,6 +543,7 @@
561 # Update the main form
562 self.refresh()
563
564+
565
566 def new(self):
567 print "A new %s has been created" % self.__class__.__name__
568@@ -1156,6 +1159,9 @@
569
570 # show import file dialog
571 ImportImageSeq.frmImportImageSequence(form=self, project=self.project)
572+
573+ def on_mnuImportTransitions_activate(self, widget, *args):
574+ ImportTransitions.frmImportTransitions(form=self, project=self.project)
575
576
577 def on_mnuSaveProject_activate(self, widget, *args):
578@@ -1705,22 +1711,28 @@
579 self.on_tlbNext_clicked(widget, event)
580
581 elif keyname == "s":
582- #go to the end of the clip
583+ #save the project
584 if (event.state == gtk.gdk.CONTROL_MASK) or (event.state == gtk.gdk.CONTROL_MASK | gtk.gdk.MOD2_MASK):
585 # call the save button
586 self.on_tlbSave_clicked(widget)
587
588 elif keyname == "y":
589- #go to the end of the clip
590+ #redo
591 if (event.state == gtk.gdk.CONTROL_MASK) or (event.state == gtk.gdk.CONTROL_MASK | gtk.gdk.MOD2_MASK):
592 # Undo last action
593 self.redo_last()
594
595 elif keyname == "z":
596- #go to the end of the clip
597+ #undo
598 if (event.state == gtk.gdk.CONTROL_MASK) or (event.state == gtk.gdk.CONTROL_MASK | gtk.gdk.MOD2_MASK):
599 # Undo last action
600 self.undo_last()
601+
602+ elif keyname == "f":
603+ #snapshot
604+ self.get_frame_snapshot()
605+
606+
607
608
609 def toggle_mode(self):
610@@ -1757,6 +1769,48 @@
611 canvas_item = clip.get_canvas_child(root_right, clip.unique_id)
612 # divide clip
613 clip.divide_clip(x, canvas_item)
614+
615+
616+ def get_frame_snapshot(self):
617+ '''Extracts a frame from each (non-audio) clip at the current
618+ playhead position'''
619+ # Get playhead position
620+ current_position = self.project.sequences[0].play_head_position
621+ # get frames per second
622+ fps = self.project.fps()
623+ # Loop through all tracks
624+ for track in self.project.sequences[0].tracks:
625+ # Loop through all clips on this track
626+ for clip in track.clips:
627+ # is playhead overlapping this clip
628+ if current_position > clip.position_on_track and current_position < (clip.position_on_track + clip.length()):
629+ #only extract frames from non-audio files
630+ if clip.file_object.file_type != "audio":
631+ clip_position = (current_position + clip.start_time) - clip.position_on_track
632+ frame_position = round(clip_position * fps)
633+ #when extracting a frame, it gets added to the
634+ #project as a new file.
635+ #Here we get the name of the existing clip, and
636+ #modify it to make it unique.
637+ filepath = clip.file_object.project.folder
638+ (fileBaseName, fileExtension)=os.path.splitext(clip.name)
639+ #add a number to the end of the filename.
640+ #get the next available number for the file
641+ blnFind = True
642+ intNum = 0
643+ while blnFind == True:
644+ intNum += 1
645+ blnFind = os.path.exists(os.path.join(filepath, fileBaseName + str(intNum) + ".png"))
646+
647+ #this will be the new name of the snapshot image file
648+ new_name = fileBaseName + str(intNum) + ".png"
649+ #extract the frame
650+ self.project.thumbnailer.get_thumb_at_frame(clip.file_object.name, int(frame_position), new_name)
651+ #add the file to the project in the project folder
652+ self.project.project_folder.AddFile(self.project.folder + "/" + new_name)
653+ #refresh the tree
654+ self.refresh()
655+
656
657
658 def get_toolbar_options(self):
659@@ -3085,6 +3139,23 @@
660 if is_title:
661 self.form.refresh()
662
663+
664+ def on_mnuReplaceClip_activate (self, event, *args):
665+ # show import file dialog to select replacement file
666+ AddFiles.frmReplaceFiles(form=self, project=self.project, clip=self.selected_clip)
667+
668+
669+ def replace_clip(self, selected_clip, new_clip):
670+ #this replaces the selected clip with a new clip
671+ (filepath, filename) = os.path.split(new_clip)
672+ file = self.project.project_folder.FindFile(filename)
673+ if file:
674+ selected_clip.file_object = file
675+ selected_clip.name = filename
676+ #force a refresh of the xml
677+ self.project.set_project_modified(is_modified=True, refresh_xml=True, type=_("Replaced Clip"))
678+ self.project.Render()
679+ self.form.refresh()
680
681 def on_mnuSliceandShuffle_activate(self, event, *args):
682 """ Cut a clip into many small pieces and shuffle them """
683
684=== modified file 'openshot/windows/TreeTransitions.py'
685--- openshot/windows/TreeTransitions.py 2010-05-31 21:31:32 +0000
686+++ openshot/windows/TreeTransitions.py 2010-07-12 22:08:40 +0000
687@@ -18,7 +18,7 @@
688
689 import os
690 import gtk, gobject, pango
691-from classes import project
692+from classes import project, messagebox
693
694 # init the foreign language
695 from language import Language_Init
696@@ -90,6 +90,33 @@
697 self.store.set_value(item, 1, _(trans_name))
698 self.store.set_value(item, 2, os.path.join(self.project.TRANSITIONS_DIR, file_name))
699
700+ #get any user created transitions
701+ if os.path.exists(self.project.USER_TRANSITIONS_DIR):
702+ user_list = os.listdir(self.project.USER_TRANSITIONS_DIR)
703+ try:
704+ for fname in sorted(user_list):
705+ (dirName, file_name) = os.path.split(fname)
706+ (fileBaseName, fileExtension)=os.path.splitext(file_name)
707+ file_path = os.path.join(self.project.USER_TRANSITIONS_DIR, "icons", fileBaseName + ".png")
708+
709+ if fileBaseName == "icons":
710+ # ignore the 'icons' folder
711+ continue
712+
713+ # get the pixbuf
714+ pbThumb = gtk.gdk.pixbuf_new_from_file(file_path)
715+
716+ # get name of transition
717+ trans_name = fileBaseName.replace("_", " ").capitalize()
718+
719+ # add transition to tree
720+ item = self.store.append(None)
721+ self.store.set_value(item, 0, pbThumb)
722+ self.store.set_value(item, 1, _(trans_name))
723+ self.store.set_value(item, 2, os.path.join(self.project.USER_TRANSITIONS_DIR, file_name))
724+ except:
725+ messagebox.show("Openshot Error!", _("There was an error loading user created transitions."))
726+
727
728 # connect signals
729 self.treeview.connect_after('drag_begin', self.on_treeTransition_drag_begin)
730
731=== modified file 'openshot/windows/preferences.py'
732--- openshot/windows/preferences.py 2010-07-06 03:23:04 +0000
733+++ openshot/windows/preferences.py 2010-07-12 22:08:40 +0000
734@@ -80,6 +80,7 @@
735 #populate the themes
736 for dir in os.listdir(self.project.THEMES_DIR):
737 self.cmbThemes.append_text(dir)
738+
739
740 # populate project file type combo
741 for file_type in ["binary", "ascii"]:
742@@ -190,7 +191,8 @@
743 def load_theme_image(self, theme_name):
744 #loads the preview image for the selected theme.
745 themes_folder = os.path.join(self.project.THEMES_DIR, theme_name)
746- self.imgTheme.set_from_file(os.path.join(themes_folder, "play.png"))
747+ if os.path.exists(os.path.join(themes_folder, "play.png")):
748+ self.imgTheme.set_from_file(os.path.join(themes_folder, "play.png"))
749
750
751 def on_icvCategories_selection_changed(self, icon_view, model=None):
752
753=== added file 'openshot/windows/ui/ImportTransitions.ui'
754--- openshot/windows/ui/ImportTransitions.ui 1970-01-01 00:00:00 +0000
755+++ openshot/windows/ui/ImportTransitions.ui 2010-07-12 22:08:40 +0000
756@@ -0,0 +1,134 @@
757+<?xml version="1.0"?>
758+<interface>
759+ <requires lib="gtk+" version="2.16"/>
760+ <!-- interface-naming-policy project-wide -->
761+ <object class="GtkWindow" id="frmImportTransitions">
762+ <property name="width_request">400</property>
763+ <property name="height_request">180</property>
764+ <property name="title" translatable="yes">Import Transitions</property>
765+ <property name="window_position">center</property>
766+ <property name="icon">icons/openshot.png</property>
767+ <child>
768+ <object class="GtkVBox" id="vbox1">
769+ <property name="visible">True</property>
770+ <property name="orientation">vertical</property>
771+ <child>
772+ <object class="GtkLabel" id="label3">
773+ <property name="visible">True</property>
774+ <property name="label" translatable="yes">The Transition file and Icon file must have the same file name,
775+and the Icon should be 80x62.</property>
776+ </object>
777+ <packing>
778+ <property name="padding">6</property>
779+ <property name="position">0</property>
780+ </packing>
781+ </child>
782+ <child>
783+ <object class="GtkTable" id="table1">
784+ <property name="visible">True</property>
785+ <property name="n_rows">2</property>
786+ <property name="n_columns">2</property>
787+ <child>
788+ <object class="GtkLabel" id="label1">
789+ <property name="visible">True</property>
790+ <property name="xalign">0</property>
791+ <property name="xpad">10</property>
792+ <property name="label" translatable="yes">Select Transition:</property>
793+ </object>
794+ <packing>
795+ <property name="x_options">GTK_FILL</property>
796+ </packing>
797+ </child>
798+ <child>
799+ <object class="GtkLabel" id="label2">
800+ <property name="visible">True</property>
801+ <property name="xalign">0</property>
802+ <property name="xpad">12</property>
803+ <property name="label" translatable="yes">Select Icon:</property>
804+ </object>
805+ <packing>
806+ <property name="top_attach">1</property>
807+ <property name="bottom_attach">2</property>
808+ <property name="x_options">GTK_FILL</property>
809+ </packing>
810+ </child>
811+ <child>
812+ <object class="GtkFileChooserButton" id="fileTransition">
813+ <property name="visible">True</property>
814+ <property name="create_folders">False</property>
815+ <signal name="file_set" handler="on_fileTransition_file_set"/>
816+ </object>
817+ <packing>
818+ <property name="left_attach">1</property>
819+ <property name="right_attach">2</property>
820+ <property name="x_padding">12</property>
821+ <property name="y_padding">12</property>
822+ </packing>
823+ </child>
824+ <child>
825+ <object class="GtkFileChooserButton" id="fileIcon">
826+ <property name="visible">True</property>
827+ <property name="create_folders">False</property>
828+ <signal name="file_set" handler="on_fileIcon_file_set"/>
829+ </object>
830+ <packing>
831+ <property name="left_attach">1</property>
832+ <property name="right_attach">2</property>
833+ <property name="top_attach">1</property>
834+ <property name="bottom_attach">2</property>
835+ <property name="x_padding">12</property>
836+ <property name="y_padding">12</property>
837+ </packing>
838+ </child>
839+ </object>
840+ <packing>
841+ <property name="position">2</property>
842+ </packing>
843+ </child>
844+ <child>
845+ <object class="GtkHButtonBox" id="hbuttonbox1">
846+ <property name="visible">True</property>
847+ <property name="layout_style">end</property>
848+ <child>
849+ <object class="GtkButton" id="btnCancel">
850+ <property name="label">gtk-cancel</property>
851+ <property name="visible">True</property>
852+ <property name="can_focus">True</property>
853+ <property name="receives_default">True</property>
854+ <property name="use_stock">True</property>
855+ <signal name="clicked" handler="on_btnCancel_clicked"/>
856+ </object>
857+ <packing>
858+ <property name="expand">False</property>
859+ <property name="fill">False</property>
860+ <property name="position">0</property>
861+ </packing>
862+ </child>
863+ <child>
864+ <object class="GtkButton" id="btnOK">
865+ <property name="label">gtk-ok</property>
866+ <property name="visible">True</property>
867+ <property name="sensitive">False</property>
868+ <property name="can_focus">True</property>
869+ <property name="receives_default">True</property>
870+ <property name="use_stock">True</property>
871+ <signal name="clicked" handler="on_btnOK_clicked"/>
872+ </object>
873+ <packing>
874+ <property name="expand">False</property>
875+ <property name="fill">False</property>
876+ <property name="position">1</property>
877+ </packing>
878+ </child>
879+ </object>
880+ <packing>
881+ <property name="fill">False</property>
882+ <property name="padding">1</property>
883+ <property name="pack_type">end</property>
884+ <property name="position">1</property>
885+ </packing>
886+ </child>
887+ </object>
888+ </child>
889+ </object>
890+</interface>
891
892=== modified file 'openshot/windows/ui/Main.ui'
893--- openshot/windows/ui/Main.ui 2010-07-04 20:03:37 +0000
894+++ openshot/windows/ui/Main.ui 2010-07-12 22:08:40 +0000
895@@ -77,6 +77,15 @@
896 </object>
897 </child>
898 <child>
899+ <object class="GtkImageMenuItem" id="mnuImportTransitions">
900+ <property name="label" translatable="yes">Import New Transition...</property>
901+ <property name="visible">True</property>
902+ <property name="use_stock">False</property>
903+ <property name="accel_group">accelgroup1</property>
904+ <signal name="activate" handler="on_mnuImportTransitions_activate"/>
905+ </object>
906+ </child>
907+ <child>
908 <object class="GtkSeparatorMenuItem" id="separatormenuitem3">
909 <property name="visible">True</property>
910 </object>
911
912=== modified file 'openshot/windows/ui/Main_clip_properties.ui'
913--- openshot/windows/ui/Main_clip_properties.ui 2010-05-03 05:51:49 +0000
914+++ openshot/windows/ui/Main_clip_properties.ui 2010-07-12 22:08:40 +0000
915@@ -69,6 +69,15 @@
916 </object>
917 </child>
918 <child>
919+ <object class="GtkImageMenuItem" id="mnuReplaceClip">
920+ <property name="label" translatable="yes">Replace Clip</property>
921+ <property name="visible">True</property>
922+ <property name="image">image1</property>
923+ <property name="use_stock">False</property>
924+ <signal name="activate" handler="on_mnuReplaceClip_activate"/>
925+ </object>
926+ </child>
927+ <child>
928 <object class="GtkImageMenuItem" id="mnuRemoveClip">
929 <property name="label" translatable="yes">Remove Clip</property>
930 <property name="visible">True</property>
931@@ -94,4 +103,8 @@
932 </child>
933 </object>
934 <object class="GtkAccelGroup" id="accelgroup1"/>
935+ <object class="GtkImage" id="image1">
936+ <property name="visible">True</property>
937+ <property name="stock">gtk-missing-image</property>
938+ </object>
939 </interface>

Subscribers

People subscribed via source and target branches

to status/vote changes: