Initial commit
|
@ -0,0 +1,255 @@
|
|||
import clutter
|
||||
import pygtk
|
||||
import gtk
|
||||
import time
|
||||
from ReflectionTexture import Texture_Reflection
|
||||
|
||||
class Menu:
|
||||
item_gap = 10 #Distance between items
|
||||
|
||||
def __init__ (self, menuMgr):
|
||||
self.menuMgr = menuMgr
|
||||
self.stage = self.menuMgr.get_stage()
|
||||
self.menuItems = []
|
||||
self.selected = 0
|
||||
self.displayPosition = (0, 0)
|
||||
self.itemGroup = clutter.Group()
|
||||
self.menuGroup = clutter.Group()
|
||||
self.stage.add(self.itemGroup)
|
||||
self.stage.add(self.menuGroup)
|
||||
#self.hasTimeline = False
|
||||
self.timeline = clutter.Timeline(15, 75) #This timeline is used on any movements that occur when changing items
|
||||
self.timeline_completed=True
|
||||
self.menuMgr.addMenu(self)
|
||||
#self.itemGroup.hide_all()
|
||||
|
||||
def addItem(self, itemLabel, imagePath):
|
||||
if len(self.menuItems) == 0:
|
||||
label_height = 0
|
||||
label_width = 0
|
||||
else:
|
||||
(label_width, label_height) = self.menuItems[0].get_size()
|
||||
|
||||
label_y = label_height * len(self.menuItems)+self.item_gap
|
||||
|
||||
newItem = ListItem(self, itemLabel, label_y, imagePath)
|
||||
self.menuItems.append(newItem)
|
||||
self.itemGroup.add(newItem)
|
||||
|
||||
group_x = self.itemGroup.get_x()
|
||||
group_y = self.itemGroup.get_y() - (label_height)
|
||||
self.itemGroup.set_position(group_x, group_y)
|
||||
|
||||
return newItem
|
||||
|
||||
def getItem(self, index):
|
||||
return self.menuItems[index]
|
||||
def getStage(self):
|
||||
return self.stage
|
||||
def getMenuMgr(self):
|
||||
return self.menuMgr
|
||||
|
||||
def setMenuPositionByName(self, location):
|
||||
if location == "center":
|
||||
menu_y = (self.stage.get_height()-self.itemGroup.get_height())/2
|
||||
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)
|
||||
|
||||
#The display position is the x, y coords of where the menu is when it is active
|
||||
def get_display_position(self):
|
||||
return self.displayPosition
|
||||
|
||||
def setMenuPosition(self, x, y):
|
||||
self.itemGroup.set_position(x,y)
|
||||
|
||||
def getItemGroup(self):
|
||||
return self.itemGroup
|
||||
|
||||
def getMenuGroup(self):
|
||||
return self.menuGroup
|
||||
|
||||
def setListFont(self, newFont):
|
||||
currentY= 0 #self.itemGroup.get_y()
|
||||
self.font = newFont
|
||||
for li in self.menuItems:
|
||||
x = li.get_x()
|
||||
#y = li.getPositionY()
|
||||
li.set_font_name(newFont)
|
||||
li.set_position(x,currentY)
|
||||
currentY = currentY + li.get_height()
|
||||
|
||||
#Returns the newly selected item
|
||||
def selectNext(self):
|
||||
|
||||
#Initially check whether the last animation is still going
|
||||
if self.timeline.is_playing():
|
||||
self.timeline.set_speed(1000) # Nasty hack to make sure the timeline finishes
|
||||
|
||||
|
||||
self.timeline = clutter.Timeline (15,85)
|
||||
#Check if we're at the last item in the list
|
||||
if (self.selected) != (len(self.menuItems)-1):
|
||||
self.selected = self.selected+1
|
||||
|
||||
self.menuItems[self.selected].scaleLabel(0, self.timeline)
|
||||
self.menuItems[self.selected-1].scaleLabel(1, self.timeline)
|
||||
if (self.selected >= 2):
|
||||
self.menuItems[self.selected-2].scaleLabel(2, self.timeline)
|
||||
#Finally move the selection bar
|
||||
self.menuMgr.get_selector_bar().selectItem(self.menuItems[self.selected], self.timeline)
|
||||
|
||||
if self.selected != (len(self.menuItems)-1):
|
||||
self.menuItems[self.selected+1].scaleLabel(1, self.timeline)
|
||||
|
||||
self.timeline.start()
|
||||
|
||||
#Returns the newly selected item
|
||||
def selectPrevious(self):
|
||||
|
||||
#Initially check whether the last animation is still going
|
||||
if self.timeline.is_playing():
|
||||
self.timeline.set_speed(1000) # Nasty hack to make sure the timeline finishes
|
||||
|
||||
self.timeline = clutter.Timeline (15,85)
|
||||
self.timeline_completed=False
|
||||
|
||||
#Check if we're at the first item in the list
|
||||
if (self.selected) != 0:
|
||||
self.selected = self.selected-1
|
||||
#Move the selection bar
|
||||
self.menuMgr.get_selector_bar().selectItem(self.menuItems[self.selected], self.timeline)
|
||||
|
||||
self.menuItems[self.selected].scaleLabel(0, self.timeline)
|
||||
self.menuItems[self.selected+1].scaleLabel(1, self.timeline)
|
||||
if self.selected <= (len(self.menuItems)-3):
|
||||
self.menuItems[self.selected+2].scaleLabel(2, self.timeline)
|
||||
|
||||
if self.selected != 0:
|
||||
self.menuItems[self.selected-1].scaleLabel(1, self.timeline)
|
||||
|
||||
self.timeline.start()
|
||||
|
||||
def selectFirst(self, moveBar):
|
||||
self.timeline = clutter.Timeline(15, 75)
|
||||
self.selected = 0
|
||||
for i in range(0,len(self.menuItems)):
|
||||
if i == 0:
|
||||
self.menuItems[i].scaleLabel(0, self.timeline)
|
||||
elif i == 1:
|
||||
self.menuItems[i].scaleLabel(1, self.timeline)
|
||||
else:
|
||||
self.menuItems[i].scaleLabel(2, self.timeline)
|
||||
|
||||
if moveBar:
|
||||
self.menuMgr.get_selector_bar().selectItem(self.menuItems[self.selected], self.timeline)
|
||||
|
||||
self.timeline.start()
|
||||
|
||||
def get_item_gap(self):
|
||||
return self.item_gap
|
||||
|
||||
def get_current_item(self):
|
||||
return self.menuItems[self.selected]
|
||||
|
||||
|
||||
class ListItem (clutter.Label):
|
||||
zoomLevel = 0.5
|
||||
opacityStep = 120
|
||||
|
||||
def __init__ (self, menu, itemLabel, y, imagePath):
|
||||
clutter.Label.__init__ (self)
|
||||
self.itemTexturesGroup = clutter.Group()
|
||||
font = menu.getMenuMgr().get_skinMgr().get_menu_font()
|
||||
self.set_font_name(font)
|
||||
self.set_text(itemLabel)
|
||||
self.color = clutter.Color(0xff, 0xff, 0xff, 0xdd)
|
||||
self.set_color(self.color)
|
||||
self.currentOpacity = 255
|
||||
self.menu = menu
|
||||
|
||||
#Text is actually scaled down in 'regular' position so that it doesn't get jaggies when zoomed in
|
||||
self.set_scale(self.zoomLevel, self.zoomLevel)
|
||||
self.currentZoom = self.zoomLevel
|
||||
|
||||
|
||||
#(label_width, label_height) = self.label.get_size()
|
||||
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)
|
||||
|
||||
#Add textures group and hide it
|
||||
self.menu.getMenuGroup().add(self.itemTexturesGroup)
|
||||
self.itemTexturesGroup.hide_all()
|
||||
|
||||
def scaleLabel(self, level, timeline):
|
||||
self.timeline = timeline
|
||||
self.timeline.set_loop(False)
|
||||
|
||||
#Determine the zooming level
|
||||
zoomTo=0
|
||||
opacityTo = 255
|
||||
if level==0:
|
||||
zoomTo = 1 #self.zoomLevel * 1.5
|
||||
opacityTo = 255
|
||||
self.itemTexturesGroup.show_all()
|
||||
if level==1:
|
||||
zoomTo = self.zoomLevel * 1.2
|
||||
opacityTo = 255 - self.opacityStep
|
||||
self.itemTexturesGroup.hide_all()
|
||||
if level==2:
|
||||
zoomTo = self.zoomLevel
|
||||
opacityTo = 255 - 2*self.opacityStep
|
||||
self.itemTexturesGroup.hide_all()
|
||||
|
||||
alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
|
||||
self.behaviour1 = clutter.BehaviourScale(alpha, self.currentZoom, zoomTo, clutter.GRAVITY_WEST)
|
||||
self.behaviour2 = clutter.BehaviourOpacity(alpha, self.currentOpacity, opacityTo)
|
||||
self.behaviour1.apply(self)
|
||||
self.behaviour2.apply(self)
|
||||
|
||||
|
||||
self.currentZoom = zoomTo
|
||||
self.currentOpacity = opacityTo
|
||||
return self.timeline
|
||||
|
||||
def get_zoom_level(self):
|
||||
return self.zoomLevel
|
||||
|
||||
|
||||
def addImage(self, path, useReflection):
|
||||
self.tempTexture = clutter.Texture()
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
|
||||
|
||||
self.tempTexture.set_pixbuf(pixbuf)
|
||||
(abs_x, abs_y) = self.get_abs_position()
|
||||
print abs_x
|
||||
x = abs_x# - self.tempTexture.get_width()
|
||||
y = (self.menu.getStage().get_height()/2) - (self.tempTexture.get_height()/2)
|
||||
self.tempTexture.set_position(x, y)
|
||||
|
||||
self.tempTexture.rotate_y(45,0,0)
|
||||
self.itemTexturesGroup.add(self.tempTexture)
|
||||
self.tempTexture.hide_all()
|
||||
|
||||
#Scale the image down by half
|
||||
#self.tempTexture.set_width(self.tempTexture.get_width()/2)
|
||||
#self.tempTexture.set_height(self.tempTexture.get_height()/2)
|
||||
|
||||
if useReflection:
|
||||
self.reflectionTexture = Texture_Reflection(self.tempTexture)
|
||||
#self.reflectionTexture.set_position(0, 0)#self.tempTexture.get_height())
|
||||
self.itemTexturesGroup.add(self.reflectionTexture)
|
||||
self.itemTexturesGroup.hide_all()
|
||||
|
||||
def setAction(self, newAction):
|
||||
self.action = newAction
|
||||
|
||||
def getAction(self):
|
||||
return self.action
|
||||
|
||||
def get_menu(self):
|
||||
return self.menu
|
|
@ -0,0 +1,203 @@
|
|||
import clutter
|
||||
from SkinMgr import SkinMgr
|
||||
from Spinner import Spinner
|
||||
import pygtk
|
||||
import gtk
|
||||
|
||||
class MenuMgr():
|
||||
|
||||
def __init__ (self, stage):
|
||||
self.stage = stage
|
||||
self.menus = []
|
||||
self.currentMenu = None
|
||||
|
||||
self.skinMgr = SkinMgr(self.stage)
|
||||
background = self.skinMgr.get_Background()
|
||||
self.stage.add(background)
|
||||
|
||||
self.selector_bar = MenuSelector(self)
|
||||
self.stage.add(self.selector_bar)
|
||||
self.selector_bar.show_all()
|
||||
self.currentPlugin = None
|
||||
|
||||
def addMenu(self, newMenu):
|
||||
self.menus.append(newMenu)
|
||||
|
||||
#If this is the first menu, make it the active one
|
||||
if self.currentMenu == None:
|
||||
self.currentMenu = newMenu
|
||||
self.currentMenu.getItemGroup().show_all()
|
||||
self.currentMenu.getMenuGroup().show_all()
|
||||
self.selector_bar.set_menu(self.currentMenu)
|
||||
|
||||
def get_selector_bar(self):
|
||||
return self.selector_bar
|
||||
|
||||
def get_stage(self):
|
||||
return self.stage
|
||||
|
||||
def get_skinMgr(self):
|
||||
return self.skinMgr
|
||||
|
||||
def transition_fade_zoom(self, fromMenu, toMenu):
|
||||
oldGroup = fromMenu.getItemGroup()
|
||||
oldMenuGroup = fromMenu.getMenuGroup()
|
||||
newGroup = toMenu.getItemGroup()
|
||||
newMenuGroup = toMenu.getMenuGroup()
|
||||
|
||||
oldGroup.set_opacity(255)
|
||||
|
||||
self.timeline = clutter.Timeline(25, 50)
|
||||
self.alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
|
||||
#self.exit_behaviour_scale = clutter.BehaviourScale(self.alpha, 1, 0.5, clutter.GRAVITY_CENTER)
|
||||
self.exit_behaviour_opacity = clutter.BehaviourOpacity(self.alpha, 150, 0)
|
||||
|
||||
#Setup some knots
|
||||
knots_exiting = (\
|
||||
(oldGroup.get_x(), oldGroup.get_y()),\
|
||||
#(-oldGroup.get_x(), int(fromMenu.getStage().get_height()/2))
|
||||
(-oldGroup.get_x(), oldGroup.get_y())\
|
||||
)
|
||||
self.exit_behaviour_path = clutter.BehaviourPath(self.alpha, knots_exiting)
|
||||
|
||||
#self.exit_behaviour_scale.apply(oldGroup)
|
||||
self.exit_behaviour_opacity.apply(oldGroup)
|
||||
self.exit_behaviour_opacity.apply(oldMenuGroup)
|
||||
self.exit_behaviour_path.apply(oldGroup)
|
||||
|
||||
|
||||
##################################################################
|
||||
#Start incoming menu
|
||||
#self.exit_behaviour_scale = clutter.BehaviourScale(self.alpha, 1, 0.5, clutter.GRAVITY_CENTER)
|
||||
self.entrance_behaviour_opacity = clutter.BehaviourOpacity(self.alpha, 0, 255)
|
||||
|
||||
#Setup some knots
|
||||
start_y = int(self.stage.get_height()/2 - newGroup.get_height()/2)
|
||||
start_x = int(self.stage.get_width())
|
||||
newGroup.set_position(start_x, start_y)
|
||||
#end_x = int(self.stage.get_width() - newGroup.get_width())/2
|
||||
(end_x, end_y) = toMenu.get_display_position()
|
||||
end_x = oldGroup.get_x() #int(end_x)
|
||||
end_y = oldGroup.get_y() #int(end_y)
|
||||
knots_entering = (\
|
||||
(newGroup.get_x(), newGroup.get_y()),\
|
||||
#(-oldGroup.get_x(), int(fromMenu.getStage().get_height()/2))
|
||||
(end_x, end_y) \
|
||||
#toMenu.get_display_position()
|
||||
)
|
||||
|
||||
self.entrance_behaviour_path = clutter.BehaviourPath(self.alpha, knots_entering)
|
||||
|
||||
self.entrance_behaviour_opacity.apply(newGroup)
|
||||
self.entrance_behaviour_opacity.apply(newMenuGroup)
|
||||
self.entrance_behaviour_path.apply(newGroup)
|
||||
newGroup.show_all()
|
||||
newMenuGroup.show_all()
|
||||
|
||||
#Finally, move the selector bar
|
||||
self.selector_bar.selectItem(fromMenu.getItem(0), self.timeline)
|
||||
#(to_x, to_y) = toMenu.get_display_position() #fromMenu.getItem(0).get_abs_position()
|
||||
#self.selector_bar.move_to(int(to_x), int(to_y), self.timeline)
|
||||
toMenu.selectFirst(False)
|
||||
|
||||
#self.timeline.connect('completed', self.on_transition_complete)
|
||||
self.timeline.start()
|
||||
self.currentMenu = toMenu
|
||||
|
||||
def on_key_press_event (self, stage, event):
|
||||
#Firstly checking whether we are in the process of running a plugin (And that the key isn't escape)
|
||||
if (not self.currentPlugin == None) and (not event.keyval == clutter.keysyms.Escape):
|
||||
#If it is, simply pass the event details along to the plugin
|
||||
self.currentPlugin.on_key_press_event(stage, event)
|
||||
return None
|
||||
|
||||
#print event.hardware_keycode
|
||||
if event.keyval == clutter.keysyms.Up: #Up button pressed
|
||||
self.currentMenu.selectPrevious()
|
||||
if event.keyval == clutter.keysyms.Down: #Down button pressed
|
||||
self.currentMenu.selectNext()
|
||||
if event.keyval == clutter.keysyms.q:
|
||||
clutter.main_quit()
|
||||
if event.hardware_keycode == 36: #return button pressed
|
||||
#self.aList.set_processing(True)
|
||||
action = self.currentMenu.get_current_item().getAction()
|
||||
if action.__class__.__name__ == "Menu": # Check whether we're a pointing to a menu object
|
||||
self.transition_fade_zoom(self.currentMenu, action)
|
||||
else:
|
||||
#We have a plugin and need to start it
|
||||
self.currentPlugin = action
|
||||
action.begin(self)
|
||||
if event.keyval == clutter.keysyms.p:
|
||||
self.mySlideshow.startShow(self.stage)
|
||||
if event.keyval == clutter.keysyms.Escape:
|
||||
if not self.currentPlugin == None:
|
||||
self.currentPlugin.stop()
|
||||
self.currentPlugin = None
|
||||
#print event.hardware_keycode
|
||||
|
||||
def get_current_menu(self):
|
||||
return self.currentMenu
|
||||
|
||||
class MenuSelector(clutter.Texture):
|
||||
x_offset = -50
|
||||
|
||||
def __init__ (self, menuMgr):
|
||||
clutter.Texture.__init__ (self)
|
||||
self.menuMgr = menuMgr
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file("ui/active_bar.png")
|
||||
self.set_pixbuf(pixbuf)
|
||||
self.set_width(400)
|
||||
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file("ui/spinner1.gif")
|
||||
self.spinner = clutter.Texture()
|
||||
self.spinner.set_pixbuf(pixbuf)
|
||||
self.spinner.hide()
|
||||
|
||||
|
||||
def selectItem(self, selectee, timeline):
|
||||
(x, y) = selectee.get_abs_position()
|
||||
|
||||
group_x = selectee.get_menu().getItemGroup().get_x()
|
||||
group_y = selectee.get_menu().getItemGroup().get_y()
|
||||
|
||||
x = x + self.x_offset
|
||||
self.timeline = timeline
|
||||
|
||||
#Check if we're going up or down
|
||||
if y > self.get_y():
|
||||
#Going down
|
||||
y = int(y - selectee.get_menu().get_item_gap()/2)
|
||||
else:
|
||||
#Going up
|
||||
y = int(y - selectee.get_menu().get_item_gap()/2)
|
||||
|
||||
self.move_to(x, y, self.timeline)
|
||||
|
||||
def move_to(self, x, y, timeline):
|
||||
self.timeline = timeline
|
||||
knots = (\
|
||||
(self.get_x(), self.get_y()),\
|
||||
(x, y)\
|
||||
)
|
||||
|
||||
self.alpha = clutter.Alpha(self.timeline, clutter.ramp_inc_func)
|
||||
self.behaviour = clutter.BehaviourPath(self.alpha, knots)
|
||||
|
||||
self.behaviour.apply(self)
|
||||
|
||||
def set_menu(self, menu):
|
||||
self.menu = menu
|
||||
|
||||
def set_spinner(self, state):
|
||||
if state:
|
||||
self.spinner = Spinner()
|
||||
self.spinner.show()
|
||||
self.menuMgr.get_stage().add(self.spinner)
|
||||
else:
|
||||
self.menuMgr.get_stage().remove(self.spinner)
|
||||
self.spinner = None
|
||||
|
||||
|
||||
def get_x_offset(self):
|
||||
return self.x_offset
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
import pygtk
|
||||
import gtk
|
||||
import clutter
|
||||
import eyeD3
|
||||
|
||||
class MusicPlayer():
|
||||
|
||||
def __init__(self, stage):
|
||||
self.stage = stage
|
||||
self.cover_viewer = coverViewer(self.stage)
|
||||
|
||||
self.is_playing = False
|
||||
|
||||
def on_key_press_event (self, stage, event):
|
||||
if event.keyval == clutter.keysyms.p:
|
||||
if self.paused:
|
||||
self.unpause()
|
||||
else:
|
||||
self.pause()
|
||||
if event.keyval == clutter.keysyms.q:
|
||||
clutter.main_quit()
|
||||
|
||||
def begin(self, MenuMgr):
|
||||
|
||||
#Create a backdrop for the player. In this case we just use the same background as the menus
|
||||
self.backdrop = clutter.CloneTexture(MenuMgr.get_skinMgr().get_Background())
|
||||
self.backdrop.set_size(self.stage.get_width(), self.stage.get_height())
|
||||
self.backdrop.set_opacity(0)
|
||||
self.backdrop.show()
|
||||
self.stage.add(self.backdrop)
|
||||
#Fade the backdrop in
|
||||
timeline_backdrop = clutter.Timeline(10,40)
|
||||
alpha = clutter.Alpha(timeline_backdrop, clutter.ramp_inc_func)
|
||||
backdrop_behaviour = clutter.BehaviourOpacity(alpha, 0, 255)
|
||||
backdrop_behaviour.apply(self.backdrop)
|
||||
timeline_backdrop.start()
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def pause(self):
|
||||
pass
|
||||
|
||||
def unpause(self):
|
||||
pass
|
||||
|
||||
|
||||
class coverViewer(clutter.Group):
|
||||
|
||||
def __init__(self, stage):
|
||||
clutter.Group.__init__(self)
|
||||
self.stage = stage
|
||||
self.covers = []
|
||||
self.num_covers = 0
|
||||
self.cover_size = 50 #A cover will be cover_size * cover_size (X * Y)
|
||||
self.cover_gap = 10
|
||||
|
||||
self.num_rows = 2
|
||||
self.num_columns = int(self.stage.get_width() / self.cover_size)
|
||||
|
||||
def add_image(self, imagePath):
|
||||
tempTexture = clutter.Texture()
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file(imagePath)
|
||||
tempTexture.set_pixbuf(pixbuf)
|
||||
xy_ratio = tempTexture.get_width() / tempTexture.get_height()
|
||||
|
||||
height = int(self.cover_size * xy_ratio)
|
||||
tempTexture.set_width(self.cover_size)
|
||||
tempTexture.set_height(height)
|
||||
|
||||
self.add(tempTexture)
|
||||
self.num_covers = self.num_covers +1
|
||||
|
||||
#Redo positioning on all textures to add new one :(
|
||||
"""for i = 0 to self.num_covers:
|
||||
tempTexture = self.get_nth_child(i)
|
||||
x = (self.cover_gap + self.cover_size) * i
|
||||
y = (i % self.num_rows) * self.cover_size
|
||||
tempTexture.set_position(x, y)"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import clutter
|
||||
|
||||
"""
|
||||
A Page is like a menu, but without the menu and 'things' placed everywhere
|
||||
instead of menu items
|
||||
"""
|
||||
class Page():
|
||||
|
||||
def __init__():
|
||||
pass
|
|
@ -0,0 +1,29 @@
|
|||
import clutter
|
||||
|
||||
class Texture_Reflection (clutter.Texture):
|
||||
|
||||
def __init__(self, origTexture):
|
||||
clutter.Texture.__init__(self)
|
||||
self.set_pixbuf(origTexture.get_pixbuf())
|
||||
|
||||
self.set_width(origTexture.get_width())
|
||||
self.set_height(origTexture.get_height())
|
||||
|
||||
#Rotate the reflection based on any rotations to the master
|
||||
ang_y = origTexture.get_ryang()
|
||||
self.rotate_y(ang_y,0,0)
|
||||
ang_x = origTexture.get_rxang()
|
||||
self.rotate_x(ang_x,0,0)
|
||||
ang_z = origTexture.get_rzang()
|
||||
self.rotate_z(ang_z,0,0)
|
||||
|
||||
#Get the location for it
|
||||
(x, y) = origTexture.get_abs_position()
|
||||
|
||||
#self.set_clip(0,self.get_height()/2,self.get_width(), (self.get_height()/2))
|
||||
|
||||
#Flip it upside down
|
||||
self.rotate_x(180,origTexture.get_height(),0)
|
||||
self.set_opacity(50)
|
||||
|
||||
self.set_position(x, y)
|
|
@ -0,0 +1,19 @@
|
|||
import clutter
|
||||
import pygtk
|
||||
import gtk
|
||||
|
||||
class SkinMgr:
|
||||
|
||||
def __init__ (self, mainStage):
|
||||
self.stage = mainStage
|
||||
|
||||
def get_Background(self):
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file("ui/background.png")
|
||||
self.background = clutter.Texture()
|
||||
self.background.set_pixbuf(pixbuf)
|
||||
self.background.set_size(self.stage.get_width(), self.stage.get_height())
|
||||
self.background.show()
|
||||
return self.background
|
||||
|
||||
def get_menu_font(self):
|
||||
return 'Tahoma 40'
|
|
@ -0,0 +1,330 @@
|
|||
import clutter
|
||||
from clutter import cluttergst
|
||||
from Menu import Menu
|
||||
import time
|
||||
import os.path
|
||||
import pygtk
|
||||
import gtk
|
||||
import random
|
||||
import thread
|
||||
|
||||
class Slideshow:
|
||||
image_file_types = ["jpg", "gif", "jpeg", "png", "bmp"]
|
||||
sound_file_types = ["mp3", "wav", "ogg"] #possibly more supported by default?
|
||||
imageDuration = 5 # In seconds
|
||||
effect_FPS = 50
|
||||
|
||||
def __init__(self, MenuMgr, basedir):
|
||||
self.image_texture_group = clutter.Group()
|
||||
self.baseDir = basedir
|
||||
self.MenuMgr = MenuMgr
|
||||
self.currentTexture = clutter.Texture()
|
||||
self.currentSong = None
|
||||
self.paused = False
|
||||
self.textures = []
|
||||
self.music = []
|
||||
self.overlay = clutter.Rectangle()
|
||||
self.backdrop = None
|
||||
|
||||
def on_key_press_event (self, stage, event):
|
||||
#print event.hardware_keycode
|
||||
if event.keyval == clutter.keysyms.p:
|
||||
if self.paused:
|
||||
self.unpause()
|
||||
else:
|
||||
self.pause()
|
||||
if event.keyval == clutter.keysyms.q:
|
||||
clutter.main_quit()
|
||||
|
||||
def loadDir(self, dirPath, recurse):
|
||||
if not os.path.isdir(dirPath):
|
||||
print "ERROR: Invalid path"
|
||||
return None
|
||||
|
||||
new_file_list = os.listdir(dirPath)
|
||||
|
||||
#If recursive sub-dirs is on, loop through any directories
|
||||
if recurse:
|
||||
for fs_object in new_file_list:
|
||||
path = dirPath + "/" + fs_object
|
||||
if os.path.isdir(path):
|
||||
self.loadDir(path, True)
|
||||
|
||||
new_image_list = filter(self.filterImageFile, new_file_list)
|
||||
new_sound_list = filter(self.filterSoundFile, new_file_list)
|
||||
|
||||
#Load pictures into textures array
|
||||
i = len(self.textures)
|
||||
for pic in new_image_list:
|
||||
self.textures.append(clutter.Texture())
|
||||
imgName = dirPath + "/" + pic
|
||||
#print imgName
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file(imgName)
|
||||
self.textures[i].set_pixbuf(pixbuf)
|
||||
self.textures[i].set_position(0,0)
|
||||
self.image_texture_group.add(self.textures[i])
|
||||
i = i+1
|
||||
|
||||
#Load sound into music array
|
||||
i = len(self.music)
|
||||
for sound in new_sound_list:
|
||||
self.music.append(cluttergst.Audio())
|
||||
sndName = dirPath + "/" + sound
|
||||
self.music[i].set_filename(sndName)
|
||||
i = i+1
|
||||
|
||||
#This makes sure we only take in image files
|
||||
def filterImageFile(self, fileName):
|
||||
extension = fileName[-3:] #Get 3 letter extension
|
||||
if extension in self.image_file_types:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
#This makes sure we only take in sound files
|
||||
def filterSoundFile(self, fileName):
|
||||
extension = fileName[-3:] #Get 3 letter extension
|
||||
if extension in self.sound_file_types:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def begin(self, MenuMgr):
|
||||
self.stage = self.MenuMgr.get_stage()
|
||||
|
||||
self.MenuMgr.get_selector_bar().set_spinner(True)
|
||||
self.stage.queue_redraw()
|
||||
|
||||
|
||||
slideName = self.baseDir + "/" + self.MenuMgr.get_current_menu().get_current_item().get_text()
|
||||
self.loadDir(slideName, True)
|
||||
self.MenuMgr.get_selector_bar().set_spinner(False)
|
||||
|
||||
if self.backdrop == None:
|
||||
#Create a rectangle that serves as the backdrop for the slideshow
|
||||
self.backdrop = clutter.Rectangle()
|
||||
self.backdrop.set_color(clutter.color_parse('Black'))
|
||||
self.backdrop.set_width(self.stage.get_width())
|
||||
self.backdrop.set_height(self.stage.get_height())
|
||||
self.stage.add(self.backdrop)
|
||||
#Fade the backdrop in
|
||||
self.image_texture_group.set_opacity(255)
|
||||
self.backdrop.set_opacity(0)
|
||||
self.backdrop.show()
|
||||
timeline_backdrop = clutter.Timeline(10,30)
|
||||
alpha = clutter.Alpha(timeline_backdrop, clutter.ramp_inc_func)
|
||||
backdrop_behaviour = clutter.BehaviourOpacity(alpha, 0, 255)
|
||||
backdrop_behaviour.apply(self.backdrop)
|
||||
timeline_backdrop.start()
|
||||
|
||||
|
||||
self.stage.add(self.image_texture_group)
|
||||
#print "No of children: " + str(self.image_texture_group.get_n_children())
|
||||
#Get a random texture
|
||||
self.rand1 = random.randint(0, self.image_texture_group.get_n_children()-1)
|
||||
self.currentTexture = self.textures[self.rand1]
|
||||
#Make sure its visible
|
||||
self.currentTexture.set_opacity(255)
|
||||
|
||||
|
||||
#Get a random song (if there's songs available)
|
||||
if not len(self.music) == 0:
|
||||
self.rand1 = random.randint(0, len(self.music)-1)
|
||||
self.currentSong = self.music[self.rand1]
|
||||
self.playNextSong(None)
|
||||
|
||||
#Housekeeping
|
||||
self.image_texture_group.hide_all()
|
||||
self.nextTexture = None
|
||||
self.nextSong = None
|
||||
|
||||
#Begin the show
|
||||
self.currentTexture.show()
|
||||
self.image_texture_group.show()
|
||||
self.nextImage(self.currentTexture)
|
||||
|
||||
def end(self):
|
||||
pass
|
||||
|
||||
|
||||
def nextImage(self, currentTexture):
|
||||
#Setup stuff for KEN BURNS EFFECT!!
|
||||
self.timeline_main = clutter.Timeline((self.effect_FPS * self.imageDuration), self.effect_FPS)
|
||||
self.timeline_main.connect('completed', self.image_timeline_end_event)
|
||||
self.alpha = clutter.Alpha(self.timeline_main, clutter.ramp_inc_func)
|
||||
|
||||
#Decide on the next texture to use
|
||||
self.nextTexture = None
|
||||
while (self.nextTexture == None):
|
||||
self.rand1 = random.randint(0, len(self.textures)-1 )
|
||||
self.nextTexture = self.image_texture_group.get_nth_child(self.rand1)
|
||||
#Make sure we don't show the same photo twice
|
||||
if (self.nextTexture == self.currentTexture) and (len(self.textures) > 1):
|
||||
self.nextTexture = None
|
||||
#Make sure its not visible initially (Prevents a nasty flicker the first time a photo is shown)
|
||||
self.nextTexture.set_opacity(0)
|
||||
|
||||
#Zooming stuff
|
||||
rand_zoom = random.uniform(1,1.3) # Zoom somewhere between 1 and 1.3 times
|
||||
self.behaviour1 = clutter.BehaviourScale(self.alpha, 1, rand_zoom, clutter.GRAVITY_CENTER)
|
||||
|
||||
#panning stuff
|
||||
x_pos = self.currentTexture.get_x() + random.randint(-100, 100)
|
||||
y_pos = self.currentTexture.get_y() + random.randint(-100, 100)
|
||||
self.alpha = clutter.Alpha(self.timeline_main, clutter.ramp_inc_func)
|
||||
|
||||
knots = (\
|
||||
(self.currentTexture.get_x(), self.currentTexture.get_y()),\
|
||||
(x_pos, y_pos)\
|
||||
)
|
||||
self.behaviour2 = clutter.BehaviourPath(self.alpha, knots)
|
||||
|
||||
|
||||
#Start and run the Ken Burns effect
|
||||
self.behaviour1.apply(self.currentTexture)
|
||||
self.behaviour2.apply(self.currentTexture)
|
||||
self.timeline_main.start()
|
||||
|
||||
|
||||
def image_timeline_end_event(self, data):
|
||||
#Add the timeline for the dissolve at the end
|
||||
self.timeline_dissolve = clutter.Timeline(30,30)
|
||||
self.alpha_dissolve = clutter.Alpha(self.timeline_dissolve, clutter.ramp_inc_func)
|
||||
|
||||
#Setup the dissolve to the next image
|
||||
self.behaviour3 = clutter.BehaviourOpacity(self.alpha_dissolve, 255, 0)
|
||||
self.behaviour4 = clutter.BehaviourOpacity(self.alpha_dissolve, 0, 255)
|
||||
|
||||
self.behaviour3.apply(self.currentTexture)
|
||||
self.behaviour4.apply(self.nextTexture)
|
||||
|
||||
#Pick a random spot for the next image
|
||||
x_pos = random.randint(0, abs(self.stage.get_width() - self.nextTexture.get_width()) ) #Somewhere between 0 and (stage_width-image_width)
|
||||
y_pos = random.randint(0, abs(self.stage.get_height() - self.nextTexture.get_height()) )
|
||||
self.nextTexture.set_position(x_pos, y_pos)
|
||||
|
||||
self.currentTexture = self.nextTexture
|
||||
self.nextTexture.show()
|
||||
self.timeline_dissolve.start()
|
||||
self.nextImage(self.currentTexture)
|
||||
|
||||
#Begins playing a new song
|
||||
def playNextSong(self, data):
|
||||
self.nextSong = None
|
||||
#Check first that there actually is music
|
||||
if len(self.music) == 0:
|
||||
return None
|
||||
|
||||
#Decide on the next song to play
|
||||
while self.nextSong == None:
|
||||
self.rand1 = random.randint(0, len(self.music)-1)
|
||||
self.nextSong = self.music[self.rand1]
|
||||
#Make sure we don't play the same song twice
|
||||
if (self.nextSong == self.currentSong) and (len(self.music) > 1):
|
||||
self.nextSong = None
|
||||
|
||||
self.currentSong = self.nextSong
|
||||
self.currentSong.set_playing(True)
|
||||
self.currentSong.connect('eos', self.playNextSong)
|
||||
|
||||
def pause(self):
|
||||
self.paused = True
|
||||
|
||||
#Use the overlay to go over show
|
||||
self.overlay.set_color(clutter.color_parse('Black'))
|
||||
self.overlay.set_width(self.stage.get_width())
|
||||
self.overlay.set_height(self.stage.get_height())
|
||||
self.overlay.set_opacity(0)
|
||||
self.overlay.show()
|
||||
#self.overlay.raise_top()
|
||||
#self.image_texture_group.lower(self.overlay)
|
||||
self.stage.add(self.overlay)
|
||||
#Fade the backdrop in
|
||||
timeline_overlay = clutter.Timeline(10,30)
|
||||
alpha = clutter.Alpha(timeline_overlay, clutter.ramp_inc_func)
|
||||
overlay_behaviour = clutter.BehaviourOpacity(alpha, 0, 100)
|
||||
overlay_behaviour2 = clutter.BehaviourOpacity(alpha, 255, 100) #Used on the backdrop
|
||||
overlay_behaviour3 = clutter.BehaviourOpacity(alpha, 255, 0) #Used on the current texture
|
||||
overlay_behaviour.apply(self.overlay)
|
||||
overlay_behaviour2.apply(self.backdrop)
|
||||
overlay_behaviour3.apply(self.currentTexture)
|
||||
timeline_overlay.start()
|
||||
|
||||
#Pause the main slideshow
|
||||
self.timeline_main.pause()
|
||||
|
||||
#Pause any music
|
||||
if not self.currentSong == None:
|
||||
if self.currentSong.get_playing():
|
||||
self.currentSong.set_playing(False)
|
||||
|
||||
def unpause(self):
|
||||
self.paused = False
|
||||
|
||||
#Fade the backdrop in
|
||||
timeline_overlay = clutter.Timeline(10,30)
|
||||
alpha = clutter.Alpha(timeline_overlay, clutter.ramp_inc_func)
|
||||
overlay_behaviour = clutter.BehaviourOpacity(alpha, 100, 0)
|
||||
overlay_behaviour2 = clutter.BehaviourOpacity(alpha, 100, 255) #Used on the backdrop
|
||||
overlay_behaviour3 = clutter.BehaviourOpacity(alpha, 0, 255) #Used on the current texture
|
||||
overlay_behaviour.apply(self.overlay)
|
||||
overlay_behaviour2.apply(self.backdrop)
|
||||
overlay_behaviour3.apply(self.currentTexture)
|
||||
timeline_overlay.start()
|
||||
|
||||
#Resume the main slideshow
|
||||
self.timeline_main.start()
|
||||
|
||||
#Resume any music
|
||||
if not self.currentSong == None:
|
||||
self.currentSong.set_playing(True)
|
||||
|
||||
def stop(self):
|
||||
#Stop any running timelines
|
||||
self.timeline_main.stop()
|
||||
|
||||
#Fade everything out
|
||||
timeline_stop = clutter.Timeline(10,30)
|
||||
alpha = clutter.Alpha(timeline_stop, clutter.ramp_inc_func)
|
||||
stop_behaviour = clutter.BehaviourOpacity(alpha, 255, 0)
|
||||
stop_behaviour.apply(self.image_texture_group)
|
||||
stop_behaviour.apply(self.backdrop)
|
||||
stop_behaviour.apply(self.overlay)
|
||||
timeline_stop.connect('completed', self.destroySlideshow)
|
||||
timeline_stop.start()
|
||||
|
||||
#Stop any music
|
||||
if not self.currentSong == None:
|
||||
if self.currentSong.get_playing():
|
||||
self.currentSong.set_playing(False)
|
||||
self.currentSong.set_position(0)
|
||||
|
||||
|
||||
def destroySlideshow(self, data):
|
||||
self.stage.remove(self.image_texture_group)
|
||||
self.backdrop.hide()
|
||||
#self.stage.remove(self.overlay)
|
||||
|
||||
self.currentTexture = None
|
||||
self.nextTexture = None
|
||||
self.currentSong = None
|
||||
self.nexttSong = None
|
||||
|
||||
#The following generates a menu with an option for each of the slideshows in the base menu
|
||||
def generateMenu(self):
|
||||
|
||||
tempMenu = Menu(self.MenuMgr)
|
||||
print self.baseDir
|
||||
file_list = os.listdir(self.baseDir)
|
||||
|
||||
for directoryEntry in file_list:
|
||||
subdir = self.baseDir + "/" + directoryEntry
|
||||
if os.path.isdir(subdir):
|
||||
imgPath = subdir + "/" + os.listdir(subdir)[0]
|
||||
print imgPath
|
||||
tempItem = tempMenu.addItem(directoryEntry, "/home/josh/.mythtv/MythVideo/0088763.jpg")
|
||||
tempItem.setAction(self)
|
||||
|
||||
|
||||
return tempMenu
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import clutter
|
||||
import gtk
|
||||
|
||||
class Spinner (clutter.Texture):
|
||||
|
||||
def __init__(self):
|
||||
clutter.Texture.__init__ (self)
|
||||
|
||||
#self.texture = clutter.Texture()
|
||||
pixbuf = gtk.gdk.pixbuf_new_from_file("ui/spinner.svg")
|
||||
self.set_pixbuf(pixbuf)
|
||||
|
||||
timeline = clutter.Timeline(40,20)
|
||||
timeline.set_loop(True)
|
||||
alpha = clutter.Alpha(timeline, clutter.ramp_inc_func)
|
||||
spin_behaviour = clutter.BehaviourRotate(alpha, clutter.Z_AXIS, clutter.ROTATE_CW, 0, 359)
|
||||
spin_behaviour.set_center(self.get_width()/2,self.get_height()/2, 0)
|
||||
spin_behaviour.apply(self)
|
||||
|
||||
timeline.start()
|
|
@ -0,0 +1,46 @@
|
|||
from clutter import cluttergst
|
||||
from myth.MythMySQL import mythVideoDB
|
||||
from myth.MythBackendConn import MythBackendConnection
|
||||
|
||||
class TVPlayer:
|
||||
|
||||
def __init__(self, stage):
|
||||
self.video = cluttergst.VideoTexture()
|
||||
self.stage = stage
|
||||
#audio.set_filename('cast1.avi')
|
||||
#audio.show()
|
||||
|
||||
#test = cluttercairo.Cairo()
|
||||
#audio = cluttergst.Audio()
|
||||
#audio.set_filename('test.mp3')
|
||||
|
||||
#stage.add(audio)
|
||||
#audio.set_playing(True)
|
||||
|
||||
#self.db_conn = mythVideoDB()
|
||||
|
||||
def begin(self, menuMgr):
|
||||
self.myConn = MythBackendConnection(self)
|
||||
self.myConn.start()
|
||||
#self.begin_playback()
|
||||
|
||||
|
||||
def begin_playback(self, fd):
|
||||
#self.video.set_filename("test.mpg")
|
||||
print "File Descriptor: " + str(fd)
|
||||
self.video.set_uri("fd://"+str(fd))
|
||||
self.video.show()
|
||||
|
||||
self.stage.add(self.video)
|
||||
self.video.set_playing(True)
|
||||
|
||||
def on_key_press_event (self, stage, event):
|
||||
#print event.hardware_keycode
|
||||
pass
|
||||
"""if event.keyval == clutter.keysyms.p:
|
||||
if self.paused:
|
||||
self.unpause()
|
||||
else:
|
||||
self.pause()
|
||||
if event.keyval == clutter.keysyms.q:
|
||||
clutter.main_quit()"""
|
|
@ -0,0 +1,139 @@
|
|||
import pygtk
|
||||
import gtk
|
||||
import clutter
|
||||
from myth.MythMySQL import mythVideoDB
|
||||
|
||||
class VideoPlayer():
|
||||
|
||||
def __init__(self, stage):
|
||||
self.stage = stage
|
||||
self.cover_viewer = coverViewer(self.stage)
|
||||
self.videoLibrary = []
|
||||
|
||||
self.is_playing = False
|
||||
|
||||
#This block can be moved to begin() but causes a performance hit when loading the module *shrug*
|
||||
dbMgr = mythVideoDB()
|
||||
results = dbMgr.get_videos()
|
||||
|
||||
for record in results:
|
||||
tempVideo = videoItem()
|
||||
tempVideo.importFromMythObject(record)
|
||||
self.videoLibrary.append(tempVideo)
|
||||
self.cover_viewer.add_image(tempVideo.getCoverfile())
|
||||
################################################################################
|
||||
|
||||
def on_key_press_event (self, stage, event):
|
||||
if event.keyval == clutter.keysyms.p:
|
||||
if self.paused:
|
||||
self.unpause()
|
||||
else:
|
||||
self.pause()
|
||||
if event.keyval == clutter.keysyms.q:
|
||||
clutter.main_quit()
|
||||
|
||||
def begin(self, MenuMgr):
|
||||
|
||||
#Create a backdrop for the player. In this case we just use the same background as the menus
|
||||
self.backdrop = clutter.CloneTexture(MenuMgr.get_skinMgr().get_Background())
|
||||
self.backdrop.set_size(self.stage.get_width(), self.stage.get_height())
|
||||
self.backdrop.set_opacity(0)
|
||||
self.backdrop.show()
|
||||
self.stage.add(self.backdrop)
|
||||
#Fade the backdrop in
|
||||
timeline_begin = clutter.Timeline(10,40)
|
||||
alpha = clutter.Alpha(timeline_begin, clutter.ramp_inc_func)
|
||||
begin_behaviour = clutter.BehaviourOpacity(alpha, 0, 255)
|
||||
begin_behaviour.apply(self.backdrop)
|
||||
|
||||
self.cover_viewer.set_opacity(0)
|
||||
self.cover_viewer.show_all()
|
||||
self.cover_viewer.show()
|
||||
self.stage.add(self.cover_viewer)
|
||||
begin_behaviour.apply(self.cover_viewer)
|
||||
|
||||
timeline_begin.start()
|
||||
|
||||
|
||||
def stop(self):
|
||||
pass
|
||||
|
||||
def pause(self):
|
||||
pass
|
||||
|
||||
def unpause(self):
|
||||
pass
|
||||
|
||||
class videoItem():
|
||||
def __init(self):
|
||||
self.mythID = None
|
||||
|
||||
def importFromMythObject(self, mythObject):
|
||||
self.mythID = mythObject[0]
|
||||
self.title = mythObject[1]
|
||||
self.director = mythObject[2]
|
||||
self.plot = mythObject[3]
|
||||
self.rating = mythObject[4]
|
||||
self.inetRef = mythObject[5]
|
||||
self.year = mythObject[6]
|
||||
self.userRating = mythObject[7]
|
||||
self.length = mythObject[8]
|
||||
self.showLevel = mythObject[9]
|
||||
self.filename = mythObject[10]
|
||||
self.coverfile = mythObject[11]
|
||||
self.childID = mythObject[12]
|
||||
self.browse = mythObject[13]
|
||||
self.playCommand = mythObject[14]
|
||||
self.category = mythObject[15]
|
||||
|
||||
def getTitle(self):
|
||||
return self.title
|
||||
def getCoverfile(self):
|
||||
return self.coverfile
|
||||
|
||||
class coverViewer(clutter.Group):
|
||||
|
||||
def __init__(self, stage):
|
||||
clutter.Group.__init__(self)
|
||||
self.stage = stage
|
||||
self.covers = []
|
||||
self.num_covers = 0
|
||||
self.cover_size = 200 #A cover will be cover_size * cover_size (X * Y)
|
||||
self.cover_gap = 10
|
||||
|
||||
self.num_rows = 2
|
||||
self.num_columns = int(self.stage.get_width() / self.cover_size)
|
||||
|
||||
def add_image(self, imagePath):
|
||||
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_position( (self.num_covers * self.cover_size), 0)
|
||||
|
||||
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)
|
||||
tempTexture.set_position(x, y)
|
||||
|
||||
self.add(tempTexture)
|
||||
self.num_covers = self.num_covers +1
|
||||
|
||||
|
||||
|
||||
#Redo positioning on all textures to add new one :(
|
||||
"""for i in range(self.num_covers):
|
||||
tempTexture = self.get_nth_child(i)
|
||||
x = (self.cover_gap + self.cover_size) * i
|
||||
y = (i % self.num_rows) * self.cover_size
|
||||
tempTexture.set_position(x, y)"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import sys
|
||||
import clutter
|
||||
#import gobject
|
||||
import pygtk
|
||||
import gtk
|
||||
from Menu import Menu
|
||||
from MenuMgr import MenuMgr
|
||||
from Slideshow import Slideshow
|
||||
from VideoPlayer import VideoPlayer
|
||||
from MusicPlayer import MusicPlayer
|
||||
from TVPlayer import TVPlayer
|
||||
|
||||
|
||||
class MainApp:
|
||||
def __init__ (self):
|
||||
gtk.gdk.threads_init()
|
||||
|
||||
self.stage = clutter.stage_get_default()
|
||||
self.stage.set_color(clutter.color_parse('Black'))
|
||||
#self.stage.set_size(800, 600)
|
||||
self.stage.set_property("fullscreen", True)
|
||||
self.stage.connect('button-press-event', self.on_button_press_event)
|
||||
self.stage.show_all()
|
||||
|
||||
|
||||
#color = clutter.Color(0xff, 0xcc, 0xcc, 0xdd)
|
||||
color = clutter.Color(0, 0, 0, 0)
|
||||
|
||||
self.menuMgr = MenuMgr(self.stage)
|
||||
self.stage.connect('key-press-event', self.menuMgr.on_key_press_event)
|
||||
|
||||
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("nothing", "ui/music.png")
|
||||
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.menu1.selectFirst(True)
|
||||
|
||||
|
||||
self.menu1.getItemGroup().show_all()
|
||||
|
||||
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")
|
||||
|
||||
self.mySlideshow = Slideshow(self.menuMgr, "/mythdata/pics")
|
||||
#self.mySlideshow.loadDir("images/", True)
|
||||
|
||||
self.vidPlayer = VideoPlayer(self.stage)
|
||||
self.tvPlayer = TVPlayer(self.stage)
|
||||
self.musicPlayer = 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)
|
||||
|
||||
self.menu2.getItem(1).setAction(self.menu1)
|
||||
|
||||
|
||||
|
||||
def on_button_press_event (self, stage, event):
|
||||
print "mouse button %d pressed at (%d, %d)" % \
|
||||
(event.button, event.x, event.y)
|
||||
if event.button == 1:
|
||||
pass
|
||||
|
||||
|
||||
def run (self):
|
||||
self.stage.show()
|
||||
#self.timeline.start()
|
||||
clutter.main()
|
||||
|
||||
def main (args):
|
||||
app = MainApp()
|
||||
app.run()
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 382 KiB |
After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 166 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 103 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 74 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 100 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 37 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 84 KiB |
|
@ -0,0 +1,24 @@
|
|||
#python
|
||||
[execution]
|
||||
# project_file_to_execute
|
||||
# The python file to run for this project
|
||||
# default value =
|
||||
project_file_to_execute = myPyToy.py
|
||||
|
||||
# use_python_to_execute
|
||||
# None
|
||||
# default value = True
|
||||
use_python_to_execute = True
|
||||
|
||||
|
||||
[general]
|
||||
# python_binary_location
|
||||
# The location of the python binary
|
||||
# default value = /usr/bin/python
|
||||
python_binary_location = /usr/bin/python
|
||||
|
||||
# source_directory
|
||||
# The directory containing source code.
|
||||
# default value = /home/josh
|
||||
source_directory = /home/josh/clutter/toys/myPyToy
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
import socket
|
||||
import time
|
||||
import threading
|
||||
|
||||
class MythBackendConnection(threading.Thread):
|
||||
|
||||
def __init__(self, videoPlayer):
|
||||
self.protocolVersion = 31
|
||||
self.localhost_name = "myhost" # Change this later
|
||||
self.server = "192.168.0.8"
|
||||
self.server_port = 6543
|
||||
self.videoPlayer = videoPlayer
|
||||
|
||||
#2 Sockets, 1 for cmds, 1 for data
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.data_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
||||
#self.sock.connect( ("192.168.0.8", 6543) )
|
||||
self.connected = False
|
||||
self.recorder = None # Mythtv recorder
|
||||
self.connect(self.server, self.server_port)
|
||||
|
||||
threading.Thread.__init__(self)
|
||||
|
||||
#def start(self):
|
||||
# threading.Thread.start(self)
|
||||
|
||||
|
||||
def run(self):
|
||||
print "Starting thread"
|
||||
self.setup_recorder()
|
||||
self.spawn_live()
|
||||
#self.disconnect()
|
||||
|
||||
def receive_reply(self, sock):
|
||||
ret = ""
|
||||
tmp = sock.recv(8)
|
||||
count = int(tmp)
|
||||
#debug("REPLY LEN: %d" % count)
|
||||
ret = sock.recv(count)
|
||||
|
||||
#print "read<--" + ret
|
||||
return ret
|
||||
|
||||
def send_cmd(self, sock, base_cmd):
|
||||
cmd = str(len(base_cmd)).ljust(8) + base_cmd
|
||||
sock.send(cmd)
|
||||
#print "write-->" + cmd
|
||||
|
||||
def connect(self, host, port):
|
||||
self.sock.connect((host, port))
|
||||
|
||||
#Do the protocol version check
|
||||
protString = "MYTH_PROTO_VERSION "+ str(self.protocolVersion)
|
||||
self.send_cmd(self.sock, protString)
|
||||
protRecvString = "ACCEPT[]:[]" + str(self.protocolVersion)
|
||||
result = self.receive_reply(self.sock)
|
||||
print result
|
||||
if not result == protRecvString:
|
||||
#Protocol Version check failed
|
||||
raise RuntimeError, "Myth Protocol version failure. Aborting."
|
||||
|
||||
#Perform the mandatory ANN
|
||||
ANNstring = "ANN Playback " + self.localhost_name + " 0"
|
||||
self.send_cmd(self.sock, ANNstring)
|
||||
ANN_recv_string = "OK" #What a successful return should be
|
||||
result = self.receive_reply(self.sock)
|
||||
if not result == ANN_recv_string:
|
||||
raise RuntimeError, "Myth: ANN connection failed"
|
||||
|
||||
#All looks good
|
||||
self.connected = True
|
||||
|
||||
def disconnect(self):
|
||||
self.sock.close()
|
||||
|
||||
def setup_recorder(self):
|
||||
if not self.connected:
|
||||
print "Cannot get recorder, no server connection exists"
|
||||
return None
|
||||
|
||||
recorder_request_string = "GET_NEXT_FREE_RECORDER[]:[]-1"
|
||||
self.send_cmd(self.sock, recorder_request_string)
|
||||
result = self.receive_reply(self.sock)
|
||||
result_list = result.rsplit("[]:[]")
|
||||
if not result_list[0] == -1:
|
||||
#Then everything worked fine
|
||||
self.recorder = result_list[0]
|
||||
else:
|
||||
print "Myth: No recorders available"
|
||||
|
||||
def spawn_live(self):
|
||||
if self.recorder == None:
|
||||
print "Myth: Cannot spawn live tv, no recorder available"
|
||||
|
||||
chainID = "live-" + self.localhost_name + "-2007-08-03T21:54:21"#+str(time.clock())
|
||||
spawn_string = "QUERY_RECORDER "+str(self.recorder)+"[]:[]SPAWN_LIVETV[]:[]"+chainID +"[]:[]0"
|
||||
self.send_cmd(self.sock, spawn_string)
|
||||
spawn_receive_string = "ok"
|
||||
result = self.receive_reply(self.sock)
|
||||
if not result == spawn_receive_string:
|
||||
print "Myth: failed to spawn live tv. Result: "+str(result)
|
||||
|
||||
#Check the recording
|
||||
check_string = "QUERY_RECORDER "+str(self.recorder)+"[]:[]IS_RECORDING"
|
||||
self.send_cmd(self.sock, check_string)
|
||||
is_recording = self.receive_reply(self.sock)
|
||||
if not is_recording == str(1):
|
||||
#Just send the check again
|
||||
self.send_cmd(self.sock, check_string)
|
||||
|
||||
#Create a new data socket
|
||||
self.data_sock.connect( (self.server, self.server_port) )
|
||||
protString = "MYTH_PROTO_VERSION "+ str(self.protocolVersion)
|
||||
self.send_cmd(self.data_sock, protString)
|
||||
protRecvString = "ACCEPT[]:[]" + str(self.protocolVersion)
|
||||
result = self.receive_reply(self.data_sock)
|
||||
|
||||
#This is just a hack to make sure the channel has locked, I'll fix it later
|
||||
time.sleep(5)
|
||||
|
||||
#Get the recording filename
|
||||
filename_string = "QUERY_RECORDER "+str(self.recorder)+"[]:[]GET_CURRENT_RECORDING"
|
||||
self.send_cmd(self.sock, filename_string)
|
||||
filedetails = self.receive_reply(self.sock)
|
||||
detail_list = filedetails.rsplit("[]:[]")
|
||||
filename_list = detail_list[8].rsplit("/")
|
||||
filename_list.reverse()
|
||||
filename = "/" + filename_list[0]
|
||||
print filename
|
||||
|
||||
#Announce our intent to read a file
|
||||
announce_cmd = "ANN FileTransfer " + self.localhost_name + "[]:[]" + filename
|
||||
self.send_cmd(self.data_sock, announce_cmd)
|
||||
result = self.receive_reply(self.data_sock)
|
||||
result_list = result.rsplit("[]:[]")
|
||||
data_socket_id = result_list[1]
|
||||
print "Socket ID: " + str(data_socket_id)
|
||||
|
||||
#Do some housekeeping
|
||||
frontend_ready_cmd = "QUERY_RECORDER "+str(self.recorder) +"[]:[]FRONTEND_READY"
|
||||
self.send_cmd(self.sock, frontend_ready_cmd)
|
||||
result = self.receive_reply(self.sock)
|
||||
input_cmd = "QUERY_RECORDER "+ str(self.recorder) +"[]:[]GET_INPUT"
|
||||
self.send_cmd(self.sock, input_cmd)
|
||||
result = self.receive_reply(self.sock)
|
||||
rec_list_cmd = "MESSAGE[]:[]RECORDING_LIST_CHANGE"
|
||||
self.send_cmd(self.sock, rec_list_cmd)
|
||||
result = self.receive_reply(self.sock)
|
||||
|
||||
#Start a recording thread
|
||||
self.buffer_live(self.sock, self.data_sock, data_socket_id)
|
||||
|
||||
def buffer_live(self, cmd_sock, data_sock, socket_id):
|
||||
#Create a buffer file
|
||||
self.buffer_file = open("test.mpg","w")
|
||||
|
||||
print "grunt0"
|
||||
#read some data
|
||||
x=0
|
||||
request_size = 32768
|
||||
|
||||
#Need to create a bit of a buffer so playback will begin
|
||||
while x<80:
|
||||
transfer_cmd = "QUERY_FILETRANSFER "+ str(socket_id) + "[]:[]REQUEST_BLOCK[]:[]"+str(request_size)
|
||||
self.send_cmd(cmd_sock, transfer_cmd)
|
||||
num_bytes = int(self.receive_reply(cmd_sock))
|
||||
data = data_sock.recv(num_bytes)
|
||||
self.buffer_file.write(data)
|
||||
self.buffer_file.flush()
|
||||
x=x+1
|
||||
|
||||
#data_sock.flush()
|
||||
tempfile = data_sock.makefile("r", request_size)
|
||||
tempfile.flush()
|
||||
self.videoPlayer.begin_playback(tempfile.fileno())
|
||||
print "BEGINNING PLAYBACK!"
|
||||
while x<1000:
|
||||
transfer_cmd = "QUERY_FILETRANSFER "+ str(socket_id) + "[]:[]REQUEST_BLOCK[]:[]"+str(request_size)
|
||||
self.send_cmd(cmd_sock, transfer_cmd)
|
||||
num_bytes = int(self.receive_reply(cmd_sock))
|
||||
data_sock.recv(num_bytes)
|
||||
#self.buffer_file.write(data)
|
||||
#self.buffer_file.flush()
|
||||
x=x+1
|
||||
|
||||
print "Ending playback"
|
||||
self.buffer_file.close()
|
||||
|
||||
def end_stream(self):
|
||||
self.stream = False
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import MySQLdb
|
||||
|
||||
class mythVideoDB():
|
||||
|
||||
def __init__(self):
|
||||
self.server = "127.0.0.1" #"192.168.0.1"
|
||||
self.db = "mythconverg"
|
||||
self.uid = "root"
|
||||
self.passwd = ""
|
||||
|
||||
db = MySQLdb.connect(self.server, self.uid, self.passwd,self.db)
|
||||
|
||||
self.cursor = db.cursor()
|
||||
#cursor.execute("SELECT * FROM videometadatagenre")
|
||||
# get the resultset as a tuple
|
||||
#result = cursor.fetchall()
|
||||
# iterate through resultset
|
||||
#for record in result:
|
||||
#print record[0] , "-->", record[1]
|
||||
|
||||
def get_videos(self):
|
||||
sql = "SELECT * FROM videometadata WHERE coverfile <> 'No Cover'"
|
||||
|
||||
self.cursor.execute(sql)
|
||||
# get the resultset as a tuple
|
||||
result = self.cursor.fetchall()
|
||||
|
||||
return result
|
After Width: | Height: | Size: 3.9 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 150 KiB |
After Width: | Height: | Size: 147 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 71 KiB |
|
@ -0,0 +1,179 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://web.resource.org/cc/"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="100"
|
||||
height="100"
|
||||
id="svg2263"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.45"
|
||||
version="1.0"
|
||||
sodipodi:docbase="/home/njp/o-hand/svn/clutter/trunk/toys/fluttr/data"
|
||||
sodipodi:docname="spinner.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"
|
||||
sodipodi:modified="true">
|
||||
<defs
|
||||
id="defs2265">
|
||||
<linearGradient
|
||||
id="linearGradient3302">
|
||||
<stop
|
||||
style="stop-color:#dadada;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3304" />
|
||||
<stop
|
||||
id="stop3327"
|
||||
offset="0.73949581"
|
||||
style="stop-color:#d2d2d2;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0.86974788"
|
||||
id="stop3333" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3306" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3289">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3291" />
|
||||
<stop
|
||||
style="stop-color:#474747;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3293" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3275">
|
||||
<stop
|
||||
id="stop3277"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop3279"
|
||||
offset="1"
|
||||
style="stop-color:#cfcfcf;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient3133">
|
||||
<stop
|
||||
style="stop-color:#1f2221;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3135" />
|
||||
<stop
|
||||
style="stop-color:#000000;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3137" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3133"
|
||||
id="linearGradient3139"
|
||||
x1="462.85715"
|
||||
y1="0"
|
||||
x2="462.85715"
|
||||
y2="600.20575"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="scale(1,0.7333333)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3275"
|
||||
id="linearGradient3273"
|
||||
x1="478.57144"
|
||||
y1="91.428574"
|
||||
x2="478.57144"
|
||||
y2="345.06439"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3133"
|
||||
id="linearGradient3283"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
x1="478.57144"
|
||||
y1="91.428574"
|
||||
x2="478.57144"
|
||||
y2="345.06439"
|
||||
gradientTransform="matrix(0.9328572,0,0,0.8971429,26.857143,22.628568)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3289"
|
||||
id="linearGradient3287"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.9328572,0,0,0.3085715,26.857139,78.54285)"
|
||||
x1="478.57144"
|
||||
y1="91.428574"
|
||||
x2="478.57144"
|
||||
y2="345.06439" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3302"
|
||||
id="radialGradient3316"
|
||||
cx="200"
|
||||
cy="125"
|
||||
fx="200"
|
||||
fy="125"
|
||||
r="50"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1,0,0,-1,0,250)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3302"
|
||||
id="radialGradient3331"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.662898,0.7231039,-0.7293767,0.6686485,194.30678,-79.630422)"
|
||||
cx="200"
|
||||
cy="125"
|
||||
fx="200"
|
||||
fy="125"
|
||||
r="50" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#363636"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
gridtolerance="10000"
|
||||
guidetolerance="10"
|
||||
objecttolerance="10"
|
||||
inkscape:pageopacity="0.75686275"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.4"
|
||||
inkscape:cx="152.97332"
|
||||
inkscape:cy="93.594381"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer4"
|
||||
width="800px"
|
||||
height="440px"
|
||||
inkscape:window-width="910"
|
||||
inkscape:window-height="624"
|
||||
inkscape:window-x="4"
|
||||
inkscape:window-y="47" />
|
||||
<metadata
|
||||
id="metadata2268">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
transform="translate(-150,-75)">
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:6;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 200,77.857143 C 173.88286,77.857143 152.85714,98.882857 152.85714,125 C 152.85714,151.11714 173.88286,172.14286 200,172.14286 C 226.11714,172.14286 247.14286,151.11714 247.14286,125 C 247.14286,98.882857 226.11714,77.857143 200,77.857143 z M 192.60446,93.532143 L 192.60446,114.275 L 207.39554,114.275 L 207.39554,93.532143 C 221.71682,96.858206 232.32232,109.63693 232.32232,125 C 232.32232,142.9089 217.9089,157.32232 200,157.32232 C 182.0911,157.32233 167.67768,142.9089 167.67768,125 C 167.67768,109.63693 178.28317,96.858206 192.60446,93.532143 z "
|
||||
id="rect3295" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 71 KiB |