gloss-mc/modules/video_player/cover_viewer.py

327 lines
14 KiB
Python

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)