Fix for bl_info blender versions, many addons used (2, 6, x) instead of (2, 6x, x...
[blender-addons-contrib.git] / sequencer_jumptocut.py
1 # ##### BEGIN GPL LICENSE BLOCK #####
2 #
3 #  This program is free software; you can redistribute it and/or
4 #  modify it under the terms of the GNU General Public License
5 #  as published by the Free Software Foundation; either version 2
6 #  of the License, or (at your option) any later version.
7 #
8 #  This program is distributed in the hope that it will be useful,
9 #  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 #  GNU General Public License for more details.
12 #
13 #  You should have received a copy of the GNU General Public License
14 #  along with this program; if not, write to the Free Software Foundation,
15 #  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 #
17 # ##### END GPL LICENSE BLOCK #####
18
19
20 bl_info = {
21     "name": "Jump to Cut",
22     "author": "Carlos Padial",
23     "version": (5, 0, 2),
24     "blender": (2, 63, 0),
25     "api": 44539,
26     "category": "Sequencer",
27     "location": "Sequencer > UI > Jump to Cut",
28     "description": "Tool collection to help speed up editting and grade videos with blender",
29     "warning": "",
30     "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/Sequencer/Jump_to_cut",
31     "tracker_url": "https://projects.blender.org/tracker/index.php?func=detail&aid=24279",}
32
33 #
34
35 #
36 #-----------------------------------------------------------------------------------------------------
37 import bpy
38
39 class Jumptocut(bpy.types.Panel):
40     bl_space_type = "SEQUENCE_EDITOR"
41     bl_region_type = "UI"
42     bl_label = "Jump to Cut"  
43
44     def draw_header(self, context):
45         layout = self.layout
46         layout.label(text="", icon="NLA")
47     
48     def draw(self, context):
49         layout = self.layout
50        
51         row=layout.row()
52         split=row.split(percentage=0.5)
53         colL = split.column()
54         colR = split.column()
55         colL.operator("sequencer.jumpprev", icon="PLAY_REVERSE")
56         colR.operator("sequencer.jumpnext", icon='PLAY')
57
58         row=layout.row()
59         split=row.split()
60         colL = split.column()
61         colR = split.column()
62         colL.operator("sequencer.markprev", icon="MARKER_HLT")
63         colR.operator("sequencer.marknext", icon='MARKER_HLT')
64         
65         row=layout.row()
66         split=row.split()
67         colL1 = split.column()
68         colL2 = split.column()
69         colL1.operator("sequencer.sourcein", icon="REW")
70         colL2.operator("sequencer.sourceout", icon='FF')
71  
72         
73         row=layout.row()
74         split=row.split()
75         colR1 = split.column()
76         colR1.operator("sequencer.setinout", icon="ARROW_LEFTRIGHT")
77         row=layout.row()
78         split=row.split(percentage=0.5)
79         colR1 = split.column()
80         colR1.operator("sequencer.triminout", icon="FULLSCREEN_EXIT") 
81         colR2 = split.column()
82         colR2.operator("sequencer.setstartend", icon="SETTINGS")
83
84         row=layout.row()
85         split=row.split()
86         colR1 = split.column()
87         colR2 = split.column()
88         colR1.operator("sequencer.metacopy", icon="COPYDOWN")
89         colR2.operator("sequencer.metapaste", icon='PASTEDOWN')
90         
91 #-----------------------------------------------------------------------------------------------------
92
93 class OBJECT_OT_Setinout(bpy.types.Operator):  
94     bl_label = "Mark in & out to active strip"
95     bl_idname = "sequencer.setinout"
96     bl_description = "set IN and OUT markers to the active strip limits"
97         
98     def invoke(self, context, event):
99         scene=bpy.context.scene
100         markers=scene.timeline_markers
101         seq=scene.sequence_editor
102         if seq:
103             strip= seq.active_strip
104             if strip != None:
105                 sin = strip.frame_start + strip.frame_offset_start
106                 sout = sin + strip.frame_final_duration 
107                 if "IN" not in markers:
108                     mark=markers.new(name="IN")
109                     mark.frame=sin
110                 else:
111                     mark=markers["IN"]
112                     mark.frame=sin
113                 if "OUT" not in markers:
114                     mark= markers.new(name="OUT")
115                     mark.frame=sout
116                 else:
117                     mark=markers["OUT"]
118                     mark.frame=sout 
119         return {'FINISHED'}
120     
121
122 def triminout(strip,sin,sout):
123     start = strip.frame_start+strip.frame_offset_start 
124     end = start+strip.frame_final_duration
125     if end > sin:
126         if start < sin:
127             strip.select_right_handle = False            
128             strip.select_left_handle = True
129             bpy.ops.sequencer.snap(frame=sin)
130             strip.select_left_handle = False
131     if start < sout:
132         if end > sout:
133             strip.select_left_handle = False            
134             strip.select_right_handle = True
135             bpy.ops.sequencer.snap(frame=sout)
136             strip.select_right_handle = False    
137     return {'FINISHED'}
138
139
140 class OBJECT_OT_Triminout(bpy.types.Operator):  
141     bl_label = "Trim to in & out"
142     bl_idname = "sequencer.triminout"
143     bl_description = "trim the selected strip to IN and OUT markers (if exists)"
144         
145     def invoke(self, context, event):
146         scene=bpy.context.scene
147         markers=scene.timeline_markers
148         seq=scene.sequence_editor
149         if seq:
150             strip= seq.active_strip
151             if strip != None:
152                 if "IN" and "OUT" in markers:
153                     sin=markers["IN"].frame
154                     sout=markers["OUT"].frame
155                     triminout(strip,sin,sout)
156                 else:
157                     self.report({'WARNING'}, "there is no IN and OUT")
158             bpy.ops.sequencer.reload()
159         return {'FINISHED'}
160
161 def searchprev(j, list):
162     list.sort(reverse=True)
163     for i in list:
164         if i < j:
165             result = i
166             break 
167     else: result = j
168     return result
169
170 def searchnext(j, list): 
171     list.sort()
172     for i in list:
173         if i > j:
174             result = i
175             break
176     else: result = j
177     return result  
178
179 def geteditpoints(seq):
180     #this create a list of editpoints including strips from
181     # inside metastrips. It reads only 1 level into the metastrip
182     editpoints = []
183     cliplist = []
184     metalist = []
185     if seq:
186         for i in seq.sequences:
187             if i.type == 'META':
188                 metalist.append(i)
189                 start = i.frame_start + i.frame_offset_start
190                 end = start + i.frame_final_duration
191                 editpoints.append(start)
192                 editpoints.append(end)
193             else:
194                 cliplist.append(i)
195         for i in metalist:
196             for j in i.sequences:
197                 cliplist.append(j)  
198         for i in cliplist:
199             start = i.frame_start + i.frame_offset_start
200             end = start + i.frame_final_duration
201             editpoints.append(start)
202             editpoints.append(end)
203             #print(start," ",end)
204     return editpoints
205
206 #JUMP    
207 class OBJECT_OT_Jumpprev(bpy.types.Operator):  #Operator jump previous edit point
208     bl_label = "Cut previous"
209     bl_idname = "sequencer.jumpprev"
210     bl_description = "jump to previous edit point"
211     
212     editpoints = []
213         
214     def invoke(self, context, event):
215         scene=bpy.context.scene
216         seq=scene.sequence_editor
217         editpoints = geteditpoints(seq)
218         bpy.context.scene.frame_current = searchprev(scene.frame_current, editpoints) 
219         return {'FINISHED'}   
220            
221 class OBJECT_OT_Jumpnext(bpy.types.Operator):  #Operator jump next edit point
222     bl_label = "Cut next"
223     bl_idname = "sequencer.jumpnext"
224     bl_description = "jump to next edit point"
225     
226     def invoke(self, context, event):
227         scene=bpy.context.scene
228         seq=scene.sequence_editor
229         editpoints = geteditpoints(seq)
230         bpy.context.scene.frame_current = searchnext(scene.frame_current, editpoints)
231         last = 0
232         for i in editpoints:
233             if i > last: last = i
234         if bpy.context.scene.frame_current == last:
235             bpy.context.scene.frame_current = last-1
236             self.report({'INFO'},'Last Frame')
237         return {'FINISHED'}
238  
239 # MARKER 
240 class OBJECT_OT_Markerprev(bpy.types.Operator): 
241     bl_label = "Marker previous"
242     bl_idname = "sequencer.markprev"
243     bl_description = "jump to previous marker"
244         
245     def invoke(self, context, event):
246         markerlist = []
247         scene= bpy.context.scene
248         markers = scene.timeline_markers
249         for i in markers: markerlist.append(i.frame)
250         bpy.context.scene.frame_current = searchprev(scene.frame_current, markerlist)
251         return {'FINISHED'}
252     
253 class OBJECT_OT_Markernext(bpy.types.Operator):  
254     bl_label = "Marker next"
255     bl_idname = "sequencer.marknext"
256     bl_description = "jump to next marker"
257         
258     def invoke(self, context, event):
259         markerlist = []
260         scene= bpy.context.scene
261         markers = scene.timeline_markers
262         for i in markers: markerlist.append(i.frame)
263         bpy.context.scene.frame_current = searchnext(scene.frame_current, markerlist)
264         return {'FINISHED'}
265
266 # SOURCE IN OUT
267               
268 class OBJECT_OT_Sourcein(bpy.types.Operator):  #Operator source in
269     bl_label = "Source IN"
270     bl_idname = "sequencer.sourcein"
271     bl_description = "add a marker named IN"
272     
273     def invoke(self, context, event):
274         scene=bpy.context.scene
275         seq = scene.sequence_editor
276         markers=scene.timeline_markers
277         if "OUT" in markers:
278             sout=markers["OUT"]
279             if scene.frame_current <= sout.frame:
280                 if "IN" not in markers:
281                     sin=markers.new(name="IN")
282                     sin.frame=scene.frame_current
283                 else:
284                     sin=markers["IN"]
285                     sin.frame=scene.frame_current
286             #trying to set in after out
287             else:  
288                 if "IN" not in markers:
289                     sin=markers.new(name="IN")
290                     sin.frame=sout.frame
291                 else:
292                     sin=markers["IN"]
293                     sin.frame=sout.frame
294                 self.report({'WARNING'},'IN after OUT')
295         else:
296             if "IN" not in markers:
297                 sin=markers.new(name="IN")
298                 sin.frame=scene.frame_current
299             else:
300                 sin=markers["IN"]
301                 sin.frame=scene.frame_current
302         if seq:
303             bpy.ops.sequencer.reload()
304         return {'FINISHED'}
305
306 class OBJECT_OT_Sourceout(bpy.types.Operator):  #Operator source out
307     bl_label = "Source OUT"
308     bl_idname = "sequencer.sourceout"
309     bl_description = "add a marker named OUT"
310     
311     def invoke(self, context, event):
312         scene=bpy.context.scene
313         seq = scene.sequence_editor
314         markers=scene.timeline_markers
315         if "IN" in markers:
316             sin=markers["IN"]
317             if scene.frame_current >= sin.frame:
318                 if "OUT" not in markers:
319                     sout= markers.new(name="OUT")
320                     sout.frame=scene.frame_current
321                 else:
322                     sout=markers["OUT"]
323                     sout.frame=scene.frame_current 
324             #trying to set out before in 
325             else:
326                 if "OUT" not in markers:
327                     sout= markers.new(name="OUT")
328                     sout.frame = sin.frame
329                 else:
330                     sout=markers["OUT"]
331                     sout.frame = sin.frame 
332                 self.report({'WARNING'}, "OUT before IN")
333         else:
334             sout= markers.new(name="OUT")
335             sout.frame=scene.frame_current
336         if seq:
337             bpy.ops.sequencer.reload()
338         return {'FINISHED'}
339
340
341
342 class OBJECT_OT_Setstartend(bpy.types.Operator):  #Operator set start & end
343     bl_label = "set Start & End"
344     bl_idname = "sequencer.setstartend"
345     bl_description = "set Start = In and End = Out"
346     
347     def invoke(self, context, event):
348         scene=bpy.context.scene
349         seq = scene.sequence_editor
350         markers=scene.timeline_markers
351         if seq:
352             if "IN" and "OUT" in markers:
353                 sin=markers["IN"]
354                 sout=markers["OUT"]
355                 scene.frame_start = sin.frame
356                 scene.frame_end = sout.frame
357                 print("change")
358             else:
359                 self.report({'WARNING'}, "there is no IN and OUT")
360             bpy.ops.sequencer.reload()
361         return {'FINISHED'}
362
363     
364 # COPY PASTE
365
366 class OBJECT_OT_Metacopy(bpy.types.Operator):  #Operator copy source in/out
367     bl_label = "Trim & Meta-Copy"
368     bl_idname = "sequencer.metacopy"
369     bl_description = "make meta from selected strips, trim it to in/out (if available) and copy it to clipboard"
370     
371     def invoke(self, context, event):
372         # rehacer
373         scene=bpy.context.scene
374         seq = scene.sequence_editor
375         markers=scene.timeline_markers
376         strip1= seq.active_strip
377         if strip1 != None:
378             if "IN" and "OUT" in markers:
379                 sin=markers["IN"].frame
380                 sout=markers["OUT"].frame
381                 bpy.ops.sequencer.meta_make()
382                 strip2= seq.active_strip
383                 triminout(strip2,sin,sout)
384                 bpy.ops.sequencer.copy()
385                 bpy.ops.sequencer.meta_separate()
386                 self.report({'INFO'}, "META has been trimed and copied")              
387             else:
388                 bpy.ops.sequencer.meta_make()
389                 bpy.ops.sequencer.copy()
390                 bpy.ops.sequencer.meta_separate()
391                 self.report({'WARNING'}, "No In & Out!! META has been copied")
392         else:
393             self.report({'ERROR'}, "No strip selected")
394         return {'FINISHED'}
395         
396 class OBJECT_OT_Metapaste(bpy.types.Operator):  #Operator paste source in/out
397     bl_label = "Paste in current Frame"
398     bl_idname = "sequencer.metapaste"
399     bl_description = "paste source from clipboard to current frame"
400     
401     def invoke(self, context, event):
402         # rehacer
403         scene=bpy.context.scene
404         bpy.ops.sequencer.paste()
405         bpy.ops.sequencer.snap(frame=scene.frame_current)
406         return {'FINISHED'}
407
408 # Registering / Unregister
409  
410 def register():
411     bpy.utils.register_class(Jumptocut)
412     bpy.utils.register_class(OBJECT_OT_Jumpprev)
413     bpy.utils.register_class(OBJECT_OT_Jumpnext)
414     bpy.utils.register_class(OBJECT_OT_Markerprev)
415     bpy.utils.register_class(OBJECT_OT_Markernext)    
416     bpy.utils.register_class(OBJECT_OT_Sourcein)
417     bpy.utils.register_class(OBJECT_OT_Sourceout)
418     bpy.utils.register_class(OBJECT_OT_Metacopy)
419     bpy.utils.register_class(OBJECT_OT_Metapaste)
420     bpy.utils.register_class(OBJECT_OT_Triminout)
421     bpy.utils.register_class(OBJECT_OT_Setinout)
422     bpy.utils.register_class(OBJECT_OT_Setstartend)
423     
424 def unregister():
425     bpy.utils.unregister_class(Jumptocut)
426     bpy.utils.unregister_class(OBJECT_OT_Jumpprev)
427     bpy.utils.unregister_class(OBJECT_OT_Jumpnext)
428     bpy.utils.unregister_class(OBJECT_OT_Markerprev)
429     bpy.utils.unregister_class(OBJECT_OT_Markernext)      
430     bpy.utils.unregister_class(OBJECT_OT_Sourcein)
431     bpy.utils.unregister_class(OBJECT_OT_Sourceout)
432     bpy.utils.unregister_class(OBJECT_OT_Metacopy)
433     bpy.utils.unregister_class(OBJECT_OT_Metapaste)
434     bpy.utils.unregister_class(OBJECT_OT_Triminout)
435     bpy.utils.unregister_class(OBJECT_OT_Setinout)
436     bpy.utils.unregister_class(OBJECT_OT_Setstartend)
437 if __name__ == "__main__":
438     register()