~openshot.code/openshot/main

« back to all changes in this revision

Viewing changes to main/classes/transition.py

  • Committer: Jonathan Thomas
  • Date: 2009-09-08 04:49:08 UTC
  • Revision ID: jonathan@jonathan64-20090908044908-kzhw2m1dl251yt9y
Bumping version to 0.9.30

Here it goes.  Massive re-factoring across OpenShot.  I put
a ton of regression work into this to ensure everything still
works, but as always, I could have missed something.

The biggest changes: 
------------------------------
1) Distutils is now used to install OpenShot (setup.py install).
   Installing OpenShot this way will copy Mime Types, Register Icons,
   Add launcher to Application menu, and copy the OpenShot .py code 
   to the /site-packages/ folder.
2) Python code moved into ~/openshot/openshot/
3) New folders ~/openshot/[bin,docs,xdg]
4) Translations moved to ~/openshot/openshot/locale
5) classes/project.py contains all of the PATH variables
6) classes/info.py contains the version of OpenShot
7) after installing (using setup.py), the /openshot/bin/openshot 
   is the launcher that gets copied to the /usr/bin
8) A few bug fixes have also been added:
   A) removing marker clears timeline
   B) opening a project stopped some changes from refreshing the video
9) Arguments can be passed to OpenShot ($ openshot 'video1.avi', 'video2.avi')
------------------------------

There are now 2 ways to launch OpenShot.

$ openshot (assuming setup.py was used to install OpenShot)
$ ~/openshot/openshot/openshot.py  (I know... it looks funny)

Good luck to everyone testing this!  =)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#       OpenShot Video Editor is a program that creates, modifies, and edits video files.
2
 
#   Copyright (C) 2009  Jonathan Thomas
3
 
#
4
 
#       This file is part of OpenShot Video Editor (http://launchpad.net/openshot/).
5
 
#
6
 
#       OpenShot Video Editor is free software: you can redistribute it and/or modify
7
 
#       it under the terms of the GNU General Public License as published by
8
 
#       the Free Software Foundation, either version 3 of the License, or
9
 
#       (at your option) any later version.
10
 
#
11
 
#       OpenShot Video Editor is distributed in the hope that it will be useful,
12
 
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
#       GNU General Public License for more details.
15
 
#
16
 
#       You should have received a copy of the GNU General Public License
17
 
#       along with OpenShot Video Editor.  If not, see <http://www.gnu.org/licenses/>.
18
 
 
19
 
import gtk
20
 
import goocanvas
21
 
import os
22
 
import uuid
23
 
 
24
 
########################################################################
25
 
class transition:
26
 
        """This class represents a media clip on the timeline."""
27
 
 
28
 
        #----------------------------------------------------------------------
29
 
        def __init__(self, name, position_on_track, length, resource, parent, type="transition", mask_value=50.0):
30
 
                """Constructor"""
31
 
                
32
 
                # init variables for clip object
33
 
                self.name = name
34
 
                self.position_on_track = float(position_on_track)  # the time in seconds where the transition starts on the timeline
35
 
                self.length = float(length)             # the length in seconds of this transition
36
 
                self.resource = resource                                # Any grey-scale image, or leave empty for a disolve
37
 
                self.softness = 0.3                             # 0.0 = no softness. 1.0 = too soft.    
38
 
                self.reverse = False
39
 
                self.unique_id = str(uuid.uuid1())
40
 
                self.parent = parent                    # the sequence
41
 
                
42
 
                # mask settings
43
 
                self.type = type                                # transition or mask
44
 
                self.mask_value = mask_value    # 0.0 to 1.0
45
 
                
46
 
                
47
 
        def length(self):
48
 
 
49
 
                # return length
50
 
                return self.length
51
 
        
52
 
                
53
 
        def Render(self, exiting_item=None, x_offset = 0):
54
 
                
55
 
                # init vars
56
 
                pixels_per_second = self.parent.parent.get_pixels_per_second()
57
 
                x = float(self.position_on_track * pixels_per_second) + x_offset
58
 
                width = self.length * pixels_per_second
59
 
                height = 40
60
 
                
61
 
                if self.parent:
62
 
                        # get bottom y of track
63
 
                        y = self.parent.y_bottom - 20
64
 
                else:
65
 
                        y = 20
66
 
                                
67
 
 
68
 
                # get a reference to the 2 main canvas objects & theme
69
 
                theme = self.parent.parent.project.theme
70
 
                
71
 
                # Get root group of the canvas
72
 
                canvas_right = self.parent.parent.project.form.MyCanvas
73
 
                root_right = canvas_right.get_root_item ()              
74
 
                
75
 
                if exiting_item == None:
76
 
                        # Create the Group (for the clip)
77
 
                        GroupTransition = goocanvas.Group (parent = root_right)
78
 
                        
79
 
                        # set the unique ID of the group
80
 
                        GroupTransition.set_data ("id", self.unique_id)
81
 
        
82
 
                        # Add a translucent blue rectangle
83
 
                        rec2 = goocanvas.Rect (parent = GroupTransition,
84
 
                                                                  x = x,
85
 
                                                                  y = y,
86
 
                                                                  width = width,
87
 
                                                                  height = height,
88
 
                                                                  line_width = 1,
89
 
                                                                  stroke_color_rgba = 1401402500,
90
 
                                                                  fill_color_rgba = 1401402500)
91
 
                        rec2.set_data ("id", "tran_rectangle")
92
 
                        
93
 
                        # add text to the transition
94
 
                        text1 = goocanvas.Text (parent = GroupTransition,
95
 
                                                                text = "%s" % self.name,
96
 
                                                                font = "Sans 8",
97
 
                                                                antialias = False,
98
 
                                                                x = x + 8,
99
 
                                                                y = y + 2,
100
 
                                                                width = width - 8,
101
 
                                                                ellipsize = 3)
102
 
                        text1.set_data ("id", "tran_text")
103
 
                        
104
 
                        # hide text (if transition is too small)
105
 
                        if width <= 20:
106
 
                                text1.set_properties(visibility = 1)
107
 
                        else:
108
 
                                text1.set_properties(visibility = 2)
109
 
                                
110
 
                                
111
 
                        # load clip images
112
 
                        if self.type == "transition":
113
 
                                # TRANSITIONS
114
 
                                if self.reverse:
115
 
                                        # DOWN
116
 
                                        imgTrans = gtk.image_new_from_file("%s/themes/%s/transition_down.png" % (self.parent.parent.project.form.openshot_path, theme))
117
 
                                else:
118
 
                                        # UP
119
 
                                        imgTrans = gtk.image_new_from_file("%s/themes/%s/transition_up.png" % (self.parent.parent.project.form.openshot_path, theme))
120
 
                        elif self.type == "mask":
121
 
                                        # MASK
122
 
                                        imgTrans = gtk.image_new_from_file("%s/themes/%s/transition_mask.png" % (self.parent.parent.project.form.openshot_path, theme))                         
123
 
                        
124
 
                        # create canvas image object
125
 
                        canvasImageTrans = goocanvas.Image (parent = GroupTransition,
126
 
                                                                  pixbuf = imgTrans.get_pixbuf(),
127
 
                                                                  x = x + 8,
128
 
                                                                  y = y + 15)
129
 
                        canvasImageTrans.set_data ("id", "trans_direction")
130
 
                        
131
 
                        # hide up/down image (if transition is too small)
132
 
                        if width <= 32:
133
 
                                canvasImageTrans.set_properties(visibility = 1)
134
 
                        else:
135
 
                                canvasImageTrans.set_properties(visibility = 2)
136
 
                                
137
 
                        
138
 
                        # connect drag n drop events to the new cavnas group
139
 
                        GroupTransition.connect ("motion_notify_event", self.on_motion_notify_x)
140
 
                        GroupTransition.connect ("button_press_event", self.on_button_press_x)
141
 
                        GroupTransition.connect ("button_release_event", self.on_button_release_x)
142
 
                
143
 
                else:
144
 
                        # get existing item
145
 
                        GroupTransition = exiting_item
146
 
                        
147
 
                        # get existing object
148
 
                        rec2 = self.get_canvas_child(GroupTransition, "tran_rectangle")
149
 
                        text1 = self.get_canvas_child(GroupTransition, "tran_text")
150
 
                        canvasImageTrans = self.get_canvas_child(GroupTransition, "trans_direction")
151
 
                        
152
 
                        # resize transition
153
 
                        rec2.set_properties(x = x)
154
 
                        text1.set_properties(x = x + 8)
155
 
                        canvasImageTrans.set_properties(x = x + 8)
156
 
                        rec2.set_properties(width = width)
157
 
                        text1.set_properties(width = width - 8)
158
 
                        
159
 
                        # hide text (if transition is too small)
160
 
                        if width <= 20:
161
 
                                text1.set_properties(visibility = 1)
162
 
                        else:
163
 
                                text1.set_properties(visibility = 2)
164
 
                                
165
 
                        # hide up/down image (if transition is too small)
166
 
                        if width <= 32:
167
 
                                canvasImageTrans.set_properties(visibility = 1)
168
 
                        else:
169
 
                                canvasImageTrans.set_properties(visibility = 2)
170
 
 
171
 
                # return the gooCanvas transition object
172
 
                return GroupTransition
173
 
        
174
 
        
175
 
        
176
 
        def get_canvas_child(self, group, requested_child_id):
177
 
                """this method loops though the children objects of this group looking 
178
 
                for the item with a specfic id."""
179
 
                
180
 
                for index in range(0, group.get_n_children()):
181
 
                        child = group.get_child(index)
182
 
                        child_id = child.get_data ("id")
183
 
 
184
 
                        if child_id == requested_child_id:
185
 
                                return child
186
 
                        
187
 
                return None
188
 
        
189
 
         
190
 
        def on_button_press_x (self, item, target, event):
191
 
                """ This method initializes some variables needed for dragging and dropping a clip """
192
 
                # raise the group up to the top level
193
 
                item.raise_(None)
194
 
                
195
 
                # set the x and y where the cursor started dragging from
196
 
                self.drag_x = event.x
197
 
                self.drag_y = event.y
198
 
 
199
 
                # only respond to the first mouse button
200
 
                if event.button == 1:
201
 
 
202
 
                        # determine what cursor mode is enable (arrow, razor, snap, etc...)
203
 
                        (isArrow, isRazor, isSnap, isResize) = self.parent.parent.project.form.get_toolbar_options()
204
 
                        
205
 
                        # ARROW MODE
206
 
                        if isArrow:
207
 
 
208
 
                                # change the cursor for the drag n drop operation
209
 
                                fleur = gtk.gdk.Cursor (gtk.gdk.FLEUR)
210
 
                                canvas = item.get_canvas ()
211
 
                                canvas.pointer_grab (item, gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK, fleur, event.time)
212
 
                        
213
 
                        # RESIZE MODE
214
 
                        elif isResize:
215
 
                                
216
 
                                # remember the original length and position before resizing starts
217
 
                                self.original_length = self.length
218
 
                                self.original_start_pos = self.position_on_track
219
 
 
220
 
 
221
 
                        # SNAP MODE
222
 
                        elif isSnap:
223
 
                                pass
224
 
 
225
 
                elif event.button == 3:
226
 
                        
227
 
                        # show the track popup menu
228
 
                        self.parent.parent.project.form.mnuTransition1.showmnu(event, self, item)
229
 
 
230
 
 
231
 
                return True
232
 
        
233
 
        
234
 
        def on_motion_notify_x (self, item, target, event):
235
 
                """this method allows the clip to be dragged and dropped on a track"""    
236
 
 
237
 
                # get the new x,y coordinates from the mouse
238
 
                new_x = event.x
239
 
                new_y = event.y 
240
 
                
241
 
                # get the pixels per second from the parent sequence
242
 
                pixels_per_second = self.parent.parent.get_pixels_per_second()
243
 
                
244
 
                # determine end pixel of sequence
245
 
                end_of_timeline = self.parent.parent.length * pixels_per_second
246
 
                
247
 
                # determine what cursor mode is enable (arrow, razor, snap, etc...)
248
 
                (isArrow, isRazor, isSnap, isResize) = self.parent.parent.project.form.get_toolbar_options()
249
 
                
250
 
                # ARROW MODE
251
 
                if isArrow:
252
 
                        
253
 
                        # Move the clip based on the x, y of the mouse
254
 
                        if (event.state & gtk.gdk.BUTTON1_MASK):
255
 
 
256
 
                                # don't allow the clip to slide past the beginning of the canvas
257
 
                                total_x_diff = new_x - self.drag_x 
258
 
                                total_y_diff = event.y - self.drag_y
259
 
                                if (item.get_bounds().x1 + total_x_diff < 0):
260
 
                                        total_x_diff = 0 - item.get_bounds().x1
261
 
                                elif (item.get_bounds().x2 + total_x_diff > end_of_timeline):
262
 
                                        total_x_diff = end_of_timeline - item.get_bounds().x2
263
 
                                
264
 
                                # get the track under this transition (the top track)
265
 
                                drop_track = self.get_valid_drop(item.get_bounds().x1, item.get_bounds().y1)
266
 
 
267
 
                                # mark project as modified
268
 
                                self.parent.parent.project.is_modified = True
269
 
 
270
 
                                # move clip
271
 
                                item.translate (total_x_diff, total_y_diff)
272
 
 
273
 
 
274
 
 
275
 
                # RESIZE MODE
276
 
                if isResize:
277
 
                        
278
 
                        # update cursor
279
 
                        self.parent.parent.project.form.current_cursor[1] = int(event.x_root)
280
 
                        self.parent.parent.project.form.current_cursor[2] = int(event.y_root)
281
 
                        self.parent.parent.project.form.current_cursor[3] = "clip"
282
 
                        
283
 
                        if (event.state & gtk.gdk.BUTTON1_MASK):
284
 
 
285
 
                                # get the direction from the cursor object
286
 
                                direction = self.parent.parent.project.form.current_cursor[0]
287
 
                                
288
 
                        else:
289
 
                                # only calculate LEFT or RIGHT when the mouse is not clicked.  Once the user starts resizing
290
 
                                # a clip, we want to just use the direction in the cursor object.  In other words, we can't allow
291
 
                                # the direction to change while we are resizing.
292
 
                                # determine if user is resizing the LEFT or RIGHT side of the clip
293
 
                                length = float(self.length)
294
 
                                
295
 
                                left_of_clip = self.position_on_track * pixels_per_second
296
 
                                center_of_clip = left_of_clip + ((length / 2.0) * pixels_per_second)
297
 
                                right_of_clip = left_of_clip + (length * pixels_per_second)
298
 
                                
299
 
                                direction = "left"
300
 
                                if event.x_root < center_of_clip:
301
 
                                        direction = "left"
302
 
                                else:
303
 
                                        direction = "right"
304
 
                                
305
 
                                # if right, update the cursor the "right grab" icon
306
 
                                if direction == "right":
307
 
                                        # update cursor variable
308
 
                                        if self.parent.parent.project.form.current_cursor[0] != "right":
309
 
        
310
 
                                                # change cursor to "right bar"
311
 
                                                self.parent.parent.project.form.current_cursor[0] = "right"
312
 
                                                self.parent.parent.project.form.MyCanvas.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.RIGHT_SIDE)) 
313
 
        
314
 
                                # if left, update the cursor the "left grab" icon
315
 
                                if direction == "left":
316
 
                                        # update cursor variable
317
 
                                        if self.parent.parent.project.form.current_cursor[0] != "left":
318
 
                                                
319
 
                                                # change cursor to "left bar"
320
 
                                                self.parent.parent.project.form.current_cursor[0] = "left" 
321
 
                                                self.parent.parent.project.form.MyCanvas.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_SIDE))
322
 
 
323
 
                        
324
 
                        # Move the clip based on the x, y of the mouse (if the mouse button is pressed)
325
 
                        if (event.state & gtk.gdk.BUTTON1_MASK):
326
 
                                
327
 
                                # Get side of clip that is being re-sized
328
 
                                side = self.parent.parent.project.form.current_cursor[0]  # left or right
329
 
                                
330
 
                                # Get the x and y difference
331
 
                                original_end_pos = (self.original_start_pos * pixels_per_second) + (self.original_length * pixels_per_second)
332
 
                                x_offset = event.x - event.x_root
333
 
 
334
 
                                if side == "left":
335
 
                                        # calculate new start position and length
336
 
                                        new_position = float(event.x_root) / float(pixels_per_second)
337
 
                                        new_length = float(original_end_pos - event.x_root) / pixels_per_second
338
 
                                        #new_start_time = self.end_time - new_length
339
 
                                                
340
 
                                        # update the properties of this clip
341
 
                                        if new_position >= 0 and new_length >= 0:
342
 
                                                
343
 
                                                # mark project as modified
344
 
                                                self.parent.parent.project.is_modified = True
345
 
                                                
346
 
                                                self.position_on_track = new_position
347
 
                                                self.length = new_length
348
 
                                                #self.start_time = new_start_time
349
 
                                                
350
 
                                                # adjust x for windows
351
 
                                                if os.name == 'nt':
352
 
                                                        x_offset = x_offset - 2
353
 
                                                        
354
 
                                                # re-render this clip to the canvas (passing the canvas group to the RenderClip method)
355
 
                                                self.Render(item, x_offset)
356
 
 
357
 
                                else:
358
 
                                        # RIGHT side
359
 
                                        # calculate the new clip length
360
 
                                        new_length = (event.x_root - (self.position_on_track * pixels_per_second)) / pixels_per_second
361
 
                                        self.length = new_length
362
 
 
363
 
                                        # update the properties of this clip
364
 
                                        if new_length > 0:
365
 
                                        
366
 
                                                # mark project as modified
367
 
                                                self.parent.parent.project.is_modified = True
368
 
        
369
 
                                                # re-render this clip to the canvas (passing the canvas group to the RenderClip method)
370
 
                                                self.Render(item, x_offset)
371
 
 
372
 
                return True
373
 
        
374
 
        
375
 
        
376
 
        def on_button_release_x (self, item, target, event):
377
 
                """ This method drops a clip, and snaps the clip to the nearest valid track """
378
 
 
379
 
                # raise the play head to the top
380
 
                self.parent.parent.play_head.raise_(None)
381
 
 
382
 
                # get reference to the canvas, and stop dragging the item
383
 
                canvas = item.get_canvas()
384
 
                canvas.pointer_ungrab (item, event.time)
385
 
                
386
 
                # determine what cursor mode is enable (arrow, razor, snap, etc...)
387
 
                (isArrow, isRazor, isSnap, isResize) = self.parent.parent.project.form.get_toolbar_options()
388
 
                
389
 
                if isArrow:
390
 
                        # get new parent track
391
 
                        drop_track = self.get_valid_drop(item.get_bounds().x1, item.get_bounds().y1)
392
 
                        bottom_y = 0
393
 
                        
394
 
                        if drop_track == None:
395
 
                                # keep old parent, if no track found
396
 
                                drop_track = self.parent
397
 
                        
398
 
                        # get bottom y of track
399
 
                        bottom_y = drop_track.y_bottom - 20
400
 
                        
401
 
                        # get the pixels per second from the parent sequence
402
 
                        pixels_per_second = self.parent.parent.get_pixels_per_second()
403
 
                        
404
 
                        # update the position 
405
 
                        self.position_on_track = float(item.get_bounds().x1) / pixels_per_second
406
 
                        
407
 
                        # update the parent (the primary track)
408
 
                        self.update_parent(drop_track)
409
 
                        drop_track.reorder_transitions()
410
 
 
411
 
                                
412
 
                                
413
 
                        # move the clip object on the timeline to correct position (snapping to the y and x of the track)               
414
 
                        item.translate (0, bottom_y - item.get_bounds().y1)
415
 
                        
416
 
                        
417
 
                # reset the cursor
418
 
                self.parent.parent.project.form.MyCanvas.window.set_cursor(None)
419
 
                
420
 
                # mark project as modified
421
 
                self.parent.parent.project.is_modified = True
422
 
                
423
 
                
424
 
        def get_valid_drop(self, x1, y1):
425
 
                """ A clip must be dropped on a track.  This method returns the track 
426
 
                object that is under the clip's current position """
427
 
 
428
 
                # loop through each track
429
 
                track_counter = 0
430
 
                
431
 
                for track in self.parent.parent.tracks:
432
 
                        # get the top y and bottom y of each track
433
 
                        y_top = track.y_top
434
 
                        y_bottom = track.y_bottom
435
 
                        
436
 
                        # increment track counter
437
 
                        track_counter = track_counter + 1
438
 
                        
439
 
                        # determine if middle of clip is contained inside this track
440
 
                        if y1 > y_top and y1 < y_bottom and track_counter != len(self.parent.parent.tracks):
441
 
                                return track
442
 
                
443
 
                # return false if no valid track found
444
 
                return None
445
 
        
446
 
        
447
 
        def update_parent(self, parent_track):
448
 
                        """ This method updates the x and y settings of the clip in the object model """
449
 
 
450
 
                        # remove clip from current parent track (if new parent is different)
451
 
                        if (parent_track != self.parent):
452
 
                                # remove clip                           
453
 
                                self.parent.transitions.remove(self)
454
 
                                
455
 
                                # add to new parent track
456
 
                                parent_track.transitions.append(self)
457
 
                                self.parent = parent_track
 
 
b'\\ No newline at end of file'