From 77bc6a25af184932d03d599bf6b0485e91a32ccd Mon Sep 17 00:00:00 2001 From: noisymime Date: Mon, 19 Nov 2007 11:38:15 +0000 Subject: [PATCH] Pluggable modules now complete. --- Menu.py | 7 +- Menu.pyc | Bin 11621 -> 11547 bytes MenuMgr.py | 6 + MenuMgr.pyc | Bin 7199 -> 7519 bytes VideoController.py | 10 +- gloss.py | 65 +--- modules/dvd_player/dvd_player.py | 12 +- modules/music_player/music_player.py | 12 +- modules/myth_tv_player/myth_tv_player.py | 15 +- modules/slideshow/slideshow.py | 20 +- Plugin.py => modules/video_player/__init__.py | 0 modules/video_player/cover_viewer.py | 327 +++++++++++++++++ modules/video_player/video_player.py | 342 +----------------- 13 files changed, 425 insertions(+), 391 deletions(-) rename Plugin.py => modules/video_player/__init__.py (100%) create mode 100644 modules/video_player/cover_viewer.py diff --git a/Menu.py b/Menu.py index 9829075..d7d442f 100644 --- a/Menu.py +++ b/Menu.py @@ -70,8 +70,8 @@ class Menu: menu_x = (self.stage.get_width()-self.itemGroup.get_width())/2 self.itemGroup.set_position(menu_x, menu_y) self.displayPosition = (menu_x, menu_y) - print "Original Group size: " + str(self.itemGroup.get_width()) - print "Starting at : " + str(menu_x) + ":" + str(menu_y) + #print "Original Group size: " + str(self.itemGroup.get_width()) + #print "Starting at : " + str(menu_x) + ":" + str(menu_y) #The display position is the x, y coords of where the menu is when it is active def get_display_position(self): @@ -299,7 +299,8 @@ class ListItem (clutter.Label): label_x = 0 #x #self.stage.get_width() - label_width - 50 label_y = y #self.stage.get_height() - label_height self.set_position(0, y) - self.addImage(imagePath, True) + if not (imagePath == "" or imagePath is None): + self.addImage(imagePath, True) #Add textures group and hide it self.menu.getMenuGroup().add(self.itemTexturesGroup) diff --git a/Menu.pyc b/Menu.pyc index 96ae71fa90b1ed34ca9622d6060e9f0877af4b8b..c73cfbe48a707267c9590ad7a02bf90f5491e854 100644 GIT binary patch delta 1032 zcmZ9~&rcIU6bJBmrL<6J1*Bl**R}}RO4S4e1VluvK)?c95viKGvK6)ht+0Y1h{}P) zn2<1uQPISMCohDo|AGnsgeT(J=)r>?biM;8)9fd2e(db)d-E-^op9Sfy`E1uyLa8O z{3DBuu@zzlv9yC_?r|gEP-cmd!B||)5sNX)C7ejjTB$kHAwt!~hdpQcOV5)+j~FuY zk|KV*xT?X97VJ5wk^6k7sg3W3n)znHZ7=!K?zPKer+nSSp{ie?m4GP72Uh?-rWJx> z&fM?;F*Ah-%*0@cCnyJZe?4Pj=Or_1}P&;DEf#@QLj@z4mj!F$zk~6B?1P1>>W0xjqfe%^ zquA2P^^oFUK&XIr5Cj+at5AX>{6{F9bDT=;irNk8o)s(dl=-R5Vp5-;)|N3-Ajo9( z3Da7NTdAzJiUS@4*?!si>llvl{S&Hx9AN@H1h>F#uGF>Aq_|%#x#(Oo->OT}GAHjv z-dJBkaXVW7i#o1huT1w0qDD|7kV(yDEZs^amo%iQ6#a`vCRRo`G^8FYN{*q^G?GZ@@e79*pvx>JGjc UDJ6w}jMUN#z87hwnXOZ)e+uEm^Z)<= delta 1060 zcmZXT%TE(g6vodfr4MMKNQPEH7%Gr~G?EBn1eAvl9)<$bh){{p&;|#wZQ22XASANT z#26RXg+O%Y!o&@kKftYtD>iP73l}EDjfsgQ#s%JQO5(ya{pH;A-FxQD`R?q-zs23w zPk+geKMegqMC(jRrUeIOc16;g+)Ngc>7sQa!$C$7Z4qrT1qTL`PCG9%a+xfq zAa*&9#WWKqiDH^dR*Xu8XfBmDQ#o0LD6dG2=8SnGomf-{a+#&9nl~P#I@NrcRAOc# zXBz2wHDRiqUe#oo>(t!hz}xOIi*Vk|iJFp)3T!6!vnqd;T+Si!-qT|3mwa$=o7nN6 z>5X`i^HlR9=3XeG3EjBA{18aGXEX<80vR$)GDiAru^R%6d`bNYeNM$UkXy;=7vUJ~3K9S{jpy!VKEQ+xnQ`a3%K$C9End zP*k8Bs0Vt*a5&B_;!U`j1J-`{G52L;-o#+@cQY$9iN!^I4VhAjOg1rRn5!`}mDM-o zT9=I(0GD%>rdk$ z2PUxD?zR1: + self.transition_fade_zoom(self.menuHistory.pop(), self.menuHistory[-1]) + self.currentMenu = self.menuHistory[-1] class MenuSelector(clutter.Texture): x_offset = -50 diff --git a/MenuMgr.pyc b/MenuMgr.pyc index a670e1716805adc7b3bed87d721dbc8223b18762..570d83838fb8c175debc924fe293442284244d34 100644 GIT binary patch delta 609 zcmXYu&ubG=5XWa;vKuz5%{H2tA3{CJLVJ-~sDe~d5Ah=Q)mAIi?b2-9l{AUTwgfcw z5D@fM2lS$d|9~KS^amaV@8YRBdF(-pSKFD8eawgN{CvaPce8`5src{d^vk8W{nSrf z**{pIL&r+$Mc0a_@$1;rbp-$kHiK=Rt+U1G`Vaxs5S}3P72H_84Lt=B`v9SWK1%Lk z5}KC*C6pK?!X)%zq-zR_+&j!G5RWT810FemYqeJey}c+8(`vWjGvw%^zc z^b#vAuC54{1u2FreLBO4(u~H=wpR~!gL;Q|IBo{f-nF8 delta 338 zcmca_HQ$1L^Cw=eyLXHxvR`8in0POcB`8>fW3vt8K0YQ5uE{!r_LG@qttPJ$+lQ+mXaL0lKLFNWUPyQ{F%s2r6GNMl^ diff --git a/VideoController.py b/VideoController.py index cd00925..45c6903 100644 --- a/VideoController.py +++ b/VideoController.py @@ -8,6 +8,7 @@ class VideoController: self.stage = stage self.overlay = None self.blackdrop = None + # Primary video texture & sink definition self.video_texture = clutter.cluttergst.VideoTexture() self.video_sink = clutter.cluttergst.VideoSink(self.video_texture) @@ -48,7 +49,9 @@ class VideoController: self.isPlaying = True return self.video_texture - + + #This handles any messages that are sent accross the playbin + #Currently the only message being checked for it a "codec not found" def on_bus_message(self, bus, message): t = message.type @@ -69,6 +72,7 @@ class VideoController: def stop_video(self): if self.video_texture.get_playing(): self.isPlaying = False + self.player.stop_video() self.player = None self.video_texture.set_playing(False) @@ -77,13 +81,13 @@ class VideoController: alpha = clutter.Alpha(timeline, clutter.ramp_inc_func) self.behaviour = clutter.BehaviourOpacity(alpha, 255,0) self.behaviour.apply(self.video_texture) - #behaviour.apply(self.blackdrop) + self.behaviour.apply(self.blackdrop) timeline.start() def end_video_event(self, data): self.stage.remove(self.video_texture) - # self.stage.remove(self.blackdrop) + self.stage.remove(self.blackdrop) self.blackdrop = None def customBin(self): diff --git a/gloss.py b/gloss.py index 2441078..20d08d9 100644 --- a/gloss.py +++ b/gloss.py @@ -60,31 +60,14 @@ class MainApp: #Update splash status msg self.splashScreen.set_msg("Creating menus") - menu1 = Menu(self.menuMgr) - menu1.addItem("TV", "ui/dvd.png") - menu1.addItem("Slideshow", "ui/gallery.png") - menu1.addItem("Videos", "ui/videos.png") - menu1.addItem("Link", "ui/link.png") - menu1.addItem("DVD", "ui/dvd.png") - menu1.addItem("nothing", "ui/dvd.png") - menu1.addItem("nothing", "ui/dvd.png") - menu1.addItem("nothing", "ui/dvd.png") + MainMenu = Menu(self.menuMgr) + #menu1.addItem("nothing", "ui/dvd.png") + #menu1.addItem("nothing", "ui/dvd.png") + #menu1.addItem("nothing", "ui/dvd.png") #menu1.setListFont('Tahoma 42') - menu1.setMenuPositionByName("center") - self.menu1 = menu1 - - self.menu2 = Menu(self.menuMgr) - self.menu2.addItem("Nothing", "ui/dvd.png") - self.menu2.addItem("Link", "ui/gallery.png") - self.menu2.addItem("blah3", "ui/game.png") - self.menu2.addItem("blah4", "ui/music.png") - self.menu2.addItem("blah", "ui/dvd.png") - self.menu2.addItem("blah2", "ui/dvd.png") - self.menu2.addItem("blah3", "ui/dvd.png") - self.menu2.addItem("blah4", "ui/dvd.png") - #self.menu2.setListFont('Tahoma 42') - self.menu2.setMenuPositionByName("center") + MainMenu.setMenuPositionByName("center") + #self.MainMenu = menu #Update splash status msg @@ -93,35 +76,19 @@ class MainApp: self.dbMgr = mythDB() #Update splash status msg - self.splashScreen.set_msg("Loading gallery") - self.mySlideshow = modules[0].Slideshow(self.menuMgr, self.dbMgr) - - #Update splash status msg - self.splashScreen.set_msg("Loading videos") - self.vidPlayer = modules[2].VideoPlayer(self.stage, self.dbMgr) - #Update splash status msg - self.splashScreen.set_msg("Setting up TV player") - self.tvPlayer = modules[1].TVPlayer(self.stage, self.dbMgr) - #Update splash status msg - self.splashScreen.set_msg("Setting up DVD player") - self.dvdPlayer = modules[3].DvdPlayer(self.stage) - #Update splash status msg - self.splashScreen.set_msg("Setting up Music player") - self.musicPlayer = modules[4].MusicPlayer(self.stage) - - menu1.getItem(0).setAction(self.tvPlayer) - #menu1.getItem(1).setAction(self.mySlideshow) - menu1.getItem(1).setAction(self.mySlideshow.generateMenu()) - menu1.getItem(2).setAction(self.vidPlayer) - menu1.getItem(3).setAction(self.menu2) - menu1.getItem(4).setAction(self.dvdPlayer) - - self.menu2.getItem(1).setAction(self.menu1) + for mods in modules: + title = mods.Module.title + image_uri = "ui/"+mods.Module.menu_image + self.splashScreen.set_msg("Loading "+title) + tempMod = mods.Module(self.menuMgr, self.dbMgr) + temp_menu_item = MainMenu.addItem(title, image_uri) + + temp_menu_item.setAction(tempMod.action()) self.splashScreen.remove() self.stage.connect('key-press-event', self.menuMgr.on_key_press_event) - self.menu1.display() - self.menu1.selectFirst(True) + MainMenu.display() + MainMenu.selectFirst(True) return False #print self.menuMgr.get_selector_bar().get_abs_position() diff --git a/modules/dvd_player/dvd_player.py b/modules/dvd_player/dvd_player.py index 2672c82..d129633 100644 --- a/modules/dvd_player/dvd_player.py +++ b/modules/dvd_player/dvd_player.py @@ -2,15 +2,19 @@ import clutter from clutter import cluttergst from VideoController import VideoController -class DvdPlayer: +class Module: + title = "DVD" + menu_image = "dvd.png" - def __init__(self, Stage): - self.stage = Stage + def __init__(self, MenuMgr, dbMgr): + self.stage = MenuMgr.get_stage() self.paused = False self.isPlaying = False self.overlay = None - + #Action to take when menu item is selected + def action(self): + return self def on_key_press_event (self, stage, event): if self.isPlaying: diff --git a/modules/music_player/music_player.py b/modules/music_player/music_player.py index a84fd5a..22363d4 100644 --- a/modules/music_player/music_player.py +++ b/modules/music_player/music_player.py @@ -3,14 +3,20 @@ import gtk import clutter import eyeD3 -class MusicPlayer(): +class Module(): + title = "Music" + menu_image = "dvd.png" - def __init__(self, stage): - self.stage = stage + def __init__(self, MenuMgr, dbMgr): + self.stage = MenuMgr.get_stage() self.cover_viewer = coverViewer(self.stage) self.is_playing = False + #Action to take when menu item is selected + def action(self): + return self + def on_key_press_event (self, stage, event): if event.keyval == clutter.keysyms.p: if self.paused: diff --git a/modules/myth_tv_player/myth_tv_player.py b/modules/myth_tv_player/myth_tv_player.py index 162c557..329de3e 100644 --- a/modules/myth_tv_player/myth_tv_player.py +++ b/modules/myth_tv_player/myth_tv_player.py @@ -9,14 +9,19 @@ from modules.myth_tv_player.MythBackendConn import MythBackendConnection from Menu import Menu from VideoController import VideoController -class TVPlayer: +class Module: + title = "TV" + menu_image = "dvd.png" - def __init__(self, stage, dbMgr): - self.videoController = VideoController(stage) - self.stage = stage + def __init__(self, MenuMgr, dbMgr): + self.stage = MenuMgr.get_stage() + self.videoController = VideoController(self.stage) self.dbMgr = dbMgr self.isRunning = False - + + #Action to take when menu item is selected + def action(self): + return self def begin(self, menuMgr): self.menuMgr = menuMgr diff --git a/modules/slideshow/slideshow.py b/modules/slideshow/slideshow.py index 0ce413f..bd686ce 100644 --- a/modules/slideshow/slideshow.py +++ b/modules/slideshow/slideshow.py @@ -9,7 +9,10 @@ import gtk import random #import thread -class Slideshow: +class Module: + title = "Slideshow" + menu_image= "gallery.png" + image_file_types = ["jpg", "gif", "jpeg", "png", "bmp"] sound_file_types = ["mp3", "wav", "ogg"] #possibly more supported by default? imageDuration = 7 # In seconds @@ -28,6 +31,9 @@ class Slideshow: #Load the base image directory. This is pulled from the myth db's settings table self.baseDir = dbMgr.get_setting('GalleryDir') + def action(self): + return self.generateMenu() + def on_key_press_event (self, stage, event): #print event.hardware_keycode if event.keyval == clutter.keysyms.p: @@ -90,6 +96,10 @@ class Slideshow: def begin(self, MenuMgr): self.stage = self.MenuMgr.get_stage() + #Check for an empty baseDir, this means there are no slideshows or no db connection. We simply tell the menuMgr to go back a menu level when this occurs + if self.baseDir is None: + MenuMgr.go_up_x_levels(1) + return #self.MenuMgr.get_selector_bar().set_spinner(True) #self.stage.queue_redraw() @@ -326,6 +336,12 @@ class Slideshow: tempMenu = Menu(self.MenuMgr) #print self.baseDir + #This occurs when there are not slideshows or we could not connect to the db to establish baseDir + if self.baseDir is None: + tempItem = tempMenu.addItem("No slideshows available", "") + tempItem.setAction(self) + return + file_list = os.listdir(self.baseDir) for directoryEntry in file_list: @@ -334,7 +350,7 @@ class Slideshow: if not (len(os.listdir(subdir)) == 0): imgPath = subdir + "/" + os.listdir(subdir)[0] #print imgPath - tempItem = tempMenu.addItem(directoryEntry, "/home/josh/.mythtv/MythVideo/0088763.jpg") + tempItem = tempMenu.addItem(directoryEntry, "") tempItem.setAction(self) diff --git a/Plugin.py b/modules/video_player/__init__.py similarity index 100% rename from Plugin.py rename to modules/video_player/__init__.py diff --git a/modules/video_player/cover_viewer.py b/modules/video_player/cover_viewer.py new file mode 100644 index 0000000..1af2e93 --- /dev/null +++ b/modules/video_player/cover_viewer.py @@ -0,0 +1,327 @@ +import pygtk +import gtk +import pygst +import gst +import gobject +import pango +import clutter + +class coverViewer(clutter.Group): + scaleFactor = 1.4 + inactiveOpacity = 150 + + + def __init__(self, stage, width, height): + clutter.Group.__init__(self) + self.stage = stage + self.videoLibrary = [] + self.textureLibrary = [] + self.current_video_details = video_details_group(width) + self.covers_group = clutter.Group() + self.num_covers = 0 + + self.cover_gap = 1 + + self.num_visible_rows = 3 + self.num_columns = 4 + self.cover_size = int(width / self.num_columns) #200 #A cover will be cover_size * cover_size (X * Y) + + #Setup the current min and max viewable rows + self.min_visible_rows = 0 + self.max_visible_rows = self.num_visible_rows + + self.currentSelection = 0 + + self.add(self.covers_group) + self.covers_group.show() + + #self.stage.add(self.current_video_description) + self.current_video_details.show() + self.current_video_details.show_all() + + + #Turns the description group off and on + def toggle_details(self): + if self.current_video_details.get_parent() == None: + self.add(self.current_video_details) + #Set the position of the details group + (pos_x, pos_y) = self.get_abs_position() + #The next two lines are horribly ugly, but all they do is position the details viewer in the middle of the gap between the bottom of the visible cover viewer and the bottom of the stage + viewer_lower_y = int(pos_y + (self.max_visible_rows * self.cover_size)) + pos_y = viewer_lower_y# + int( (self.stage.get_height() - viewer_lower_y) / 2 - int(self.current_video_details.get_height()/2)) + self.current_video_details.set_position(20, pos_y) + else: + self.stage.remove(self.current_video_details) + + def add_video(self, video): + self.videoLibrary.append(video) + imagePath = video.getCoverfile() + tempTexture = clutter.Texture() + pixbuf = gtk.gdk.pixbuf_new_from_file(imagePath) + tempTexture.set_pixbuf(pixbuf) + xy_ratio = float(tempTexture.get_width()) / tempTexture.get_height() + + width = int(self.cover_size * xy_ratio) + tempTexture.set_width(width) + tempTexture.set_height(self.cover_size) + tempTexture.set_opacity(self.inactiveOpacity) + + tempTexture.set_position( (self.num_covers * self.cover_size), 0) + tempTexture.set_depth(1) + + self.textureLibrary.append(tempTexture) + + #x = (self.cover_gap + self.cover_size) * (self.num_covers/self.num_rows) + #y = (self.num_covers % self.num_rows) * self.cover_size + ( (self.num_covers % self.num_rows) * self.cover_gap) + x = (self.num_covers % self.num_columns) * self.cover_size + ( (self.num_covers % self.num_columns) * self.cover_gap) + y = (self.cover_gap + self.cover_size) * (self.num_covers/self.num_columns) + + #Center the cover + if width < self.cover_size: + x = x + (self.cover_size - width)/2 + + tempTexture.set_position(x, y) + + #If we're past the maximum rows, make the pics invistible + if self.num_covers > (self.num_columns * self.num_visible_rows)-1: + tempTexture.set_opacity(0) + else: + self.covers_group.add(tempTexture) + + tempTexture.show() + self.num_covers = self.num_covers +1 + + def select_item(self, incomingItem, outgoingItem): + self.timeline = clutter.Timeline(10,35) + self.current_video_details.set_video(self.videoLibrary[incomingItem], self.timeline) + + #Check if the cover is currently not visible + rolling = False + if incomingItem > (self.num_columns * self.max_visible_rows-1): + self.rollViewer(True, self.timeline) + rolling = True + if incomingItem < (self.num_columns * self.min_visible_rows): + self.rollViewer(False, self.timeline) + rolling = True + + outgoingTexture = self.textureLibrary[outgoingItem] + incomingTexture = self.textureLibrary[incomingItem] + + alpha = clutter.Alpha(self.timeline, clutter.smoothstep_inc_func)# clutter.ramp_inc_func) + self.behaviourNew_scale = clutter.BehaviourScale(alpha, 1, self.scaleFactor, clutter.GRAVITY_CENTER) + self.behaviourNew_z = clutter.BehaviourDepth(alpha, 1, 2) + #If we're performing a roll (See above) then the incoming opacity should start at 0 rather than the normal inactive opacity + if rolling: + self.behaviourNew_opacity = clutter.BehaviourOpacity(alpha, 0, 255) + else: + self.behaviourNew_opacity = clutter.BehaviourOpacity(alpha, self.inactiveOpacity, 255) + + self.behaviourOld_scale = clutter.BehaviourScale(alpha, self.scaleFactor, 1, clutter.GRAVITY_CENTER) + self.behaviourOld_z = clutter.BehaviourDepth(alpha, 2, 1) + self.behaviourOld_opacity = clutter.BehaviourOpacity(alpha, 255, self.inactiveOpacity) + + self.behaviourNew_scale.apply(incomingTexture) + self.behaviourNew_z.apply(incomingTexture) + self.behaviourNew_opacity.apply(incomingTexture) + self.behaviourOld_scale.apply(outgoingTexture) + self.behaviourOld_z.apply(outgoingTexture) + self.behaviourOld_opacity.apply(outgoingTexture) + + self.currentSelection = incomingItem + + self.timeline.start() + + def select_first(self): + self.timeline = clutter.Timeline(20,80) + self.current_video_details.set_video(self.videoLibrary[0], self.timeline) + + + incomingItem = 0 + incomingTexture = self.textureLibrary[incomingItem] + + alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func) + self.behaviourNew_scale = clutter.BehaviourScale(alpha, 1, self.scaleFactor, clutter.GRAVITY_CENTER) + self.behaviourNew_z = clutter.BehaviourDepth(alpha, 1, 2) + self.behaviourNew_opacity = clutter.BehaviourOpacity(alpha, self.inactiveOpacity, 255) + + self.behaviourNew_scale.apply(incomingTexture) + self.behaviourNew_z.apply(incomingTexture) + self.behaviourNew_opacity.apply(incomingTexture) + + self.currentSelection = incomingItem + self.timeline.start() + + #This moves the visible row of covers up and down + # moveUp: True if the covers are to come up, false if they're to go down + def rollViewer(self, moveUp, timeline): + if moveUp: + new_y = self.covers_group.get_y() - self.cover_size + self.max_visible_rows = self.max_visible_rows + 1 + self.min_visible_rows = self.min_visible_rows + 1 + + #Define the row of covers that now needs to disapear / appear + min_outgoing = (self.min_visible_rows-1) * self.num_columns + max_outgoing = min_outgoing + self.num_columns + min_incoming = (self.max_visible_rows-1) * self.num_columns + max_incoming = min_incoming + self.num_columns + + #Quick check to make sure that max_incoming isn't greater than the max number of images (This occurs when the final row is incomplete) + if max_incoming > self.num_covers: + max_incoming = min_incoming + (self.num_covers % self.num_columns) + else: + new_y = self.covers_group.get_y() + self.cover_size + self.max_visible_rows = self.max_visible_rows - 1 + self.min_visible_rows = self.min_visible_rows - 1 + + #Define the row of covers that now needs to disapear / appear + min_incoming = (self.min_visible_rows) * self.num_columns + max_incoming = min_incoming + self.num_columns + min_outgoing = (self.max_visible_rows) * self.num_columns + max_outgoing = min_outgoing + self.num_columns + + #Quick check to make sure that max_outgoing isn't greater than the max number of images (This occurs when the final row is incomplete) + if max_outgoing > self.num_covers: + max_outgoing = min_outgoing + (self.num_covers % self.num_columns) + + #Need to add the new row to the group + self.addIncomingRow(min_incoming, max_incoming) + #And set the outgoing row to remove after the timeline finishes + self.timeline.connect('completed', self.removeOutgoingRow, min_outgoing, max_outgoing) + + + knots = (\ + (self.covers_group.get_x(), self.covers_group.get_y()),\ + (self.covers_group.get_x(), new_y) \ + ) + + alpha = clutter.Alpha(timeline, clutter.ramp_inc_func) + self.behaviour_path = clutter.BehaviourPath(alpha, knots) + self.behaviour_incoming = clutter.BehaviourOpacity(alpha, 0, self.inactiveOpacity) + self.behaviour_outgoing = clutter.BehaviourOpacity(alpha, self.inactiveOpacity, 0) + + self.behaviour_path.apply(self.covers_group) + #Also need to change a few opacities - This is really messy, but works + for i in range(min_outgoing, max_outgoing): + self.behaviour_outgoing.apply(self.textureLibrary[i]) + for i in range(min_incoming, max_incoming): + self.behaviour_incoming.apply(self.textureLibrary[i]) + + def removeOutgoingRow(self, timeline, min, max): + for i in range(min, max): + self.covers_group.remove(self.textureLibrary[i]) + + def addIncomingRow(self, min, max): + for i in range(min, max): + self.covers_group.add(self.textureLibrary[i]) + + #xy_ratio = float(self.textureLibrary[i].get_width()) / self.textureLibrary[i].get_height() + #width = int(self.cover_size * xy_ratio) + + #x = (i % self.num_columns) * self.cover_size + ( (i % self.num_columns) * self.cover_gap) + #y = (self.cover_gap + self.cover_size) * (i/self.num_columns) + + #Center the cover + #if width < self.cover_size: + # x = x + (self.cover_size - width)/2 + + #self.textureLibrary[i].set_position(x, y) + self.textureLibrary[i].show() + + def get_current_video(self): + return self.videoLibrary[self.currentSelection] + + def on_key_press_event(self, event): + newItem = None + if event.keyval == clutter.keysyms.Left: + #Make sure we're not already on the first cover + if not self.currentSelection == 0: + newItem = self.currentSelection - 1 + elif event.keyval == clutter.keysyms.Right: + #This check makes sure that we're not on the last cover already + if not self.currentSelection == (self.num_covers-1): + newItem = self.currentSelection + 1 + elif event.keyval == clutter.keysyms.Down: + #Check if we're already on the bottom row + if not (self.currentSelection > (len(self.textureLibrary)-1 - self.num_columns)): + newItem = self.currentSelection + self.num_columns + elif event.keyval == clutter.keysyms.Up: + #Check if we're already on the top row + if not (self.currentSelection < self.num_columns): + newItem = self.currentSelection - self.num_columns + + #Final sanity check + if (newItem < 0) and (not newItem == None): + newItem = self.currentSelection + + #If there is movement, make the scale happen + if not newItem == None: + self.select_item(newItem, self.currentSelection) + +class video_details_group(clutter.Group): + font = "Lucida Grande " + title_font_size = 30 + main_font_size = 22 + plot_font_size = 18 + + def __init__(self, desired_width): + clutter.Group.__init__(self) + self.width = desired_width + + #Add the various labels + self.title = clutter.Label() + self.title.set_font_name(self.font + str(self.title_font_size)) + self.title.set_color(clutter.color_parse('White')) + self.title.set_text("") + self.title.set_ellipsize(pango.ELLIPSIZE_END) + self.add(self.title) + + #Not sure how to get the row height before the text is set :( + self.row_gap = self.title.get_height() + + self.year = clutter.Label() + self.year.set_font_name(self.font + str(self.main_font_size)) + self.year.set_color(clutter.color_parse('White')) + self.year.set_text("") + self.year.set_opacity(220) + self.year.set_ellipsize(pango.ELLIPSIZE_END) + self.year.set_position(0, self.row_gap) + self.add(self.year) + + self.director = clutter.Label() + self.director.set_font_name(self.font + str(self.main_font_size)) + self.director.set_color(clutter.color_parse('White')) + self.director.set_text("") + self.director.set_opacity(220) + self.director.set_ellipsize(pango.ELLIPSIZE_END) + self.director.set_position(int(self.year.get_width()), self.row_gap) + self.add(self.director) + + self.plot = clutter.Label() + self.plot.set_font_name(self.font + str(self.plot_font_size)) + self.plot.set_color(clutter.color_parse('White')) + self.plot.set_text("") + self.plot.set_opacity(220) + #self.plot.set_ellipsize(pango.ELLIPSIZE_END) + self.plot.set_position(0, int(self.row_gap*2)) + self.add(self.plot) + + self.show_all() + + def set_video_bare(self,video): + self.timeline = clutter.Timeline(10,45) + self.set_video(video, self.timeline) + + def set_video(self, video, timeline): + self.video = video + + self.title.set_text(video.title) + self.title.set_width(self.width) + + self.year.set_text("Year: " + str(video.year)) + + self.director.set_text(" Director: " + str(video.director)) + self.director.set_position(int(self.year.get_width()), self.row_gap) + self.director.set_width(int(self.width - self.year.get_width())) + + self.plot.set_text(video.plot) + self.plot.set_width(self.width) \ No newline at end of file diff --git a/modules/video_player/video_player.py b/modules/video_player/video_player.py index 37e2a92..9e984f2 100644 --- a/modules/video_player/video_player.py +++ b/modules/video_player/video_player.py @@ -7,13 +7,16 @@ import pango import clutter from clutter import cluttergst from VideoController import VideoController +from modules.video_player.cover_viewer import coverViewer -class VideoPlayer(): +class Module(): + title = "Videos" + menu_image= "videos.png" - def __init__(self, stage, dbMgr): - self.stage = stage + def __init__(self, MenuMgr, dbMgr): + self.stage = MenuMgr.get_stage() self.cover_viewer = coverViewer(self.stage, 800, 600) - self.videoController = VideoController(stage) + self.videoController = VideoController(self.stage) self.is_playing = False #This block can be moved to begin() but causes a performance hit when loading the module *shrug* @@ -27,7 +30,9 @@ class VideoPlayer(): tempVideo.importFromMythObject(record) self.cover_viewer.add_video(tempVideo) - + #Action to take when menu item is selected + def action(self): + return self def on_key_press_event (self, stage, event): if self.is_playing: @@ -120,6 +125,16 @@ class VideoPlayer(): self.is_playing = False + timeline = clutter.Timeline(15, 25) + self.cover_viewer.set_opacity(0) + alpha = clutter.Alpha(timeline, clutter.ramp_inc_func) + self.behaviour = clutter.BehaviourOpacity(alpha, 0,255) + self.behaviour.apply(self.cover_viewer) + + self.stage.add(self.cover_viewer) + self.cover_viewer.show() + timeline.start() + def pause(self): pass @@ -153,321 +168,4 @@ class videoItem(): def getCoverfile(self): return self.coverfile -class coverViewer(clutter.Group): - scaleFactor = 1.4 - inactiveOpacity = 150 - def __init__(self, stage, width, height): - clutter.Group.__init__(self) - self.stage = stage - self.videoLibrary = [] - self.textureLibrary = [] - self.current_video_details = video_details_group(width) - self.covers_group = clutter.Group() - self.num_covers = 0 - - self.cover_gap = 1 - - self.num_visible_rows = 3 - self.num_columns = 4 - self.cover_size = int(width / self.num_columns) #200 #A cover will be cover_size * cover_size (X * Y) - - #Setup the current min and max viewable rows - self.min_visible_rows = 0 - self.max_visible_rows = self.num_visible_rows - - self.currentSelection = 0 - - self.add(self.covers_group) - self.covers_group.show() - - #self.stage.add(self.current_video_description) - self.current_video_details.show() - self.current_video_details.show_all() - - - #Turns the description group off and on - def toggle_details(self): - if self.current_video_details.get_parent() == None: - self.add(self.current_video_details) - #Set the position of the details group - (pos_x, pos_y) = self.get_abs_position() - #The next two lines are horribly ugly, but all they do is position the details viewer in the middle of the gap between the bottom of the visible cover viewer and the bottom of the stage - viewer_lower_y = int(pos_y + (self.max_visible_rows * self.cover_size)) - pos_y = viewer_lower_y# + int( (self.stage.get_height() - viewer_lower_y) / 2 - int(self.current_video_details.get_height()/2)) - self.current_video_details.set_position(20, pos_y) - else: - self.stage.remove(self.current_video_details) - - def add_video(self, video): - self.videoLibrary.append(video) - imagePath = video.getCoverfile() - tempTexture = clutter.Texture() - pixbuf = gtk.gdk.pixbuf_new_from_file(imagePath) - tempTexture.set_pixbuf(pixbuf) - xy_ratio = float(tempTexture.get_width()) / tempTexture.get_height() - - width = int(self.cover_size * xy_ratio) - tempTexture.set_width(width) - tempTexture.set_height(self.cover_size) - tempTexture.set_opacity(self.inactiveOpacity) - - tempTexture.set_position( (self.num_covers * self.cover_size), 0) - tempTexture.set_depth(1) - - self.textureLibrary.append(tempTexture) - - #x = (self.cover_gap + self.cover_size) * (self.num_covers/self.num_rows) - #y = (self.num_covers % self.num_rows) * self.cover_size + ( (self.num_covers % self.num_rows) * self.cover_gap) - x = (self.num_covers % self.num_columns) * self.cover_size + ( (self.num_covers % self.num_columns) * self.cover_gap) - y = (self.cover_gap + self.cover_size) * (self.num_covers/self.num_columns) - - #Center the cover - if width < self.cover_size: - x = x + (self.cover_size - width)/2 - - tempTexture.set_position(x, y) - - #If we're past the maximum rows, make the pics invistible - if self.num_covers > (self.num_columns * self.num_visible_rows)-1: - tempTexture.set_opacity(0) - else: - self.covers_group.add(tempTexture) - - tempTexture.show() - self.num_covers = self.num_covers +1 - - def select_item(self, incomingItem, outgoingItem): - self.timeline = clutter.Timeline(10,35) - self.current_video_details.set_video(self.videoLibrary[incomingItem], self.timeline) - - #Check if the cover is currently not visible - rolling = False - if incomingItem > (self.num_columns * self.max_visible_rows-1): - self.rollViewer(True, self.timeline) - rolling = True - if incomingItem < (self.num_columns * self.min_visible_rows): - self.rollViewer(False, self.timeline) - rolling = True - - outgoingTexture = self.textureLibrary[outgoingItem] - incomingTexture = self.textureLibrary[incomingItem] - - alpha = clutter.Alpha(self.timeline, clutter.smoothstep_inc_func)# clutter.ramp_inc_func) - self.behaviourNew_scale = clutter.BehaviourScale(alpha, 1, self.scaleFactor, clutter.GRAVITY_CENTER) - self.behaviourNew_z = clutter.BehaviourDepth(alpha, 1, 2) - #If we're performing a roll (See above) then the incoming opacity should start at 0 rather than the normal inactive opacity - if rolling: - self.behaviourNew_opacity = clutter.BehaviourOpacity(alpha, 0, 255) - else: - self.behaviourNew_opacity = clutter.BehaviourOpacity(alpha, self.inactiveOpacity, 255) - - self.behaviourOld_scale = clutter.BehaviourScale(alpha, self.scaleFactor, 1, clutter.GRAVITY_CENTER) - self.behaviourOld_z = clutter.BehaviourDepth(alpha, 2, 1) - self.behaviourOld_opacity = clutter.BehaviourOpacity(alpha, 255, self.inactiveOpacity) - - self.behaviourNew_scale.apply(incomingTexture) - self.behaviourNew_z.apply(incomingTexture) - self.behaviourNew_opacity.apply(incomingTexture) - self.behaviourOld_scale.apply(outgoingTexture) - self.behaviourOld_z.apply(outgoingTexture) - self.behaviourOld_opacity.apply(outgoingTexture) - - self.currentSelection = incomingItem - - self.timeline.start() - - def select_first(self): - self.timeline = clutter.Timeline(20,80) - self.current_video_details.set_video(self.videoLibrary[0], self.timeline) - - - incomingItem = 0 - incomingTexture = self.textureLibrary[incomingItem] - - alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func) - self.behaviourNew_scale = clutter.BehaviourScale(alpha, 1, self.scaleFactor, clutter.GRAVITY_CENTER) - self.behaviourNew_z = clutter.BehaviourDepth(alpha, 1, 2) - self.behaviourNew_opacity = clutter.BehaviourOpacity(alpha, self.inactiveOpacity, 255) - - self.behaviourNew_scale.apply(incomingTexture) - self.behaviourNew_z.apply(incomingTexture) - self.behaviourNew_opacity.apply(incomingTexture) - - self.currentSelection = incomingItem - self.timeline.start() - - #This moves the visible row of covers up and down - # moveUp: True if the covers are to come up, false if they're to go down - def rollViewer(self, moveUp, timeline): - if moveUp: - new_y = self.covers_group.get_y() - self.cover_size - self.max_visible_rows = self.max_visible_rows + 1 - self.min_visible_rows = self.min_visible_rows + 1 - - #Define the row of covers that now needs to disapear / appear - min_outgoing = (self.min_visible_rows-1) * self.num_columns - max_outgoing = min_outgoing + self.num_columns - min_incoming = (self.max_visible_rows-1) * self.num_columns - max_incoming = min_incoming + self.num_columns - - #Quick check to make sure that max_incoming isn't greater than the max number of images (This occurs when the final row is incomplete) - if max_incoming > self.num_covers: - max_incoming = min_incoming + (self.num_covers % self.num_columns) - else: - new_y = self.covers_group.get_y() + self.cover_size - self.max_visible_rows = self.max_visible_rows - 1 - self.min_visible_rows = self.min_visible_rows - 1 - - #Define the row of covers that now needs to disapear / appear - min_incoming = (self.min_visible_rows) * self.num_columns - max_incoming = min_incoming + self.num_columns - min_outgoing = (self.max_visible_rows) * self.num_columns - max_outgoing = min_outgoing + self.num_columns - - #Quick check to make sure that max_outgoing isn't greater than the max number of images (This occurs when the final row is incomplete) - if max_outgoing > self.num_covers: - max_outgoing = min_outgoing + (self.num_covers % self.num_columns) - - #Need to add the new row to the group - self.addIncomingRow(min_incoming, max_incoming) - #And set the outgoing row to remove after the timeline finishes - self.timeline.connect('completed', self.removeOutgoingRow, min_outgoing, max_outgoing) - - - knots = (\ - (self.covers_group.get_x(), self.covers_group.get_y()),\ - (self.covers_group.get_x(), new_y) \ - ) - - alpha = clutter.Alpha(timeline, clutter.ramp_inc_func) - self.behaviour_path = clutter.BehaviourPath(alpha, knots) - self.behaviour_incoming = clutter.BehaviourOpacity(alpha, 0, self.inactiveOpacity) - self.behaviour_outgoing = clutter.BehaviourOpacity(alpha, self.inactiveOpacity, 0) - - self.behaviour_path.apply(self.covers_group) - #Also need to change a few opacities - This is really messy, but works - for i in range(min_outgoing, max_outgoing): - self.behaviour_outgoing.apply(self.textureLibrary[i]) - for i in range(min_incoming, max_incoming): - self.behaviour_incoming.apply(self.textureLibrary[i]) - - def removeOutgoingRow(self, timeline, min, max): - for i in range(min, max): - self.covers_group.remove(self.textureLibrary[i]) - - def addIncomingRow(self, min, max): - for i in range(min, max): - self.covers_group.add(self.textureLibrary[i]) - - xy_ratio = float(self.textureLibrary[i].get_width()) / self.textureLibrary[i].get_height() - width = int(self.cover_size * xy_ratio) - - x = (i % self.num_columns) * self.cover_size + ( (i % self.num_columns) * self.cover_gap) - y = (self.cover_gap + self.cover_size) * (i/self.num_columns) - - #Center the cover - if width < self.cover_size: - x = x + (self.cover_size - width)/2 - - self.textureLibrary[i].set_position(x, y) - self.textureLibrary[i].show() - - def get_current_video(self): - return self.videoLibrary[self.currentSelection] - - def on_key_press_event(self, event): - newItem = None - if event.keyval == clutter.keysyms.Left: - #Make sure we're not already on the first cover - if not self.currentSelection == 0: - newItem = self.currentSelection - 1 - elif event.keyval == clutter.keysyms.Right: - #This check makes sure that we're not on the last cover already - if not self.currentSelection == (self.num_covers-1): - newItem = self.currentSelection + 1 - elif event.keyval == clutter.keysyms.Down: - #Check if we're already on the bottom row - if not (self.currentSelection > (len(self.textureLibrary)-1 - self.num_columns)): - newItem = self.currentSelection + self.num_columns - elif event.keyval == clutter.keysyms.Up: - #Check if we're already on the top row - if not (self.currentSelection < self.num_columns): - newItem = self.currentSelection - self.num_columns - - #Final sanity check - if (newItem < 0) and (not newItem == None): - newItem = self.currentSelection - - #If there is movement, make the scale happen - if not newItem == None: - self.select_item(newItem, self.currentSelection) - -class video_details_group(clutter.Group): - font = "Lucida Grande " - title_font_size = 30 - main_font_size = 22 - plot_font_size = 18 - - def __init__(self, desired_width): - clutter.Group.__init__(self) - self.width = desired_width - - #Add the various labels - self.title = clutter.Label() - self.title.set_font_name(self.font + str(self.title_font_size)) - self.title.set_color(clutter.color_parse('White')) - self.title.set_text("") - self.title.set_ellipsize(pango.ELLIPSIZE_END) - self.add(self.title) - - #Not sure how to get the row height before the text is set :( - self.row_gap = self.title.get_height() - - self.year = clutter.Label() - self.year.set_font_name(self.font + str(self.main_font_size)) - self.year.set_color(clutter.color_parse('White')) - self.year.set_text("") - self.year.set_opacity(220) - self.year.set_ellipsize(pango.ELLIPSIZE_END) - self.year.set_position(0, self.row_gap) - self.add(self.year) - - self.director = clutter.Label() - self.director.set_font_name(self.font + str(self.main_font_size)) - self.director.set_color(clutter.color_parse('White')) - self.director.set_text("") - self.director.set_opacity(220) - self.director.set_ellipsize(pango.ELLIPSIZE_END) - self.director.set_position(int(self.year.get_width()), self.row_gap) - self.add(self.director) - - self.plot = clutter.Label() - self.plot.set_font_name(self.font + str(self.plot_font_size)) - self.plot.set_color(clutter.color_parse('White')) - self.plot.set_text("") - self.plot.set_opacity(220) - #self.plot.set_ellipsize(pango.ELLIPSIZE_END) - self.plot.set_position(0, int(self.row_gap*2)) - self.add(self.plot) - - self.show_all() - - def set_video_bare(self,video): - self.timeline = clutter.Timeline(10,45) - self.set_video(video, self.timeline) - - def set_video(self, video, timeline): - self.video = video - - self.title.set_text(video.title) - self.title.set_width(self.width) - - self.year.set_text("Year: " + str(video.year)) - - self.director.set_text(" Director: " + str(video.director)) - self.director.set_position(int(self.year.get_width()), self.row_gap) - self.director.set_width(int(self.width - self.year.get_width())) - - self.plot.set_text(video.plot) - self.plot.set_width(self.width)