]> git.plutz.net Git - viper/blob - vchunk.py
moved from svn.imp.fu-berlin.de/viper rev33
[viper] / vchunk.py
1 #encoding: utf-8
2 #Copyright 2009 - 2010 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 import Pmw
21 from chunk import *
22
23 class VChunk(LabelFrame, Chunk):
24     """
25     Visual video chunk widget
26
27     This widget represents a video chunk and provides controls for
28     defining the  chunk.
29
30     Properties are:
31     schedule (string)   - commands to the owning object, values can be
32                             mv left : move this chunk left
33                             mv right: move this chunk right
34                             copy    : double this chunk
35                             apply   : realize new video properties
36                             delete  : remove this chunk
37     
38     subgets             - dictionary of widgets forming this
39                           complex widget
40     played (Tk.Boolean) - indicates status of the play checkbox (use ...play.get())
41     marked (Tk.Boolean) - indicates status of the mark checkbox (use ...mark.get())
42     """
43
44     def __init__(self, master = None, file = '', start = None, frames = None, play = True):
45         """
46         Constructor
47
48         chunk  - a Chunk object to represent
49         master - the holding widget
50         """
51         self.subgets = {}
52         self.schedule = ''
53         self.animate = play
54         self.played = BooleanVar(value = True)
55         self.marked = BooleanVar(value = True)
56
57         tooltips = Pmw.Balloon()
58
59         Chunk.__init__(self, file, start, frames)
60         LabelFrame.__init__(self, master = master, text = 
61                             file.split('/')[-1] + ':' + str(start) + ':' + str(frames)
62                             )
63         self.subgets['video'] = Frame(self, height=90, width=120, bg = '#000000')
64         self.subgets['video'].grid(column=0, row=0, rowspan=4, sticky=W)
65
66         self.subgets['sb_m_start'] = Spinbox(self, from_ = 0, increment = 1, width = 3,
67                                              to = int(float(self.videoprops['ID_LENGTH']) / 60))
68         self.subgets['sb_m_start'].delete(0, END)
69         self.subgets['sb_m_start'].insert(0, int(self.start / 60))
70         self.subgets['sb_m_start'].grid(column=2, row=1, rowspan=1)
71
72         self.subgets['sb_s_start'] = Spinbox(self, from_ = 0, increment = 1, width = 2, to = 60)
73         self.subgets['sb_s_start'].delete(0, END)
74         self.subgets['sb_s_start'].insert(0, int(self.start) % 60)
75         self.subgets['sb_s_start'].grid(column=3, row=1, rowspan=1)
76
77         self.subgets['sb_f_start'] = Spinbox(self, from_ = 0, increment = 1, width = 2,
78                                              to = int(float(self.videoprops['ID_VIDEO_FPS'])))
79         self.subgets['sb_f_start'].delete(0, END)
80         self.subgets['sb_f_start'].insert(0, int(self.start *
81                                                  float(self.videoprops['ID_VIDEO_FPS'])
82                                                  ) % int(float(self.videoprops['ID_VIDEO_FPS'])))
83         self.subgets['sb_f_start'].grid(column=4, row=1, rowspan=1)
84
85         tooltips.bind(self.subgets['sb_m_start'],
86                       'Define the staring minute of the video chunk in the source video file.')
87         tooltips.bind(self.subgets['sb_s_start'],
88                       'Define the starting second of the video chunk in the source video file.')
89         tooltips.bind(self.subgets['sb_f_start'],
90                       'Define the starting frame of the video chunk in the source video file.')
91
92         frames = int(self.start * float(self.videoprops['ID_VIDEO_FPS'])) + self.frames
93         self.subgets['sb_m_stop'] = Spinbox(self, from_ = 0, increment = 1, width = 3,
94                                             to = int(float(self.videoprops['ID_LENGTH']) / 60))
95         self.subgets['sb_m_stop'].delete(0, END)
96         self.subgets['sb_m_stop'].insert(0, int(frames / float(self.videoprops['ID_VIDEO_FPS'])
97                                                 / 60))
98         self.subgets['sb_m_stop'].grid(column=2, row=2, rowspan=1)
99
100         self.subgets['sb_s_stop'] = Spinbox(self, from_ = 0, increment = 1, width = 2, to = 60)
101         self.subgets['sb_s_stop'].delete(0, END)
102         self.subgets['sb_s_stop'].insert(0, int(frames / float(self.videoprops['ID_VIDEO_FPS'])
103                                                 ) % 60)
104         self.subgets['sb_s_stop'].grid(column=3, row=2, rowspan=1)
105
106         self.subgets['sb_f_stop'] = Spinbox(self, from_ = 0, increment = 1, width = 2,
107                                              to = int(float(self.videoprops['ID_VIDEO_FPS'])))
108         self.subgets['sb_f_stop'].delete(0, END)
109         self.subgets['sb_f_stop'].insert(0, frames % int(float(self.videoprops['ID_VIDEO_FPS'])))
110         self.subgets['sb_f_stop'].grid(column=4, row=2, rowspan=1)
111
112         tooltips.bind(self.subgets['sb_m_stop'],
113                       'Define the stop minute of the video chunk in the source video file.')
114         tooltips.bind(self.subgets['sb_s_stop'],
115                       'Define the stop second of the video chunk in the source video file.')
116         tooltips.bind(self.subgets['sb_f_stop'],
117                       'Define the stop frame of the video chunk in the source video file.')
118
119         self.subgets['b_apply'] = Button(self, text = 'Set', command=self.chprops)
120         self.subgets['b_apply'].grid(column=5, row=1, rowspan = 2, sticky=W)
121         tooltips.bind(self.subgets['b_apply'],
122                       'Apply changes of start and end time.')
123
124         self.subgets['b_mvbw'] = Button(self, text = '<-', command=self.mvbw)
125         self.subgets['b_mvbw'].grid(column = 1, row = 3, rowspan = 1, columnspan = 2, sticky=E)
126         tooltips.bind(self.subgets['b_mvbw'],
127                       'Swap this chunk with its left neighbour (move it left).')
128
129         self.subgets['b_copy'] = Button(self, text = 'Copy', command=self.copy)
130         self.subgets['b_copy'].grid(column = 3, columnspan = 2, row = 3, rowspan = 1)
131         tooltips.bind(self.subgets['b_copy'],
132                       'Create another chunk with the same properties as this one.')
133
134         self.subgets['b_mvfw'] = Button(self, text = '->', command=self.mvfw)
135         self.subgets['b_mvfw'].grid(column = 5, row = 3, rowspan = 1, sticky=W)
136         tooltips.bind(self.subgets['b_mvfw'],
137                       'Swap this chunk with its right neighbour (move it right).')
138
139         self.subgets['c_play'] = Checkbutton(self, text='Play', offvalue=False,
140                                              onvalue=True, variable = self.played)
141 #        self.subgets['c_play'].select()
142         self.subgets['c_play'].grid(column=1, columnspan = 2, row=0)
143         tooltips.bind(self.subgets['c_play'],
144                       'Mark this chunk for playback in main window.')
145
146         self.subgets['c_mark'] = Checkbutton(self, text='Mark', offvalue=False,
147                                              onvalue=True, variable = self.marked)
148 #        self.subgets['c_mark'].select()
149         self.subgets['c_mark'].grid(column=3, columnspan = 2, row=0)
150         tooltips.bind(self.subgets['c_mark'],
151                       'Mark this chunk for application of choosen filters and effects.')
152
153         self.subgets['b_del'] = Button(self, text='Del', command = self.delete)
154         self.subgets['b_del'].grid(column=5, row=0, sticky=NE)
155         tooltips.bind(self.subgets['b_del'],
156                       'Remove this chunk from the project.')
157         self.chprops()
158
159     def load_filters(self, dbcur, num):
160         """
161         Load filter list from database
162
163         db  - sqlite database cursor
164         num - database primary key id of this chunk
165         """
166
167         dbcur.execute('SELECT iorder FROM filters ' +
168                       'WHERE chunk = ' + str(num) + ' ORDER BY iorder')
169         for filter in dbcur.fetchall():
170             dbcur.execute('SELECT line FROM filter_lines WHERE filter = ' +
171                           str(filter[0]) + ' ORDER BY iorder')
172             line = []
173             for item in dbcur.fetchall():
174                 line.append(item[0])
175             self.add_filter(line)
176
177     def delete(self):
178         """
179         Scheduler for internal use
180         """
181         self.schedule = 'delete'
182
183     def mvbw(self):
184         """
185         Scheduler for internal use
186         """
187         self.schedule = 'mv left'
188
189     def mvfw(self):
190         """
191         Scheduler for internal use
192         """
193         self.schedule = 'mv right'
194
195     def copy(self):
196         """
197         Scheduler for internal use
198         """
199         self.schedule = 'copy'
200
201     def store(self, dbcur):
202         """
203         Store chunk to database
204
205         The tables "chunks", "filters" and "filter_lines"
206         must be prepared in database.
207
208         dbcur - sqlite database cursor
209         """
210         if self.played.get(): played = '1'
211         else: played = '0'
212         if self.marked.get(): marked = '1'
213         else: marked = '0'
214         dbcur.execute('INSERT INTO chunks (filename, start, frames, played, marked) ' + 
215                       'VALUES ("' + self.videofile + '", ' + str(self.start) + ', ' +
216                       str(self.frames) + ', ' + played + ', ' + marked + ');')
217
218         dbcur.execute('SELECT last_insert_rowid();')
219         chunk_id = str(dbcur.fetchone()[0])
220
221         for filter in self.filters:
222             dbcur.execute('INSERT INTO filters (chunk) VALUES (' + chunk_id + ');')
223             dbcur.execute('SELECT last_insert_rowid();')
224             filter_id = str(dbcur.fetchone()[0])
225             for line in filter:
226                 dbcur.execute('INSERT INTO filter_lines (line, filter) ' +
227                               'VALUES ("' + line + '", ' + filter_id + ')')
228
229     def chprops(self):
230         """
231         Changes 'start' and 'frames' property of chunk.
232
233         This method is called when the Apply (Set) button is pressed.
234         The methos also schedules the apply event
235         """
236         try:
237             start = (int(self.subgets['sb_m_start'].get()) * 60 +
238                      int(self.subgets['sb_s_start'].get()) +
239                      int(self.subgets['sb_f_start'].get()) / float(self.videoprops['ID_VIDEO_FPS'])
240                      )
241             frames = int((int(self.subgets['sb_m_stop'].get()) * 60 +
242                           int(self.subgets['sb_s_stop'].get())) *
243                          float(self.videoprops['ID_VIDEO_FPS']) + 
244                          int(self.subgets['sb_f_stop'].get()) - 
245                          (start * float(self.videoprops['ID_VIDEO_FPS']))
246                          )
247             self.stop()
248             self.option(start=start, frames=frames)
249             if self.animate: self.play()
250             self.config(text = self.videofile.split('/')[-1] + ':' + str(start) + ':' + str(frames))
251         except:
252             print 'could not parse props'
253         self.schedule = 'apply'
254
255     def play(self):
256         Flic.play(self, self.subgets['video'].winfo_id(), width=120, height=90)