Merge lp:~fincha/openshot/andy-1.2 into lp:openshot/1.4
- andy-1.2
- Merge into main
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 | ||||||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Jonathan Thomas | Pending | ||
Review via email: mp+29753@code.launchpad.net |
Commit message
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> |