File fretsonfire-1.3.110-song-chooser.patch of Package fretsonfire
--- src/Dialogs.py
+++ src/Dialogs.py
@@ -43,7 +43,7 @@
import Player
import Guitar
-def wrapText(font, pos, text, rightMargin = 0.9, scale = 0.002, visibility = 0.0):
+def wrapText(font, pos, text, rightMargin = 0.9, scale = 0.002, visibility = 0.0, hide = 0, hidestring = ""):
"""
Wrap a piece of text inside given margins.
@@ -52,13 +52,17 @@
@param rightMargin: Right margin
@param scale: Text scale
@param visibility: Visibility factor [0..1], 0 is fully visible
+ @param hide: Hide text instead of line wrap
"""
x, y = pos
space = font.getStringSize(" ", scale = scale)[0]
-
+ hidew, hideh = font.getStringSize(hidestring, scale = scale)
+ rightMargin = rightMargin - hidew
for n, word in enumerate(text.split(" ")):
w, h = font.getStringSize(word, scale = scale)
- if x + w > rightMargin or word == "\n":
+ if x + w > rightMargin and hide:
+ word = hidestring
+ if (x + w > rightMargin and not hide) or word == "\n":
x = pos[0]
y += h
if word == "\n":
@@ -67,6 +71,9 @@
glRotate(visibility * (n + 1) * -45, 0, 0, 1)
font.render(word, (x, y + visibility * n), scale = scale)
glPopMatrix()
+ if x + w > rightMargin and hide:
+ x += hidew + space
+ break
x += w + space
return (x - space, y)
@@ -122,7 +129,7 @@
elif key == pygame.K_BACKSPACE and not self.accepted:
self.text = self.text[:-1]
elif unicode and ord(unicode) > 31 and not self.accepted:
- self.text += unicode
+ self.text += str(unicode)
return True
def run(self, ticks):
@@ -338,7 +345,11 @@
self.initialItem = selectedSong
self.library = selectedLibrary
self.searchText = ""
+ self.playSongName = ""
+ self.cassetteShow = self.engine.config.get("game", "casseteview")
+ self.autoPreview = self.engine.config.get("game", "autopreview")
+ self.artistSort = self.engine.config.get("game", "artistsort")
# Use the default library if this one doesn't exist
if not self.library or not os.path.isdir(self.engine.resource.fileName(self.library)):
self.library = Song.DEFAULT_LIBRARY
@@ -433,7 +444,7 @@
else:
self.engine.view.popLayer(self)
self.accepted = True
- if not self.song:
+ if not self.song and self.autoPreview:
self.engine.data.acceptSound.play()
elif c in [Player.CANCEL, Player.KEY2]:
if self.library != Song.DEFAULT_LIBRARY:
@@ -453,7 +464,7 @@
if self.matchesSearch(self.items[self.selectedIndex]):
break
self.updateSelection()
- if not self.song:
+ if not self.song and self.autoPreview:
self.engine.data.selectSound.play()
elif c in [Player.DOWN, Player.ACTION2]:
if self.matchesSearch(self.items[self.selectedIndex]):
@@ -462,12 +473,45 @@
if self.matchesSearch(self.items[self.selectedIndex]):
break
self.updateSelection()
- if not self.song:
+ if not self.song and self.autoPreview:
+ self.engine.data.selectSound.play()
+ elif key == pygame.K_PAGEUP:
+ if self.matchesSearch(self.items[self.selectedIndex]):
+ while 1:
+ self.selectedIndex = (self.selectedIndex - 10) % len(self.items)
+ if self.matchesSearch(self.items[self.selectedIndex]):
+ break
+ self.updateSelection()
+ if not self.song and self.autoPreview:
self.engine.data.selectSound.play()
+ elif key == pygame.K_PAGEDOWN:
+ if self.matchesSearch(self.items[self.selectedIndex]):
+ while 1:
+ self.selectedIndex = (self.selectedIndex + 10) % len(self.items)
+ if self.matchesSearch(self.items[self.selectedIndex]):
+ break
+ self.updateSelection()
+ if not self.song and self.autoPreview:
+ self.engine.data.selectSound.play()
elif key == pygame.K_BACKSPACE and not self.accepted:
self.searchText = self.searchText[:-1]
+ self.doSearch()
+ elif key == pygame.K_SPACE:
+ if self.playSongName == self.getSelectedSong():
+ self.playSongName = ""
+ self.song.fadeout(1000)
+ else:
+ self.playSelectedSong(forceplay=1)
+ elif key == pygame.K_HOME:
+ self.artistSort = (self.artistSort + 1) % 2
+ if self.artistSort:
+ self.items.sort(key=lambda l: (l.artist.lower() if isinstance(l, Song.SongInfo) else '0'))
+ else:
+ self.items.sort(key=lambda l: (l.name.lower()))
+ elif key == pygame.K_TAB:
+ self.cassetteShow = not self.cassetteShow
elif unicode and ord(unicode) > 31 and not self.accepted:
- self.searchText += unicode
+ self.searchText += str(unicode)
self.doSearch()
return True
@@ -504,9 +548,9 @@
song.play()
self.song = song
- def playSelectedSong(self):
+ def playSelectedSong(self, forceplay = 0):
song = self.getSelectedSong()
- if not song:
+ if not song or (not self.autoPreview and not forceplay):
return
if self.songLoader:
@@ -517,10 +561,12 @@
return
if self.song:
+ self.playSongName = ""
self.song.fadeout(1000)
self.songLoader = self.engine.resource.load(self, None, lambda: Song.loadSong(self.engine, song, playbackOnly = True, library = self.library),
onLoad = self.songLoaded)
+ self.playSongName = self.getSelectedSong()
def run(self, ticks):
self.time += ticks / 50.0
@@ -608,73 +654,160 @@
self.background.transform.scale(math.sin(t / 8) + 2, math.sin(t / 8) + 2)
self.background.draw()
- # render the item list
- try:
- glMatrixMode(GL_PROJECTION)
- glPushMatrix()
- glLoadIdentity()
- gluPerspective(60, self.engine.view.aspectRatio, 0.1, 1000)
- glMatrixMode(GL_MODELVIEW)
- glLoadIdentity()
-
- glEnable(GL_DEPTH_TEST)
- glDisable(GL_CULL_FACE)
- glDepthMask(1)
-
- offset = 10 * (v ** 2)
- self.camera.origin = (-10 + offset, -self.cameraOffset, 4 + offset)
- self.camera.target = ( 0 + offset, -self.cameraOffset, 2.5 + offset)
- self.camera.apply()
-
- y = 0.0
- for i, item in enumerate(self.items):
- if not self.matchesSearch(item):
- continue
+ x = .6
+ y = .15
+
+ if self.cassetteShow:
+ # render the item list
+ try:
+ glMatrixMode(GL_PROJECTION)
+ glPushMatrix()
+ glLoadIdentity()
+ gluPerspective(60, self.engine.view.aspectRatio, 0.1, 1000)
+ glMatrixMode(GL_MODELVIEW)
+ glLoadIdentity()
+
+ glEnable(GL_DEPTH_TEST)
+ glDisable(GL_CULL_FACE)
+ glDepthMask(1)
+
+ offset = 10 * (v ** 2)
+ self.camera.origin = (-10 + offset, -self.cameraOffset, 4 + offset)
+ self.camera.target = ( 0 + offset, -self.cameraOffset, 2.5 + offset)
+ self.camera.apply()
+
+ y = 0.0
+ for i, item in enumerate(self.items):
+ if not self.matchesSearch(item):
+ continue
- c = math.sin(self.itemAngles[i] * math.pi / 180)
+ c = math.sin(self.itemAngles[i] * math.pi / 180)
- if isinstance(item, Song.SongInfo):
- h = c * self.cassetteWidth + (1 - c) * self.cassetteHeight
- else:
- h = c * self.libraryWidth + (1 - c) * self.libraryHeight
+ if isinstance(item, Song.SongInfo):
+ h = c * self.cassetteWidth + (1 - c) * self.cassetteHeight
+ else:
+ h = c * self.libraryWidth + (1 - c) * self.libraryHeight
- d = (y + h * .5 + self.camera.origin[1]) / (4 * (self.camera.target[2] - self.camera.origin[2]))
+ d = (y + h * .5 + self.camera.origin[1]) / (4 * (self.camera.target[2] - self.camera.origin[2]))
- if i == self.selectedIndex:
- self.selectedOffset = y + h / 2
- Theme.setSelectedColor()
- else:
- Theme.setBaseColor()
+ if i == self.selectedIndex:
+ self.selectedOffset = y + h / 2
+ Theme.setSelectedColor()
+ else:
+ Theme.setBaseColor()
- glTranslatef(0, -h / 2, 0)
+ glTranslatef(0, -h / 2, 0)
- glPushMatrix()
- if abs(d) < 1.2:
- if isinstance(item, Song.SongInfo):
- glRotate(self.itemAngles[i], 0, 0, 1)
- self.renderCassette(item.cassetteColor, self.itemLabels[i])
- elif isinstance(item, Song.LibraryInfo):
- glRotate(-self.itemAngles[i], 0, 0, 1)
- if i == self.selectedIndex:
- glRotate(self.time * 4, 1, 0, 0)
- self.renderLibrary(item.color, self.itemLabels[i])
- glPopMatrix()
+ glPushMatrix()
+ if abs(d) < 1.2:
+ if isinstance(item, Song.SongInfo):
+ glRotate(self.itemAngles[i], 0, 0, 1)
+ self.renderCassette(item.cassetteColor, self.itemLabels[i])
+ elif isinstance(item, Song.LibraryInfo):
+ glRotate(-self.itemAngles[i], 0, 0, 1)
+ if i == self.selectedIndex:
+ glRotate(self.time * 4, 1, 0, 0)
+ self.renderLibrary(item.color, self.itemLabels[i])
+ glPopMatrix()
- glTranslatef(0, -h / 2, 0)
- y += h
- glDisable(GL_DEPTH_TEST)
- glDisable(GL_CULL_FACE)
- glDepthMask(0)
+ glTranslatef(0, -h / 2, 0)
+ y += h
+
+ glDisable(GL_DEPTH_TEST)
+ glDisable(GL_CULL_FACE)
+ glDepthMask(0)
- finally:
- glMatrixMode(GL_PROJECTION)
- glPopMatrix()
- glMatrixMode(GL_MODELVIEW)
+ finally:
+ glMatrixMode(GL_PROJECTION)
+ glPopMatrix()
+ glMatrixMode(GL_MODELVIEW)
+ else:
+ self.engine.view.setOrthogonalProjection(normalize = True)
+ font = self.engine.data.font
- # render the song info
+ try:
+ glEnable(GL_BLEND)
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+ glEnable(GL_COLOR_MATERIAL)
+ Theme.setBaseColor(1 - v)
+ n = (0, 0)
+ glBegin(GL_QUADS)
+ glColor4f(0,0,0, .2)
+ glVertex2f(.04, .02)
+ glVertex2f(.04, .652)
+ glVertex2f(.58, .652)
+ glVertex2f(.58, .02)
+ glEnd()
+ glBegin(GL_LINE_LOOP)
+ glColor4f(.7,.7,.7,1)
+ glVertex2f(.04, .02)
+ glVertex2f(.04, .652)
+ glVertex2f(.58, .652)
+ glVertex2f(.58, .02)
+ glEnd()
+
+ length = 0
+ select = 0
+ it = 0
+ for i, item in enumerate(self.items):
+ if not self.matchesSearch(item):
+ continue
+ if isinstance(item, Song.SongInfo) or isinstance(item, Song.LibraryInfo):
+ length+=1
+ if self.selectedIndex == i:
+ select = length
+
+ Theme.setSelectedColor(1 - v)
+ scale = 0.0008
+ for i, item in enumerate(self.items):
+ if not self.matchesSearch(item):
+ continue
+ if isinstance(item, Song.SongInfo) or isinstance(item, Song.LibraryInfo):
+ it+=1
+ if it >= (select - 5) or it >= (select + 11):
+ if self.selectedIndex == i:
+ glBegin(GL_QUADS)
+ glColor4f(1,1,1, .1)
+ else:
+ glBegin(GL_QUADS)
+ if it % 2 == 0:
+ glColor4f(0,0,0, .3)
+ else:
+ glColor4f(0,0,0, .5)
+ glVertex2f(.045, n[1] + font.getHeight() * scale)
+ glVertex2f(.045, n[1] + 3*font.getHeight() * scale)
+ glVertex2f(.575, n[1] + 3*font.getHeight() * scale)
+ glVertex2f(.575, n[1] + font.getHeight() * scale)
+ glEnd()
+ Theme.setSelectedColor(1 - v)
+ if self.artistSort:
+ n = wrapText(font, (.05, n[1] + font.getHeight() * scale), item.artist if isinstance(item, Song.SongInfo) else _("Songs library"), 0.57, visibility = 0.0, scale = scale, hide = 1, hidestring = "...")
+ Theme.setBaseColor(1 - v)
+ n = wrapText(font, (.07, n[1] + font.getHeight() * scale), item.name, 0.57, visibility = 0.0, scale = scale, hide = 1, hidestring = "..." )
+ else:
+ n = wrapText(font, (.05, n[1] + font.getHeight() * scale), item.name, 0.57, visibility = 0.0, scale = scale, hide = 1, hidestring = "...")
+ Theme.setBaseColor(1 - v)
+ n = wrapText(font, (.07, n[1] + font.getHeight() * scale), item.artist if isinstance(item, Song.SongInfo) else _("Songs library"), 0.57, visibility = 0.0, scale = scale, hide = 1, hidestring = "..." )
+ if ((n[1] + 2*font.getHeight() * scale) >= .65):
+ break
+
+ perc = float(select)/float(length) if length > 0 else 0
+ glBegin(GL_QUADS)
+ glColor4f(1,1,1,.8)
+ glVertex2f(.575, .02 + .59*perc)
+ glColor4f(.3,.3,.3,.8)
+ glVertex2f(.575, .02 + .59*perc + .04)
+ glColor4f(1,1,1,.8)
+ glVertex2f(.586, .02 + .59*perc + .04)
+ glColor4f(.3,.3,.3,.8)
+ glVertex2f(.586, .02 + .59*perc)
+ glEnd()
+
+ finally:
+ self.engine.view.resetProjection()
self.engine.view.setOrthogonalProjection(normalize = True)
font = self.engine.data.font
-
+ # render the song info
try:
glEnable(GL_BLEND)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
--- src/fretsonfire.pot
+++ src/fretsonfire.pot
@@ -120,63 +120,67 @@
msgid "__lefttoright__"
msgstr ""
-#: Dialogs.py:271
+#: Dialogs.py:278
msgid "<OK>"
msgstr ""
-#: Dialogs.py:357
+#: Dialogs.py:368
msgid "Browsing Collection..."
msgstr ""
-#: Dialogs.py:683
+#: Dialogs.py:784 Dialogs.py:790
+msgid "Songs library"
+msgstr ""
+
+#: Dialogs.py:818
msgid "Filter: %s"
msgstr ""
-#: Dialogs.py:685
+#: Dialogs.py:820
msgid "Not found"
msgstr ""
-#: Dialogs.py:688
+#: Dialogs.py:823
msgid "Loading Preview..."
msgstr ""
-#: Dialogs.py:731
+#: Dialogs.py:866
msgid "One song in this library"
msgstr ""
-#: Dialogs.py:733
+#: Dialogs.py:868
msgid "%d songs in this library"
msgstr ""
-#: Dialogs.py:758
+#: Dialogs.py:893
msgid "[Parent Folder]"
msgstr ""
-#: Dialogs.py:760
+#: Dialogs.py:895
msgid "%s [Folder]"
msgstr ""
-#: Dialogs.py:966
+#: Dialogs.py:1101
msgid "%.2f beats per minute"
msgstr ""
-#: Dialogs.py:1030
+#: Dialogs.py:1165
msgid "Pick!"
msgstr ""
-#: Dialogs.py:1069
+#: Dialogs.py:1204
msgid "Choose a Song"
msgstr ""
-#: Dialogs.py:1084
+#: Dialogs.py:1219
msgid "Choose a File"
msgstr ""
-#: Dialogs.py:1110
+#: Dialogs.py:1245
msgid "Play with the keys and press Escape when you're done."
msgstr ""
-#: Dialogs.py:1120
+#: Dialogs.py:1255
msgid "Loading..."
msgstr ""
@@ -392,11 +396,11 @@
msgid "Upload Highscores"
msgstr ""
-#: GameEngine.py:51 GameEngine.py:53 GameEngine.py:54 GameEngine.py:55
+#: GameEngine.py:51 GameEngine.py:53 GameEngine.py:54 GameEngine.py:55 GameEngine.py:56 GameEngine.py:57 GameEngine.py:58
msgid "No"
msgstr ""
-#: GameEngine.py:51 GameEngine.py:53 GameEngine.py:54 GameEngine.py:55
+#: GameEngine.py:51 GameEngine.py:53 GameEngine.py:54 GameEngine.py:55 GameEngine.py:56 GameEngine.py:57 GameEngine.py:58
msgid "Yes"
msgstr ""
@@ -409,106 +413,118 @@
msgstr ""
#: GameEngine.py:55
-msgid "Fullscreen Mode"
+msgid "Cassete list mode"
msgstr ""
#: GameEngine.py:56
+msgid "Song auto preview"
+msgstr ""
+
+#: GameEngine.py:57
+msgid "Sort by artist"
+msgstr ""
+
+#: GameEngine.py:58
+msgid "Fullscreen Mode"
+msgstr ""
+
+#: GameEngine.py:59
msgid "2x"
msgstr ""
-#: GameEngine.py:56
+#: GameEngine.py:59
msgid "4x"
msgstr ""
-#: GameEngine.py:56
+#: GameEngine.py:59
msgid "6x"
msgstr ""
-#: GameEngine.py:56
+#: GameEngine.py:59
msgid "8x"
msgstr ""
-#: GameEngine.py:56
+#: GameEngine.py:59
msgid "Antialiasing Quality"
msgstr ""
-#: GameEngine.py:56
+#: GameEngine.py:59
msgid "None"
msgstr ""
-#: GameEngine.py:58
+#: GameEngine.py:61
msgid "Frames per Second"
msgstr ""
-#: GameEngine.py:59
+#: GameEngine.py:62
msgid "High"
msgstr ""
-#: GameEngine.py:59
+#: GameEngine.py:62
msgid "Low"
msgstr ""
-#: GameEngine.py:59
+#: GameEngine.py:62
msgid "Normal"
msgstr ""
-#: GameEngine.py:59
+#: GameEngine.py:62
msgid "SVG Quality"
msgstr ""
-#: GameEngine.py:60
+#: GameEngine.py:63
msgid "Sample Frequency"
msgstr ""
-#: GameEngine.py:61
+#: GameEngine.py:64
msgid "Sample Bits"
msgstr ""
-#: GameEngine.py:63
+#: GameEngine.py:66
msgid "Buffer Size"
msgstr ""
-#: GameEngine.py:64
+#: GameEngine.py:67
msgid "A/V delay"
msgstr ""
-#: GameEngine.py:65
+#: GameEngine.py:68
msgid "Loud"
msgstr ""
-#: GameEngine.py:65
+#: GameEngine.py:68
msgid "Painful"
msgstr ""
-#: GameEngine.py:65
+#: GameEngine.py:68
msgid "Quiet"
msgstr ""
-#: GameEngine.py:65
+#: GameEngine.py:68
msgid "Screw Up Sounds"
msgstr ""
-#: GameEngine.py:65 Mod.py:33
+#: GameEngine.py:68 Mod.py:33
msgid "Off"
msgstr ""
-#: GameEngine.py:66
+#: GameEngine.py:69
msgid "Guitar Volume"
msgstr ""
-#: GameEngine.py:67
+#: GameEngine.py:70
msgid "Song Volume"
msgstr ""
-#: GameEngine.py:68
+#: GameEngine.py:71
msgid "Rhythm Volume"
msgstr ""
-#: GameEngine.py:69
+#: GameEngine.py:72
msgid "Text scale"
msgstr ""
-#: GameEngine.py:135
+#: GameEngine.py:138
msgid "Frets on Fire"
msgstr ""
--- src/GameEngine.py
+++ src/GameEngine.py
@@ -52,6 +52,9 @@
Config.define("game", "uploadurl", str, "http://fretsonfire.sourceforge.net/play")
Config.define("game", "leftymode", bool, False, text = _("Lefty mode"), options = {False: _("No"), True: _("Yes")})
Config.define("game", "tapping", bool, True, text = _("Tappable notes"), options = {False: _("No"), True: _("Yes")})
+Config.define("game", "casseteview", bool, True, text = _("Cassete list mode"), options = {False: _("No"), True: _("Yes")})
+Config.define("game", "autopreview", bool, True, text = _("Song auto preview"), options = {False: _("No"), True: _("Yes")})
+Config.define("game", "artistsort", bool, False, text = _("Sort by artist"), options = {False: _("No"), True: _("Yes")})
Config.define("video", "fullscreen", bool, False, text = _("Fullscreen Mode"), options = {False: _("No"), True: _("Yes")})
Config.define("video", "multisamples", int, 4, text = _("Antialiasing Quality"), options = {0: _("None"), 2: _("2x"), 4: _("4x"), 6: _("6x"), 8: _("8x")})
Config.define("video", "resolution", str, "640x480")
--- src/Settings.py
+++ src/Settings.py
@@ -140,6 +140,9 @@
ConfigChoice(engine.config, "game", "leftymode", autoApply = True),
ConfigChoice(engine.config, "game", "tapping", autoApply = True),
ConfigChoice(engine.config, "game", "uploadscores", autoApply = True),
+ ConfigChoice(engine.config, "game", "casseteview", autoApply = True),
+ ConfigChoice(engine.config, "game", "autopreview", autoApply = True),
+ ConfigChoice(engine.config, "game", "artistsort", autoApply = True),
]
gameSettingsMenu = Menu.Menu(engine, gameSettings + applyItem)