From 3ba33f8e920a9e9a3114f159e2b6fda4273a6efb Mon Sep 17 00:00:00 2001
From: whiteshark0 <whiteshark0@b956fd51-792f-4845-bead-9b4dfca2ff2c>
Date: Wed, 28 Mar 2007 13:08:41 +0000
Subject: Added Jumpto Ability to SongScreen (Press J) Fixed: Golden Notes are
 not shown in PartyMode

git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@39 b956fd51-792f-4845-bead-9b4dfca2ff2c
---
 Game/Code/Classes/UGraphic.pas        |   9 +-
 Game/Code/Classes/USongs.pas          |  77 ++++++-
 Game/Code/Classes/UThemes.pas         |  16 +-
 Game/Code/Screens/UScreenSing.pas     |   9 +-
 Game/Code/Screens/UScreenSingModi.pas |   6 +-
 Game/Code/Screens/UScreenSong.pas     | 371 ++++++++++++++--------------------
 Game/Code/Screens/UScreenSongMenu.pas |   1 +
 Game/Code/UltraStar.dpr               |   1 +
 8 files changed, 248 insertions(+), 242 deletions(-)

(limited to 'Game')

diff --git a/Game/Code/Classes/UGraphic.pas b/Game/Code/Classes/UGraphic.pas
index 8238eace..d9831143 100644
--- a/Game/Code/Classes/UGraphic.pas
+++ b/Game/Code/Classes/UGraphic.pas
@@ -6,7 +6,7 @@ uses
   UScreenWelcome, UScreenMain, UScreenName, UScreenLevel, UScreenOptions, UScreenOptionsGame,
   UScreenOptionsGraphics, UScreenOptionsSound, UScreenOptionsLyrics, UScreenOptionsThemes, UScreenOptionsRecord,
   UScreenSong, UScreenSing, UScreenScore, UScreenTop5, UScreenEditSub,
-  UScreenEdit, UScreenEditConvert, UScreenEditHeader, UScreenOpen, UThemes, USkins, UScreenSongMenu,
+  UScreenEdit, UScreenEditConvert, UScreenEditHeader, UScreenOpen, UThemes, USkins, UScreenSongMenu, UScreenSongJumpto,
   {Party Screens} UScreenSingModi, UScreenPartyNewRound, UScreenPartyScore, UScreenPartyOptions, UScreenPartyWin, UScreenPartyPlayer;
 
 type
@@ -51,6 +51,7 @@ var
   ScreenOpen:         TScreenOpen;
 
   ScreenSongMenu:     TScreenSongMenu;
+  ScreenSongJumpto:     TScreenSongJumpto;
 
   //Party Screens
   ScreenSingModi:         TScreenSingModi;
@@ -390,9 +391,11 @@ begin
   ScreenOpen :=             TScreenOpen.Create('');
   Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Open', 3); Log.BenchmarkStart(3);
   ScreenSingModi :=         TScreenSingModi.Create;
-  Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen SongMenu', 3); Log.BenchmarkStart(3);
-  //ScreenSongMenu :=         TScreenSongMenu.Create;
   Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen Sing with Modi support', 3); Log.BenchmarkStart(3);
+  ScreenSongMenu :=         TScreenSongMenu.Create;
+  Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen SongMenu', 3); Log.BenchmarkStart(3);
+  ScreenSongJumpto :=         TScreenSongJumpto.Create;
+  Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen SongJumpto', 3); Log.BenchmarkStart(3);
   ScreenPartyNewRound :=    TScreenPartyNewRound.Create;
   Log.BenchmarkEnd(3); Log.LogBenchmark('====> Screen PartyNewRound', 3); Log.BenchmarkStart(3);
   ScreenPartyScore :=       TScreenPartyScore.Create;
diff --git a/Game/Code/Classes/USongs.pas b/Game/Code/Classes/USongs.pas
index c2532a03..5b75879d 100644
--- a/Game/Code/Classes/USongs.pas
+++ b/Game/Code/Classes/USongs.pas
@@ -82,6 +82,8 @@ type
     function FindNextVisible(SearchFrom:integer): integer; //Find Next visible Song
     function VisibleSongs: integer; // returns number of visible songs (for tabs)
     function VisibleIndex(Index: integer): integer; // returns visible song index (skips invisible)
+
+    function SetFilter(FilterStr: String; const fType: Byte): Cardinal;
   end;
 
 var
@@ -91,7 +93,7 @@ var
 
 implementation
 
-uses UPliki, UIni, UFiles;
+uses UPliki, UIni, UFiles, StrUtils;
 
 procedure TSongs.LoadSongList;
 begin
@@ -572,12 +574,12 @@ var
   S:    integer; // song
 begin
   CatNumShow := Index;
-  for S := 0 to high(CatSongs.Song) do begin
-    if CatSongs.Song[S].OrderNum = Index then
+  for S := 0 to high(CatSongs.Song) do
+  begin
+    if (CatSongs.Song[S].OrderNum = Index) AND (Not CatSongs.Song[S].Main) then
       CatSongs.Song[S].Visible := true
     else
-      if not CatSongs.Song[S].Main then
-        CatSongs.Song[S].Visible := false;
+      CatSongs.Song[S].Visible := false;
   end;
 end;
 
@@ -599,12 +601,6 @@ begin
   if Num <> CatNumShow then
     begin
     ShowCategory(Num);
-    //Hide Categorys when in Category Hack
-    for S := low(CatSongs.Song) to high(CatSongs.Song) do begin
-      if CatSongs.Song[S].Main then   //Hide all Cats
-      CatSongs.Song[S].Visible := false
-    end;
-    //Hide Categorys when in Category Hack End
     end
   else begin
     ShowCategoryList;
@@ -664,4 +660,63 @@ begin
     if CatSongs.Song[S].Visible = true then Inc(Result);
 end;
 
+function TCatSongs.SetFilter(FilterStr: String; const fType: Byte): Cardinal;
+var
+  I, J: Integer;
+  cString: String;
+  SearchStr: Array of String;
+begin
+  {fType: 0: All
+          1: Title
+          2: Artist}
+  if FilterStr<>'' then begin
+    Result := 0;
+    //Create Search Array
+    SetLength(SearchStr, 1);
+    I := Pos (' ', FilterStr);
+    While (I <> 0) do
+    begin
+      SetLength (SearchStr, Length(SearchStr) + 1);
+      cString := Copy(FilterStr, 1, I-1);
+      if (cString <> ' ') AND (cString <> '') then
+        SearchStr[High(SearchStr)-1] := cString;
+      Delete (FilterStr, 1, I);
+
+      I := Pos (' ', FilterStr);
+    end;
+    //Copy last Word
+    if (FilterStr <> ' ') AND (FilterStr <> '') then
+      SearchStr[High(SearchStr)] := FilterStr;
+
+    for I:=0 to High(Song) do begin
+      if not Song[i].Main then
+      begin
+        case fType of
+          0: cString := Song[I].Artist + ' ' + Song[i].Title + ' ' + Song[i].Folder;
+          1: cString := Song[I].Title;
+          2: cString := Song[I].Artist;
+        end;
+        Song[i].Visible:=True;
+        //Look for every Searched Word
+        For J := 0 to High(SearchStr) do
+        begin
+          Song[i].Visible := Song[i].Visible AND AnsiContainsText(cString, SearchStr[J])
+        end;
+        if Song[i].Visible then
+          Inc(Result);
+      end
+      else
+        Song[i].Visible:=False;
+    end;
+    CatNumShow := -2;
+  end
+  else begin
+    for i:=0 to High(Song) do begin
+      Song[i].Visible:=(Ini.Tabs=1)=Song[i].Main;
+      CatNumShow := -1;
+    end;
+    Result := 0;
+  end;
+end;
+
 end.
diff --git a/Game/Code/Classes/UThemes.pas b/Game/Code/Classes/UThemes.pas
index e9aa2141..e31e94d2 100644
--- a/Game/Code/Classes/UThemes.pas
+++ b/Game/Code/Classes/UThemes.pas
@@ -393,6 +393,12 @@ type
     TextMenu: TThemeText;
   end;
 
+  TThemeSongJumpTo = class(TThemeBasic)
+    ButtonSearchText: TThemeButton;
+    SelectSlideType:  TThemeSelectSlide;
+    TextFound:        TThemeText;
+  end;
+
   //Party Screens
   TThemePartyNewRound = class(TThemeBasic)
     TextRound1:        TThemeText;
@@ -525,6 +531,7 @@ type
     OptionsRecord:    TThemeOptionsRecord;
     //Menu
     SongMenu:         TThemeSongMenu;
+    SongJumpto:       TThemeSongJumpTo;
     //Party Screens:
     PartyNewRound:    TThemePartyNewRound;
     PartyScore:       TThemePartyScore;
@@ -606,6 +613,7 @@ begin
   OptionsRecord := TThemeOptionsRecord.Create;
 
   SongMenu := TThemeSongMenu.Create;
+  SongJumpto := TThemeSongJumpto.Create;
   //Party Screens
   PartyNewRound := TThemePartyNewRound.Create;
   PartyWin := TThemePartyWin.Create;
@@ -980,7 +988,7 @@ begin
       ThemeLoadSelectSlide(OptionsRecord.SelectSlideChannelR, 'OptionsRecordSelectSlideChannelR');
       ThemeLoadButton(OptionsRecord.ButtonExit, 'OptionsRecordButtonExit');
 
-    //Song Menu
+   //Song Menu
     ThemeLoadBasic (SongMenu, 'SongMenu');
     ThemeLoadButton(SongMenu.Button1, 'SongMenuButton1');
     ThemeLoadButton(SongMenu.Button2, 'SongMenuButton2');
@@ -990,6 +998,12 @@ begin
 
     ThemeLoadText(SongMenu.TextMenu, 'SongMenuTextMenu');
 
+    //Song Jumpto
+    ThemeLoadBasic (SongJumpto, 'SongJumpto');
+    ThemeLoadButton(SongJumpto.ButtonSearchText, 'SongJumptoButtonSearchText');
+    ThemeLoadSelectSlide(SongJumpto.SelectSlideType, 'SongJumptoSelectSlideType');
+    ThemeLoadText(SongJumpto.TextFound, 'SongJumptoTextFound');
+
     //Party Screens:
     //Party NewRound
     ThemeLoadBasic(PartyNewRound, 'PartyNewRound');
diff --git a/Game/Code/Screens/UScreenSing.pas b/Game/Code/Screens/UScreenSing.pas
index f6ec6224..7b96e273 100644
--- a/Game/Code/Screens/UScreenSing.pas
+++ b/Game/Code/Screens/UScreenSing.pas
@@ -636,10 +636,6 @@ begin
 
   // prepare timer (II)
   CountSkipTimeSet;
-
-//GoldenStarsTwinkle Mod
-  GoldenRec.KillAll;
-//GoldenStarsTwinkle Mod End
 end;
 
 function TScreenSing.Draw: boolean;
@@ -1016,6 +1012,11 @@ begin
   Music.CaptureStop;
   Music.Stop;
 
+  //Kill all Stars not Killed yet
+  //GoldenStarsTwinkle Mod
+    GoldenRec.KillAll;
+  //GoldenStarsTwinkle Mod End
+
   if Ini.SavePlayback = 1 then begin
     Log.BenchmarkStart(0);
     Log.LogVoice(0);
diff --git a/Game/Code/Screens/UScreenSingModi.pas b/Game/Code/Screens/UScreenSingModi.pas
index ec47dc60..bf342e7a 100644
--- a/Game/Code/Screens/UScreenSingModi.pas
+++ b/Game/Code/Screens/UScreenSingModi.pas
@@ -63,7 +63,7 @@ procedure PlaySound (const Index: Cardinal); stdcall;       //Plays a Custom Sou
 function ToSentences(Const Czeski: TCzesci): TSentences;
 
 implementation
-uses UGraphic, UDraw, UMain, Classes, URecord, ULanguage, math, UDLLManager, USkins;
+uses UGraphic, UDraw, UMain, Classes, URecord, ULanguage, math, UDLLManager, USkins, UGraphicClasses;
 
 // Method for input parsing. If False is returned, GetNextWindow
 // should be checked to know the next window to load;
@@ -967,6 +967,10 @@ end;
   // draw custom items
   SingModiDraw(PlayerInfo);  // always draw
 
+  //GoldenNoteStarsTwinkle Mod
+    GoldenRec.SpawnRec;
+  //GoldenNoteStarsTwinkle Mod
+
   //Update PlayerInfo
   for I := 0 to PlayerInfo.NumPlayers-1 do
   begin
diff --git a/Game/Code/Screens/UScreenSong.pas b/Game/Code/Screens/UScreenSong.pas
index cd412ceb..69ec8639 100644
--- a/Game/Code/Screens/UScreenSong.pas
+++ b/Game/Code/Screens/UScreenSong.pas
@@ -69,7 +69,8 @@ type
       procedure SkipTo(Target: integer);
       procedure FixSelected; //Show Wrong Song when Tabs on Fix
       procedure FixSelected2; //Show Wrong Song when Tabs on Fix
-      procedure ShowCatTL(Cat: Integer);// Show Cat in Tob left
+      procedure ShowCatTL(Cat: Integer);// Show Cat in Top left
+      procedure ShowCatTLCustom(Caption: String);// Show Custom Text in Top left
       procedure HideCatTL;// Show Cat in Tob left
       procedure Refresh; //Refresh Song Sorting
       procedure DrawEqualizer;
@@ -81,6 +82,9 @@ type
       procedure StartSong;
       procedure OpenEditor;
       procedure DoJoker(Team: Byte);
+
+      //Extensions
+      procedure DrawExtensions;
   end;
 
 implementation
@@ -92,37 +96,50 @@ uses UGraphic, UMain, UCovers, math, OpenGL12, Windows, USkins, UDLLManager, UPa
 procedure TScreenSong.FixSelected;
 var I, I2: Integer;
   begin
-  I2:= 0;
-  for I := low(CatSongs.Song) to High(Catsongs.Song) do
+    if CatSongs.VisibleSongs > 0 then
     begin
-    if CatSongs.Song[I].Visible then
-      inc(I2);
+      I2:= 0;
+      for I := low(CatSongs.Song) to High(Catsongs.Song) do
+      begin
+        if CatSongs.Song[I].Visible then
+          inc(I2);
 
-    if I = Interaction - 1 then
-      break;
-    end;
+        if I = Interaction - 1 then
+          break;
+      end;
 
-  SongCurrent := I2;
-  SongTarget  := I2;
+      SongCurrent := I2;
+      SongTarget  := I2;
+    end;
   end;
 
 procedure TScreenSong.FixSelected2;
 var I, I2: Integer;
   begin
-  I2:= 0;
-  for I := low(CatSongs.Song) to High(Catsongs.Song) do
+    if CatSongs.VisibleSongs > 0 then
     begin
-    if CatSongs.Song[I].Visible then
-      inc(I2);
+      I2:= 0;
+      for I := low(CatSongs.Song) to High(Catsongs.Song) do
+      begin
+        if CatSongs.Song[I].Visible then
+          inc(I2);
 
-    if I = Interaction - 1 then
-      break;
-    end;
+        if I = Interaction - 1 then
+          break;
+      end;
 
-  SongTarget  := I2;
+      SongTarget  := I2;
+    end;
   end;
 //Show Wrong Song when Tabs on Fix End
 
+  procedure TScreenSong.ShowCatTLCustom(Caption: String);// Show Custom Text in Top left
+  begin
+    Text[TextCat].Text := Caption;
+    Text[TextCat].Visible := true;
+    Static[StaticCat].Visible := False;
+  end;
+
   //Show Cat in Top Left Mod
   procedure TScreenSong.ShowCatTL(Cat: Integer);
     begin
@@ -162,164 +179,24 @@ var
 begin
   Result := true;
 
-  //Song Menu
+  //Song Screen Extensions (Jumpto + Menu)
   if (ScreenSongMenu.Visible) then
   begin
     Result := ScreenSongMenu.ParseInput(PressedKey, ScanCode, PressedDown);
     Exit;
+  end
+  else if (ScreenSongJumpto.Visible) then
+  begin
+    Result := ScreenSongJumpto.ParseInput(PressedKey, ScanCode, PressedDown);
+    Exit;
   end;
 
   If (PressedDown) Then
   begin // Key Down
 
-//  HS := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT);
-{  if (not HighSpeed) and (HS > 0) then begin
-    HighSpeed := true;
-    SDL_EnableKeyRepeat(50, 50);
-  end;
-  if (HighSpeed) and (HS = 0) then begin
-    HighSpeed := false;
-    SDL_EnableKeyRepeat(125, 125);
-  end;}
-
-  SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT
+    SDL_ModState := SDL_GetModState and (KMOD_LSHIFT + KMOD_RSHIFT
     + KMOD_LCTRL + KMOD_RCTRL + KMOD_LALT  + KMOD_RALT);
 
-  // Jump to Key Mod
-  if (SDL_ModState = KMOD_LALT) AND (Mode = 0) then //Jump to Key
-  begin
-    //get Letter
-    case PressedKey of
-      SDLK_A :  Letter := 'A';
-      SDLK_B :  Letter := 'B';
-      SDLK_C :  Letter := 'C';
-      SDLK_D :  Letter := 'D';
-      SDLK_E :  Letter := 'E';
-      SDLK_F :  Letter := 'F';
-      SDLK_G :  Letter := 'G';
-      SDLK_H :  Letter := 'H';
-      SDLK_I :  Letter := 'I';
-      SDLK_J :  Letter := 'J';
-      SDLK_K :  Letter := 'K';
-      SDLK_L :  Letter := 'L';
-      SDLK_M :  Letter := 'M';
-      SDLK_N :  Letter := 'N';
-      SDLK_O :  Letter := 'O';
-      SDLK_P :  Letter := 'P';
-      SDLK_Q :  Letter := 'Q';
-      SDLK_R :  Letter := 'R';
-      SDLK_S :  Letter := 'S';
-      SDLK_T :  Letter := 'T';
-      SDLK_U :  Letter := 'U';
-      SDLK_V :  Letter := 'V';
-      SDLK_W :  Letter := 'W';
-      SDLK_X :  Letter := 'X';
-      SDLK_Y :  Letter := 'Y';
-      SDLK_Z :  Letter := 'Z';
-      SDLK_1 :  Letter := '1';
-      SDLK_2 :  Letter := '2';
-      SDLK_3 :  Letter := '3';
-      SDLK_4 :  Letter := '4';
-      SDLK_5 :  Letter := '5';
-      SDLK_6 :  Letter := '6';
-      SDLK_7 :  Letter := '7';
-      SDLK_8 :  Letter := '8';
-      SDLK_9 :  Letter := '9';
-      SDLK_0 :  Letter := '0';
-      else exit;
-    end;
-
-  {//Search Letter
-  for I := Interaction + 1 to high(CatSongs.Song) do
-  begin
-    if CatSongs.Song[I].Visible and (Letter = Uppercase(CatSongs.Song[I].Artist)[1]) then
-      break; //Found Song
-    if I = Interaction then //went through complete array but nothing Found
-      break;
-    if I = high(CatSongs.Song) then //At the end of the array->Go to beginning
-      for I2 := low(CatSongs.Song) to Interaction do
-        if CatSongs.Song[I].Visible and (Letter = Uppercase(CatSongs.Song[I].Artist)[1]) then
-          break; //Found Song
-  end;   }
-
-    for I := 0 to High(CatSongs.Song) do begin
-      if (CatSongs.Song[I].Visible) AND (UpperCase(CatSongs.Song[I].Artist[1]) = Letter) then
-      begin
-        //Select Song
-        Interaction := I;
-        SkipTo(Interaction);
-        break;
-      end;
-    end;
-
-  //Don't do other Functions
-  exit;
-  end;
-
-  if (SDL_ModState = KMOD_LALT or KMOD_LSHIFT) then //Jump to Key
-  begin
-    //get Letter
-    case PressedKey of
-      SDLK_a..SDLK_z :  Letter := Chr(Ord('a')+PressedKey-97);
-      SDLK_1 :  Letter := '1';
-      SDLK_2 :  Letter := '2';
-      SDLK_3 :  Letter := '3';
-      SDLK_4 :  Letter := '4';
-      SDLK_5 :  Letter := '5';
-      SDLK_6 :  Letter := '6';
-      SDLK_7 :  Letter := '7';
-      SDLK_8 :  Letter := '8';
-      SDLK_9 :  Letter := '9';
-      SDLK_0 :  Letter := '0';
-      else exit;
-    end;
-
-  {//Search Letter
-  for I := Interaction + 1 to high(CatSongs.Song) do
-  begin
-    if CatSongs.Song[I].Visible and (Letter = Uppercase(CatSongs.Song[I].Artist)[1]) then
-      break; //Found Song
-    if I = Interaction then //went through complete array but nothing Found
-      break;
-    if I = high(CatSongs.Song) then //At the end of the array->Go to beginning
-      for I2 := low(CatSongs.Song) to Interaction do
-        if CatSongs.Song[I].Visible and (Letter = Uppercase(CatSongs.Song[I].Artist)[1]) then
-          break; //Found Song
-  end;   }
-
-   {for I := 0 to High(CatSongs.Song) do begin
-     if (CatSongs.Song[I].Visible) AND (UpperCase(CatSongs.Song[I].Artist[1]) = Letter) then}
-
-    for I := Interaction + 1 to high(CatSongs.Song) + 1 do
-    begin
-      if (I > high(CatSongs.Song)) then
-      begin
-        for I2 := low(CatSongs.Song) to Interaction do
-        begin
-          if CatSongs.Song[I2].Visible and (Letter = lowercase(CatSongs.Song[I2].Artist[1])) then
-          begin
-            Interaction := I2;
-            break; //Found Song
-          end;
-        end;
-        break;
-      end
-      else if CatSongs.Song[I].Visible and (Letter = lowercase(CatSongs.Song[I].Artist[1])) then
-      begin
-        Interaction := I;
-        break; //Found Song
-      end;
-    end;
-
-
-   //Select Song
-   SkipTo(Interaction);
-
-  //Don't do other Functions
-  exit;
-  end;
-
-
     case PressedKey of
       SDLK_ESCAPE :
         begin
@@ -406,7 +283,6 @@ begin
               end
               else if (Mode = 1) then //PartyMode -> Show Menu
               begin
-                ScreenSongMenu.Visible := True;
                 ScreenSongMenu.MenuShow(SM_Party_Main);
               end;
             end;
@@ -417,12 +293,19 @@ begin
         begin
           if Length(Songs.Song) > 0 then begin
             if not CatSongs.Song[Interaction].Main then begin // clicked on Song
-              ScreenSongMenu.Visible := True;
               ScreenSongMenu.MenuShow(SM_Main);
             end;
           end;
         end;
 
+      SDLK_J: //Show SongMenu
+        begin
+          if Length(Songs.Song) > 0 then
+          begin
+            ScreenSongJumpto.Visible := True;
+          end;
+        end;
+
       SDLK_DOWN:
         begin
         if (Mode = 0) then
@@ -788,25 +671,47 @@ begin
 end;
 
 procedure TScreenSong.SetScroll;
+var
+  VS, B: Integer;
 begin
-//Set Positions
-  Case Theme.Song.Cover.Style of
-    3: SetScroll3;
-    5: SetScroll5
-    else SetScroll4;
-  end;
-//Set Texts:
-  Text[TextArtist].Text := CatSongs.Song[Interaction].Artist;
-  Text[TextTitle].Text  :=  CatSongs.Song[Interaction].Title;
-  if (Ini.Tabs_at_startup = 1) And (CatSongs.CatNumShow = -1) then
+  VS := CatSongs.VisibleSongs;
+  if VS > 0 then
   begin
-    Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].OrderNum) + '/' + IntToStr(CatSongs.CatCount);
-    Text[TextTitle].Text  := '(' + IntToStr(CatSongs.Song[Interaction].CatNumber) + ' ' + Language.Translate('SING_SONGS_IN_CAT') + ')';
+    //Set Positions
+    Case Theme.Song.Cover.Style of
+      3: SetScroll3;
+      5:begin
+          if VS > 5 then
+            SetScroll5
+          else
+            SetScroll4;
+        end;
+      else SetScroll4;
+    end;
+    //Set Texts:
+    Text[TextArtist].Text := CatSongs.Song[Interaction].Artist;
+    Text[TextTitle].Text  :=  CatSongs.Song[Interaction].Title;
+    if (Ini.Tabs_at_startup = 1) And (CatSongs.CatNumShow = -1) then
+    begin
+      Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].OrderNum) + '/' + IntToStr(CatSongs.CatCount);
+      Text[TextTitle].Text  := '(' + IntToStr(CatSongs.Song[Interaction].CatNumber) + ' ' + Language.Translate('SING_SONGS_IN_CAT') + ')';
+    end
+    else if (CatSongs.CatNumShow = -2) then
+      Text[TextNumber].Text := IntToStr(CatSongs.VisibleIndex(Interaction)+1) + '/' + IntToStr(VS)
+    else if (Ini.Tabs_at_startup = 1) then
+      Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].CatNumber) + '/' + IntToStr(CatSongs.Song[Interaction - CatSongs.Song[Interaction].CatNumber].CatNumber)
+    else
+      Text[TextNumber].Text := IntToStr(Interaction+1) + '/' + IntToStr(Length(CatSongs.Song));
   end
-  else if (Ini.Tabs_at_startup = 1) then
-    Text[TextNumber].Text := IntToStr(CatSongs.Song[Interaction].CatNumber) + '/' + IntToStr(CatSongs.Song[Interaction - CatSongs.Song[Interaction].CatNumber].CatNumber)
   else
-    Text[TextNumber].Text := IntToStr(Interaction+1) + '/' + IntToStr(Length(CatSongs.Song));
+  begin
+    Text[TextNumber].Text := '0/0';
+    Text[TextArtist].Text := '';
+    Text[TextTitle].Text  := '';
+    for B := 0 to High(Button) do
+      Button[B].Visible := False;
+
+  end;
 end;
 
 procedure TScreenSong.SetScroll1;
@@ -1023,7 +928,7 @@ begin
 
     Wsp := 2 * pi * (CatSongs.VisibleIndex(B) - SongCurrent) /  VS {CatSongs.VisibleSongs};// 0.5.0 (II): takes another 16ms
 
-    Z := (1 + cos(Wsp)) / 2 - 0.02;
+    Z := (1 + cos(Wsp)) / 2 - 0.2;
     Z2 := (1 + 2*Z) / 3;
 
     Button[B].X := Theme.Song.Cover.X + (Theme.Song.Cover.W + 0.185 * Theme.Song.Cover.H * VS * sin(Wsp) - Theme.Song.Cover.X) * Z2; // 0.5.0 (I): 2 times faster by not calling CatSongs.VisibleSongs
@@ -1247,6 +1152,19 @@ begin
   SetJoker;
 end;
 
+procedure TScreenSong.DrawExtensions;
+begin
+  //Draw Song Menu
+  if (ScreenSongMenu.Visible) then
+  begin
+    ScreenSongMenu.Draw;
+  end
+  else if (ScreenSongJumpto.Visible) then
+  begin
+    ScreenSongJumpto.Draw;
+  end
+end;
+
 function TScreenSong.Draw: boolean;
 var
   dx:   real;
@@ -1286,71 +1204,80 @@ begin
   if Theme.Song.Equalizer.Visible then
     DrawEqualizer;
 
-  //Draw Song Menu
-  if (ScreenSongMenu.Visible) then
-  begin
-    ScreenSongMenu.Draw;
-  end;
+  DrawExtensions;
 end;
 
 procedure TScreenSong.SelectNext;
 var
   Skip:   integer;
   I:      integer;
+  VS:     Integer;
 begin
-  CoverTime := 0;
-  Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', true); // 0.5.0: show cached texture
-  Button[Interaction].Texture2.Alpha := 0;
+  VS := CatSongs.VisibleSongs;
 
-  //0.5.0: unload old full size texture
-  if Button[Interaction].Texture.Name <> Skin.GetTextureFileName('SongCover') then
-    Texture.UnloadTexture(Button[Interaction].Texture.Name, false);
+  if VS > 0 then
+  begin
+    CoverTime := 0;
+    Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', true); // 0.5.0: show cached texture
+    Button[Interaction].Texture2.Alpha := 0;
 
-  Skip := 1;
+    //0.5.0: unload old full size texture
+    if Button[Interaction].Texture.Name <> Skin.GetTextureFileName('SongCover') then
+      Texture.UnloadTexture(Button[Interaction].Texture.Name, false);
 
-  // this 1 could be changed by CatSongs.FindNextVisible
-  while (not CatSongs.Song[(Interaction + Skip) mod Length(Interactions)].Visible) do Inc(Skip);
-  SongTarget := SongTarget + 1;//Skip;
+    Skip := 1;
 
-  Interaction := (Interaction + Skip) mod Length(Interactions);
+    // this 1 could be changed by CatSongs.FindNextVisible
+    while (not CatSongs.Song[(Interaction + Skip) mod Length(Interactions)].Visible) do Inc(Skip);
 
-  // try to keep all at the beginning
-  if SongTarget > CatSongs.VisibleSongs-1 then begin
-    SongTarget := SongTarget - CatSongs.VisibleSongs;
-    SongCurrent := SongCurrent - CatSongs.VisibleSongs;
-  end;
+    SongTarget := SongTarget + 1;//Skip;
 
-  // Interaction -> Button, ktorego okladke przeczytamy
-//  Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', false); // 0.5.0: show uncached texture
+    Interaction := (Interaction + Skip) mod Length(Interactions);
+
+    // try to keep all at the beginning
+    if SongTarget > VS-1 then begin
+      SongTarget := SongTarget - VS;
+      SongCurrent := SongCurrent - VS;
+    end;
+
+  end;
+      // Interaction -> Button, ktorego okladke przeczytamy
+      //  Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', false); // 0.5.0: show uncached texture
 end;
 
 procedure TScreenSong.SelectPrev;
 var
   Skip:   integer;
   I:      integer;
+  VS:     Integer;
 begin
-  CoverTime := 0;
-  Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', true); // 0.5.0: show cached texture
-  Button[Interaction].Texture2.Alpha := 0;
+  VS := CatSongs.VisibleSongs;
 
-  //0.5.0: unload old full size texture
-  if Button[Interaction].Texture.Name <> Skin.GetTextureFileName('SongCover') then
-    Texture.UnloadTexture(Button[Interaction].Texture.Name, false);
+  if VS > 0 then
+  begin
+    CoverTime := 0;
+    Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', true); // 0.5.0: show cached texture
+    Button[Interaction].Texture2.Alpha := 0;
 
-  Skip := 1;
+    //0.5.0: unload old full size texture
+    if Button[Interaction].Texture.Name <> Skin.GetTextureFileName('SongCover') then
+      Texture.UnloadTexture(Button[Interaction].Texture.Name, false);
 
-  while (not CatSongs.Song[(Interaction - Skip + Length(Interactions)) mod Length(Interactions)].Visible) do Inc(Skip);
-  SongTarget := SongTarget - 1;//Skip;
+    Skip := 1;
 
-  Interaction := (Interaction - Skip + Length(Interactions)) mod Length(Interactions);
+    while (not CatSongs.Song[(Interaction - Skip + Length(Interactions)) mod Length(Interactions)].Visible) do Inc(Skip);
+    SongTarget := SongTarget - 1;//Skip;
 
-  // try to keep all at the beginning
-  if SongTarget < 0 then begin
-    SongTarget := SongTarget + CatSongs.VisibleSongs;
-    SongCurrent := SongCurrent + CatSongs.VisibleSongs;
-  end;
+    Interaction := (Interaction - Skip + Length(Interactions)) mod Length(Interactions);
 
-//  Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', false); // 0.5.0: show uncached texture
+    // try to keep all at the beginning
+    if SongTarget < 0 then begin
+      SongTarget := SongTarget + CatSongs.VisibleSongs;
+      SongCurrent := SongCurrent + CatSongs.VisibleSongs;
+    end;
+
+  //  Button[Interaction].Texture := Texture.GetTexture(Button[Interaction].Texture.Name, 'Plain', false); // 0.5.0: show uncached texture
+  end;
 end;
 
 procedure TScreenSong.UpdateLCD;
diff --git a/Game/Code/Screens/UScreenSongMenu.pas b/Game/Code/Screens/UScreenSongMenu.pas
index 2a03a7c2..a5ae2083 100644
--- a/Game/Code/Screens/UScreenSongMenu.pas
+++ b/Game/Code/Screens/UScreenSongMenu.pas
@@ -165,6 +165,7 @@ end;
 procedure TScreenSongMenu.MenuShow(sMenu: Byte);
 begin
   Interaction := 0; //Reset Interaction
+  Visible := True;  //Set Visible
   Case sMenu of
     SM_Main:
       begin
diff --git a/Game/Code/UltraStar.dpr b/Game/Code/UltraStar.dpr
index 9b73883a..65a01257 100644
--- a/Game/Code/UltraStar.dpr
+++ b/Game/Code/UltraStar.dpr
@@ -75,6 +75,7 @@ uses
   UScreenOpen in 'Screens\UScreenOpen.pas',
   UScreenTop5 in 'Screens\UScreenTop5.pas',
   UScreenSongMenu in 'Screens\UScreenSongMenu.pas',
+  UScreenSongJumpto in 'Screens\UScreenSongJumpto.pas',
 
   //------------------------------
   //Includes - Screens PartyMode
-- 
cgit v1.2.3