import pygame
import cPickle
import os, os.path, re, math
from keyfile import *
from fx import *
import event
fileroot = "songs"
songcache = 'songcache.pickle'
possave = 0
def mksongcache():
songs = FileNode()
songs.crawl(fileroot)
f = open(songcache,'w')
cPickle.dump(songs,f)
f.close()
return songs
filetile = pygame.image.load("gfx/filetile.png")
class SelectWidget(FX):
color = (240,240,255)
basecolor = (200,0,0)
fadetime = 700
size = (400,30)
OFF = 0
ON = 1
FADING = 2
def __init__(self,text,location=(0,0)):
FX.__init__(self)
f = pygame.font.Font('font/Nano.ttf',16)
self.text = f.render(text,True,self.color)
self.surface = pygame.Surface(self.size).convert_alpha()
self.surface.fill( (0,0,0,0) )
self.surface.blit(filetile,(0,0))
self.surface.blit(self.text, (9,7))
self.pointlist = [(10,0),(self.size[0]-2,0),(self.size[0]-2,self.size[1]-2),(0,self.size[1]-2),(0,10)]
self.state = self.OFF
self.location = location
def off(self):
if self.state == self.ON:
self.state = self.FADING
self.fade_t = pygame.time.get_ticks()
def on(self):
self.state = self.ON
def draw(self,t):
self.screen.blit(self.surface,self.location)
color = self.basecolor
if self.state == self.ON:
color = self.color
if self.state == self.FADING:
dt = pygame.time.get_ticks() - self.fade_t
if dt < self.fadetime:
alpha = math.exp(-0.003*dt)
color = [(1.0-alpha) * self.basecolor[n] + alpha * self.color[n] for n in range(0,3)]
else:
self.state = self.OFF
pointlist = [(x[0] + self.location[0],x[1] + self.location[1]) for x in self.pointlist]
pygame.draw.lines(self.screen,color,True,pointlist,2)
def WTFsort(a,b):
if a.type == a.DIRECTORY and b.type == b.DIRECTORY:
if a.name > b.name:
return 1
elif a.name < b.name:
return -1
else:
return 0
elif a.type == a.DIRECTORY and b.type == b.FILE:
return 1
elif a.type == a.FILE and b.type == b.DIRECTORY:
return -1
else:
if a.info['player'] > b.info['player']:
return 1
elif a.info['player'] < b.info['player']:
return -1
else:
if not 'playlevel' in a.info:
return -1
if not 'playlevel' in b.info:
return 1
if a.info['playlevel'] > b.info['playlevel']:
return 1
elif a.info['playlevel'] < b.info['playlevel']:
return -1
else:
if not 'total' in a.info:
return -1
if not 'total' in b.info:
return 1
if a.info['total'] > b.info['total']:
return 1
elif a.info['total'] < b.info['total']:
return -1
else:
return 0
filematch = re.compile('\.(bms|bme|sm)$',re.I)
class FileNode:
DIRECTORY = 0
FILE = 1
def __init__(self):
self.children = []
self.open = False
self.info = None
self.widget = None
def crawl(self,path):
print "Crawling " + path
self.path = path
if os.path.isdir(path):
self.type = self.DIRECTORY
self.name = os.path.basename(path)
files = filter(lambda x: os.path.isdir(os.path.join(path,x)) or filematch.search(x), os.listdir(path))
for f in files:
c = FileNode()
if c.crawl(os.path.join(path,f)):
self.children.append(c)
self.children.sort(WTFsort)
elif os.path.isfile(path):
self.type = self.FILE
self.info = kf_info(path)
self.name = self.info['title']
else:
print path + " isn't a file or a directory. Ignoring."
return False
return True
def update(self):
for c in self.children:
if not os.path.exists(c.path):
self.children.remove(c)
else:
c.update()
def add(self,child):
self.children.append(child)
def tolist(self,depth=0):
self.depth = depth
l = [self]
if self.open:
for c in self.children:
r = c.tolist(depth+1)
for i in r:
l.append(i)
return l
def getwidget(self):
if not self.widget:
self.widget = SelectWidget(self.name)
return self.widget
def nukewidgets(self):
self.widget = None
for c in self.children:
c.nukewidgets()
class FileSelect:
def __init__(self):
self.screen = pygame.display.get_surface()
try:
f = open(songcache,'r')
self.songs = cPickle.load(f)
f.close()
except IOError:
self.songs = mksongcache()
except cPickle.UnpicklingError:
self.songs = mksongcache()
self.period = 428
self.songlist = self.songs.tolist()
try:
self.position = self.songlist.index(self.songs.current)
except AttributeError:
self.position = 0
except ValueError:
self.position = 0
self.fslabel = Text('file select','font/Nano.ttf',30,(330,30),(255,0,0))
self.fadebottom = pygame.Surface((640,200)).convert_alpha()
for n in range(0,200):
alpha = int((1.0 - math.exp(-n/30.0)) * 255.0)
color = (0,0,0,alpha)
pygame.draw.line(self.fadebottom,color,(0,n),(640,n))
self.labels = {}
self.olabels = {}
self.olabels['title'] = Text('title','font/Nano.ttf',12, (20,320),(255,130,130))
self.labels['title'] = Text('','font/Nano.ttf',18, (30,330),(230,230,255))
self.olabels['artist'] = Text('artist','font/Nano.ttf',12, (20,360),(255,130,130))
self.labels['artist'] = Text('','font/Nano.ttf',16, (30,370),(230,230,255))
self.olabels['genre'] = Text('genre','font/Nano.ttf',12, (20,390),(255,130,130))
self.labels['genre'] = Text('','font/Nano.ttf',16, (30,400),(230,230,255))
self.olabels['playlevel'] = Text('difficulty','font/Nano.ttf',12, (20,420),(255,130,130))
self.labels['playlevel'] = Text('','font/Nano.ttf',16, (30,430),(230,230,255))
self.olabels['bpm'] = Text('BPM','font/Nano.ttf',12, (20,450),(255,130,130))
self.labels['bpm'] = Text('','font/Nano.ttf',16, (30,460),(230,230,255))
self.calcsongwidgets()
def draw(self,t):
self.screen.fill( (30,0,0) )
l = len(self.songlist)
for nu in range(self.position-4,self.position+8):
n = nu % l
self.songlist[n].getwidget().draw(t)
self.screen.blit(self.fadebottom,(0,280))
for k in self.olabels.keys():
self.olabels[k].draw(t)
for k in self.labels.keys():
self.labels[k].draw(t)
self.fslabel.draw(t)
def calcsongwidgets(self):
l = len(self.songlist)
for nu in range(self.position-4,self.position+8):
n = nu % l
w = self.songlist[n].getwidget()
w.location = (10 + self.songlist[n].depth * 20, 150 - (self.position - nu)*30)
if n == self.position:
w.on()
if self.songlist[n].type == FileNode.DIRECTORY:
for tag in ('artist','genre','playlevel','bpm'):
self.labels[tag].settext('')
self.labels['title'].settext(self.songlist[n].name)
else:
for tag in ('title','artist','genre','bpm'):
self.labels[tag].settext(self.songlist[n].info[tag])
try:
playlevel = int(self.songlist[n].info['playlevel'])
self.labels['playlevel'].settext(("*" * playlevel) + "(" + str(playlevel) + ")")
except ValueError:
self.labels['playlevel'].settext(str(self.songlist[n].info['playlevel']))
else:
w.off()
def run(self):
global possave
decided = 0
pygame.mixer.music.load('snd/0x01.ogg')
pygame.mixer.music.set_volume(0.75)
pygame.mixer.music.play(-1)
stab = pygame.mixer.Sound('snd/stab.ogg')
stab.set_volume(0.25)
start_t = pygame.time.get_ticks()
while decided == 0:
t = pygame.time.get_ticks() - start_t
act = event.getaction()
while act:
if act == event.CANCEL:
return ['mainmenu']
elif act == event.DOWN:
self.position += 1
self.calcsongwidgets()
elif act == event.UP:
self.position -= 1
self.calcsongwidgets()
elif act == event.OK:
if self.songlist[self.position].type == FileNode.DIRECTORY:
self.songlist[self.position].open = not self.songlist[self.position].open
self.songlist = self.songs.tolist()
self.calcsongwidgets()
else:
decided = self.position
act = event.getaction()
self.position = self.position % len(self.songlist)
self.draw(t)
pygame.display.flip()
pygame.mixer.music.fadeout(1500)
stab.play()
self.songs.nukewidgets()
self.songs.current = self.songlist[self.position]
f = open(songcache,'w')
cPickle.dump(self.songs,f)
f.close()
return ['play',self.songlist[decided].path]