]> git.plutz.net Git - viper/blob - timeline.py
implemeted most basic cropping controls
[viper] / timeline.py
1 #encoding: utf-8
2 #Copyright 2009 - 2011 Paul Hänsch
3
4 # This file is part of Viper.
5 #
6 # Viper 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 # Viper 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 Viper.  If not, see <http://www.gnu.org/licenses/>
18
19 from Tkinter import *
20 from vchunk import *
21 from vframeset import *
22 import Pmw
23
24 class Timeline(Frame):
25     """
26     This widget represents a sequence of video chunks.
27
28     It holds a list of chunks and provides an interface to manipulate the order
29     of these chunks. The main control widgets are placed on the VChunk ojects.
30     Properties:
31     subgets       - a dictionary of subordinated widgets 
32     chunks (list) - list of VChunk objects, do not edit this list manually
33                     use add() to add a >chunk< object, the vchunk will be
34                     built and displayed automatically
35     timer (Tk)    - internal timer for regular execution of tasks scheduled by
36                     vchunks
37     """
38
39     def __init__(self, master):
40         """
41         Constructor
42         """
43         Frame.__init__(self, master = master)
44         self.subgets = {}
45         self.chunks = []
46         self.mods = []    # list of chunk modifying objects (filter and effect dialogs)
47         self.view = None  # viewer widget
48         self.basedir = None  #path of project directory, required for framesets
49         self.animChunks = BooleanVar(value = True)
50         tooltips = Pmw.Balloon(self)
51
52         self.subgets['chunklist'] = Pmw.ScrolledFrame(self, usehullsize = 1, 
53                                                       hull_height = 142, hull_width = 800)
54         self.subgets['chunklist'].pack(side=TOP, fill=X)
55         self.subgets['b_PlayAll'] = Button(self, text='Play All', command=self.playall)
56         self.subgets['b_PlayAll'].pack(side=LEFT)
57         self.subgets['b_InvPlay'] = Button(self, text='Invert Play', command=self.invplay)
58         self.subgets['b_InvPlay'].pack(side=LEFT)
59         tooltips.bind(self.subgets['b_PlayAll'],
60                            'Mark all video snippets for playback.')
61         self.subgets['b_MarkAll'] = Button(self, text='Mark All', command=self.markall)
62         self.subgets['b_MarkAll'].pack(side=LEFT)
63         self.subgets['b_InvMark'] = Button(self, text='Invert Mark', command=self.invmark)
64         self.subgets['b_InvMark'].pack(side=LEFT)
65         tooltips.bind(self.subgets['b_MarkAll'],
66                            'Mark all video snippets for filter and effect application.')
67
68         self.subgets['b_info'] = Button(self, text='Video Info', command=self.info)
69         self.subgets['b_info'].pack(side=RIGHT)
70         tooltips.bind(self.subgets['b_info'],
71                            'Show detailed information about the marked video chunks.')
72
73         self.subgets['b_frameset'] = Button(self, text='Make Frameset', command=self.convert,
74                                             state = 'disabled')
75         self.subgets['b_frameset'].pack(side=RIGHT)
76         tooltips.bind(self.subgets['b_frameset'],
77                            'Convert marked video chunks into framesets.\n' +
78                            'This enables you to perform advanced video operations.')
79
80         self.process_schedule()
81
82     def switch_animChunks(self):
83         for chunk in self.chunks:
84             chunk.animate = self.animChunks.get()
85             chunk.chprops()
86
87     def info(self):
88         """
89         Displays a window with information about loaded video files.
90         """
91         win = Tk()
92         frm = LabelFrame(win, text = 'Info')
93         frm.pack(side = TOP, expand = True, fill = BOTH)
94         text = Text(frm, width = 40, height = 10)
95         text.pack(side = LEFT, fill = BOTH, expand = True)
96         scroll = Scrollbar(frm, orient = VERTICAL, command = text.yview)
97         scroll.pack(side = RIGHT, fill = Y, anchor = W)
98         text.config(yscrollcommand = scroll.set)
99         Button(win, command = win.destroy, text = 'OK').pack(side = RIGHT, anchor = N)
100
101         for vc in self.chunks:
102             if vc.marked.get():
103                 text.insert(END, '###=- ' + vc.cget('text') + ':\n####\n')
104                 pkeys = vc.videoprops.keys()
105                 pkeys.sort()
106                 for pkey in pkeys:
107                     text.insert(END, pkey + ':\t')
108                     text.insert(END, vc.videoprops[pkey] + '\n')
109                 text.insert(END, '\n')
110         text.config(state = 'disabled')
111
112     def convert(self):
113         """
114         Converts marked chunks to framesets
115         """
116         for vc in self.chunks:
117             if vc.marked.get():
118                 index = self.chunks.index(vc)
119                 new = VFrameset(self.subgets['chunklist'].interior(),
120                                 vurl = vc.videofile,
121                                )
122                 new.played.set(value = vc.played.get())
123                 new.marked.set(value = vc.marked.get())
124                 if self.animChunks.get(): new.play()
125                 new.pack(before = vc, side=LEFT)
126                 self.chunks.insert(index, new)
127                 self.chunks.remove(vc)
128                 vc.stop()
129                 vc.destroy()
130
131     def playall(self):
132         """
133         Internal button press execution code
134         """
135         for vc in self.chunks:
136             vc.subgets['c_play'].select()
137
138     def invplay(self):
139         """
140         Internal button press execution code
141         """
142         for vc in self.chunks:
143             vc.subgets['c_play'].toggle()
144
145     def markall(self):
146         """
147         Internal button press execution code
148         """
149         for vc in self.chunks:
150             vc.subgets['c_mark'].select()
151
152     def invmark(self):
153         """
154         Internal button press execution code
155         """
156         for vc in self.chunks:
157             vc.subgets['c_mark'].toggle()
158
159     def process_schedule(self):
160         """
161         Process scheduled events on video chunks.
162
163         This function is internal. Its used to execute actions like 
164         moving and copying of chunks
165         """
166         params = []
167         marked = []
168
169         for vc in self.chunks:
170             if vc.played.get():
171                 params.extend(vc.slave_subcommand())
172             if vc.marked.get():
173                 marked.append(vc)
174
175             if vc.schedule == '':
176                 pass
177             elif vc.schedule == 'delete':
178                 self.chunks.remove(vc)
179                 vc.stop()
180                 vc.destroy()
181             elif vc.schedule == 'copy':
182                 index = self.chunks.index(vc)
183                 new = VChunk(self.subgets['chunklist'].interior(),
184                              file = vc.videofile,
185                              start = vc.start,
186                              frames = vc.frames
187                              )
188                 new.filters = list(vc.filters)
189                 new.played.set(value = vc.played.get())
190                 new.marked.set(value = vc.marked.get())
191                 if self.animChunks.get(): new.play()
192                 else: new.stop()
193                 new.pack(before = vc, side=LEFT)
194                 self.chunks.insert(index, new)
195                 vc.schedule = ''
196             elif vc.schedule == 'mv left':
197                 index = self.chunks.index(vc)
198                 if vc != self.chunks[0]:
199                     vc.pack_forget()
200                     self.chunks.remove(vc)
201                     self.chunks.insert(index - 1, vc)
202                     vc.pack(before = self.chunks[index], side = LEFT)
203                 vc.schedule = ''
204             elif vc.schedule == 'mv right':
205                 index = self.chunks.index(vc)
206                 if vc != self.chunks[-1]:
207                     vc.pack_forget()
208                     self.chunks.remove(vc)
209                     self.chunks.insert(index + 1, vc)
210                     vc.pack(after = self.chunks[index], side = LEFT)
211                 vc.schedule = ''
212
213         if self.view != None:
214             self.view.set_playback_params(params)
215         for mod in self.mods:
216             mod.set_chunks(marked)
217
218         self.after(20, self.process_schedule)
219
220     def add(self, file, start = None, frames = None):
221         """
222         Append video chunk to the list
223         """
224         vc = VChunk(self.subgets['chunklist'].interior(),
225                     file = file,
226                     start = start,
227                     frames = frames,
228                     play = self.animChunks.get()
229                     )
230         vc.pack(side = LEFT)
231         self.chunks.append(vc)
232
233     def set_view(self, view):
234         self.view = view
235
236     def set_mods(self, mods):
237         self.mods = mods
238
239     def set_basedir(self, basedir):
240         self.basedir = basedir
241         self.subgets['b_frameset'].config(state = 'normal')
242
243     def get_basedir(self):
244         return self.basedir