From db783db5f7aadaaab3d8cb63f099c82cd411c20b Mon Sep 17 00:00:00 2001 From: paul Date: Sat, 9 Apr 2011 20:48:20 +0000 Subject: [PATCH] started basic frameset support svn path=/trunk/; revision=4 --- main.py | 37 ++++++----- timeline.py | 28 +++++++- vframeset.py | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 225 insertions(+), 18 deletions(-) create mode 100644 vframeset.py diff --git a/main.py b/main.py index 92511f3..33c592b 100755 --- a/main.py +++ b/main.py @@ -2,7 +2,7 @@ #encoding: utf-8 #Viper - Video In Python Editing Reptile, a video editor -#Copyright 2009 - 2010 Paul Hänsch +#Copyright 2009 - 2011 Paul Hänsch #This file is part of Viper. @@ -101,27 +101,33 @@ class Main(Tk): call named_save_project() if no project directory is set yet """ - - self.named_save_project() + if self.subgets['timeline'].get_basedir() == None: + self.named_save_project() + else: + savedir = self.subgets['timeline'].get_basedir() + try: os.unlink(savedir + '/description.sqlite') + except: pass + + dbcon = sqlite.connect(savedir + '/description.sqlite') + dbcur = dbcon.cursor() + dbcur.execute('CREATE TABLE chunks (iorder INTEGER PRIMARY KEY, filename TEXT, start REAL, frames INTEGER, played INTEGER, marked BOOLEAN);') + dbcur.execute('CREATE TABLE filters (iorder INTEGER PRIMARY KEY, chunk INTEGER, FOREIGN KEY (chunk) REFERENCES chunks (iorder));') + dbcur.execute('CREATE TABLE filter_lines (iorder INTEGER PRIMARY KEY, line TEXT, filter INTEGER, FOREIGN KEY (filter) REFERENCES filters (iorder));') + for chunk in self.subgets['timeline'].chunks: + chunk.store(dbcur) + + dbcur.close() + dbcon.commit() + dbcon.close() def named_save_project(self): """ Ask for directory to save to (and save project) """ - savedir = tkFileDialog.asksaveasfilename(filetypes = [('Viper Project Directory', '*.vpd')]) os.makedirs(savedir) - dbcon = sqlite.connect(savedir + '/description.sqlite') - dbcur = dbcon.cursor() - dbcur.execute('CREATE TABLE chunks (iorder INTEGER PRIMARY KEY, filename TEXT, start REAL, frames INTEGER, played INTEGER, marked BOOLEAN);') - dbcur.execute('CREATE TABLE filters (iorder INTEGER PRIMARY KEY, chunk INTEGER, FOREIGN KEY (chunk) REFERENCES chunks (iorder));') - dbcur.execute('CREATE TABLE filter_lines (iorder INTEGER PRIMARY KEY, line TEXT, filter INTEGER, FOREIGN KEY (filter) REFERENCES filters (iorder));') - for chunk in self.subgets['timeline'].chunks: - chunk.store(dbcur) - - dbcur.close() - dbcon.commit() - dbcon.close() + self.subgets['timeline'].set_basedir(savedir) + self.save_project() def open_project(self): """ @@ -130,6 +136,7 @@ class Main(Tk): """ opendir = tkFileDialog.askopenfilename(filetypes = [('Project Description', '*/description.sqlite')]) + self.subgets['timeline'].set_basedir(opendir[0:-19]) for chunk in self.subgets['timeline'].chunks: chunk.delete() diff --git a/timeline.py b/timeline.py index 1ed4d5c..5482800 100644 --- a/timeline.py +++ b/timeline.py @@ -1,5 +1,5 @@ #encoding: utf-8 -#Copyright 2009 - 2010 Paul Hänsch +#Copyright 2009 - 2011 Paul Hänsch #This file is part of Viper. @@ -18,6 +18,7 @@ from Tkinter import * from vchunk import * +from vframeset import * import Pmw class Timeline(Frame): @@ -44,6 +45,7 @@ class Timeline(Frame): self.chunks = [] self.mods = [] # list of chunk modifying objects (filter and effect dialogs) self.view = None # viewer widget + self.basedir = None #path of project directory, required for framesets self.animChunks = BooleanVar(value = True) tooltips = Pmw.Balloon(self) @@ -109,9 +111,22 @@ class Timeline(Frame): def convert(self): """ - Converts marked chunks to framesets (not yet implemented) + Converts marked chunks to framesets """ - pass + for vc in self.chunks: + if vc.marked.get(): + index = self.chunks.index(vc) + new = VFrameset(self.subgets['chunklist'].interior(), + vurl = vc.videofile, + ) + new.played.set(value = vc.played.get()) + new.marked.set(value = vc.marked.get()) + new.play() + new.pack(before = vc, side=LEFT) + self.chunks.insert(index, new) + self.chunks.remove(vc) + vc.stop() + vc.destroy() def playall(self): """ @@ -219,3 +234,10 @@ class Timeline(Frame): def set_mods(self, mods): self.mods = mods + + def set_basedir(self, basedir): + self.basedir = basedir + self.subgets['b_frameset'].config(state = 'normal') + + def get_basedir(self): + return self.basedir diff --git a/vframeset.py b/vframeset.py new file mode 100644 index 0000000..ffdc945 --- /dev/null +++ b/vframeset.py @@ -0,0 +1,178 @@ +#encoding: utf-8 +#Copyright 2011 Paul Hänsch + +#This file is part of Viper. + +#Viper is free software: you can redistribute it and/or modify +#it under the terms of the GNU General Public License as published by +#the Free Software Foundation, either version 3 of the License, or +#(at your option) any later version. + +#Viper is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#GNU General Public License for more details. + +#You should have received a copy of the GNU General Public License +#along with Viper. If not, see + +from Tkinter import * +import Pmw +from flic import * + +class VFrameset(LabelFrame, Flic): + """ + Visual frameset widget + + This widget represents a set of frames and provides controls for manipulating + and positioning it. + + Properties are: + schedule (string) - commands to the owning object, values can be + mv left : move this chunk left + mv right: move this chunk right + copy : double this chunk + apply : realize new video properties + delete : remove this chunk + + subgets - dictionary of widgets forming this + complex widget + played (Tk.Boolean) - indicates status of the play checkbox (use ...play.get()) + marked (Tk.Boolean) - indicates status of the mark checkbox (use ...mark.get()) + """ + + def __init__(self, master = None, vurl = '', play = True): + """ + Constructor + + master - the holding widget + """ + self.vurl = vurl + self.subgets = {} + self.schedule = '' + self.animate = play + self.played = BooleanVar(value = True) + self.marked = BooleanVar(value = True) + + tooltips = Pmw.Balloon() + + Flic.__init__(self) + LabelFrame.__init__(self, master = master, text = vurl.split('/')[-1]) + self.subgets['video'] = Frame(self, height=90, width=120, bg = '#000000') + self.subgets['video'].grid(column=0, row=0, rowspan=4, sticky=W) + + self.subgets['b_edit'] = Button(self, text = 'Edit', command = self.edit) + self.subgets['b_edit'].grid(column = 1, row=1, columnspan = 4, rowspan = 2) + tooltips.bind(self.subgets['b_edit'], 'Select and remove single frames from frameset.') + + self.subgets['b_mvbw'] = Button(self, text = '<-', command=self.mvbw) + self.subgets['b_mvbw'].grid(column = 1, row = 3, rowspan = 1, columnspan = 2, sticky=E) + tooltips.bind(self.subgets['b_mvbw'], + 'Swap this chunk with its left neighbour (move it left).') + + self.subgets['b_copy'] = Button(self, text = 'Copy', command=self.copy) + self.subgets['b_copy'].grid(column = 3, columnspan = 2, row = 3, rowspan = 1) + tooltips.bind(self.subgets['b_copy'], + 'Create another chunk with the same properties as this one.') + + self.subgets['b_mvfw'] = Button(self, text = '->', command=self.mvfw) + self.subgets['b_mvfw'].grid(column = 5, row = 3, rowspan = 1, sticky=W) + tooltips.bind(self.subgets['b_mvfw'], + 'Swap this chunk with its right neighbour (move it right).') + + self.subgets['c_play'] = Checkbutton(self, text='Play', offvalue=False, + onvalue=True, variable = self.played) +# self.subgets['c_play'].select() + self.subgets['c_play'].grid(column=1, columnspan = 2, row=0) + tooltips.bind(self.subgets['c_play'], + 'Mark this chunk for playback in main window.') + + self.subgets['c_mark'] = Checkbutton(self, text='Mark', offvalue=False, + onvalue=True, variable = self.marked) +# self.subgets['c_mark'].select() + self.subgets['c_mark'].grid(column=3, columnspan = 2, row=0) + tooltips.bind(self.subgets['c_mark'], + 'Mark this chunk for application of choosen filters and effects.') + + self.subgets['b_del'] = Button(self, text='Del', command = self.delete) + self.subgets['b_del'].grid(column=5, row=0, sticky=NE) + tooltips.bind(self.subgets['b_del'], + 'Remove this chunk from the project.') + self.schedule = 'apply' + + def load_filters(self, dbcur, num): + """ + Load filter list from database + + db - sqlite database cursor + num - database primary key id of this chunk + """ + + dbcur.execute('SELECT iorder FROM filters ' + + 'WHERE chunk = ' + str(num) + ' ORDER BY iorder') + for filter in dbcur.fetchall(): + dbcur.execute('SELECT line FROM filter_lines WHERE filter = ' + + str(filter[0]) + ' ORDER BY iorder') + line = [] + for item in dbcur.fetchall(): + line.append(item[0]) + self.add_filter(line) + + def delete(self): + """ + Scheduler for internal use + """ + self.schedule = 'delete' + + def mvbw(self): + """ + Scheduler for internal use + """ + self.schedule = 'mv left' + + def mvfw(self): + """ + Scheduler for internal use + """ + self.schedule = 'mv right' + + def copy(self): + """ + Scheduler for internal use + """ + self.schedule = 'copy' + + def store(self, dbcur): + """ + Store chunk to database + + The tables "chunks", "filters" and "filter_lines" + must be prepared in database. + + dbcur - sqlite database cursor + """ + if self.played.get(): played = '1' + else: played = '0' + if self.marked.get(): marked = '1' + else: marked = '0' + dbcur.execute('INSERT INTO chunks (filename, start, frames, played, marked) ' + + 'VALUES ("' + self.vurl + '", 0, 0, ' + played + ', ' + marked + ');') + + dbcur.execute('SELECT last_insert_rowid();') + chunk_id = str(dbcur.fetchone()[0]) + + for filter in self.filters: + dbcur.execute('INSERT INTO filters (chunk) VALUES (' + chunk_id + ');') + dbcur.execute('SELECT last_insert_rowid();') + filter_id = str(dbcur.fetchone()[0]) + for line in filter: + dbcur.execute('INSERT INTO filter_lines (line, filter) ' + + 'VALUES ("' + line + '", ' + filter_id + ')') + def slave_video(self): + return [self.vurl] + + def edit(self): + self.schedule = 'apply' + + def play(self): + Flic.play(self, self.subgets['video'].winfo_id(), width=120, height=90) -- 2.39.2