From 019d57a35441572024cd478da08a67149a1c865f Mon Sep 17 00:00:00 2001 From: tobigun Date: Sun, 27 Apr 2008 10:30:11 +0000 Subject: - Fixed several bugs with tabbed browsing (Tabs: on) which occurred after TSong was changed from a record to a class. - Replaced BubbleSort with MergeSort for song sorting (QuickSort is not applicable here because it is instable) - Added a constructor to TSong for Category-Buttons (this is a bad solution because category-buttons are not songs, a common super-class TCatItem would be nicer) - Some cleanup git-svn-id: svn://svn.code.sf.net/p/ultrastardx/svn/trunk@1039 b956fd51-792f-4845-bead-9b4dfca2ff2c --- Game/Code/Classes/UCommon.pas | 87 ++++++ Game/Code/Classes/USong.pas | 34 +-- Game/Code/Classes/USongs.pas | 651 +++++++++++++++++------------------------- 3 files changed, 364 insertions(+), 408 deletions(-) (limited to 'Game/Code/Classes') diff --git a/Game/Code/Classes/UCommon.pas b/Game/Code/Classes/UCommon.pas index 5af018b7..1872b789 100644 --- a/Game/Code/Classes/UCommon.pas +++ b/Game/Code/Classes/UCommon.pas @@ -67,6 +67,9 @@ function IsAlphaNumericChar(ch: WideChar): boolean; function IsPunctuationChar(ch: WideChar): boolean; function IsControlChar(ch: WideChar): boolean; +// A stable alternative to TList.Sort() (use TList.Sort() if applicable, see below) +procedure MergeSort(List: TList; CompareFunc: TListSortCompare); + implementation @@ -613,6 +616,90 @@ begin end; end; +(* + * Recursive part of the MergeSort algorithm. + * OutList will be either InList or TempList and will be swapped in each + * depth-level of recursion. By doing this it we can directly merge into the + * output-list. If we only had In- and OutList parameters we had to merge into + * InList after the recursive calls and copy the data to the OutList afterwards. + *) +function _MergeSort(InList, TempList, OutList: TList; StartPos, BlockSize: integer; + CompareFunc: TListSortCompare): TList; +var + LeftSize, RightSize: integer; // number of elements in left/right block + LeftEnd, RightEnd: integer; // Index after last element in left/right block + MidPos: integer; // index of first element in right block + Pos: integer; // position in output list +begin + LeftSize := BlockSize div 2; + RightSize := BlockSize - LeftSize; + MidPos := StartPos + LeftSize; + + // sort left and right halves of this block by recursive calls of this function + if (LeftSize >= 2) then + _MergeSort(InList, OutList, TempList, StartPos, LeftSize, CompareFunc) + else + TempList[StartPos] := InList[StartPos]; + if (RightSize >= 2) then + _MergeSort(InList, OutList, TempList, MidPos, RightSize, CompareFunc) + else + TempList[MidPos] := InList[MidPos]; + + // merge sorted left and right sub-lists into output-list + LeftEnd := MidPos; + RightEnd := StartPos + BlockSize; + Pos := StartPos; + while ((StartPos < LeftEnd) and (MidPos < RightEnd)) do + begin + if (CompareFunc(TempList[StartPos], TempList[MidPos]) <= 0) then + begin + OutList[Pos] := TempList[StartPos]; + Inc(StartPos); + end + else + begin + OutList[Pos] := TempList[MidPos]; + Inc(MidPos); + end; + Inc(Pos); + end; + + // copy remaining elements to output-list + while (StartPos < LeftEnd) do + begin + OutList[Pos] := TempList[StartPos]; + Inc(StartPos); + Inc(Pos); + end; + while (MidPos < RightEnd) do + begin + OutList[Pos] := TempList[MidPos]; + Inc(MidPos); + Inc(Pos); + end; +end; + +(* + * Stable alternative to the instable TList.Sort() (uses QuickSort) implementation. + * A stable sorting algorithm preserves preordered items. E.g. if sorting by + * songs by title first and artist afterwards, the songs of each artist will + * be ordered by title. In contrast to this an unstable algorithm (like QuickSort) + * may destroy an existing order, so the songs of an artist will not be ordered + * by title anymore after sorting by artist in the previous example. + * If you do not need a stable algorithm, use TList.Sort() instead. + *) +procedure MergeSort(List: TList; CompareFunc: TListSortCompare); +var + TempList: TList; +begin + TempList := TList.Create(); + TempList.Count := List.Count; + if (List.Count >= 2) then + _MergeSort(List, TempList, List, 0, List.Count, CompareFunc); + TempList.Free; +end; + + initialization InitConsoleOutput(); diff --git a/Game/Code/Classes/USong.pas b/Game/Code/Classes/USong.pas index 66169ef0..3c365720 100644 --- a/Game/Code/Classes/USong.pas +++ b/Game/Code/Classes/USong.pas @@ -63,10 +63,10 @@ type FileName: widestring; // sorting methods - Category: array of widestring; // I think I won't need this + Category: array of widestring; // TODO: do we need this? Genre: widestring; Edition: widestring; - Language: widestring; // 0.5.0: new + Language: widestring; Title: widestring; Artist: widestring; @@ -80,7 +80,7 @@ type Background: widestring; Video: widestring; VideoGAP: real; - VideoLoaded: boolean; // 0.5.0: true if the video has been loaded + VideoLoaded: boolean; // true if the video has been loaded NotesGAP: integer; Start: real; // in seconds Finish: integer; // in miliseconds @@ -98,19 +98,20 @@ type OrderTyp: integer; // type of sorting for this button (0=name) CatNumber: integer; // Count of Songs in Category for Cats and Number of Song in Category for Songs - SongFile: TextFile; // all procedures in this unit operates on this file + SongFile: TextFile; // all procedures in this unit operate on this file Base : array[0..1] of integer; Rel : array[0..1] of integer; Mult : integer; MultBPM : integer; - constructor create ( const aFileName : WideString ); + constructor Create (); overload; + constructor Create ( const aFileName : WideString ); overload; function LoadSong: boolean; function LoadXMLSong: boolean; function Analyse(): boolean; function AnalyseXML(): boolean; - procedure clear(); + procedure Clear(); end; implementation @@ -121,42 +122,33 @@ uses UMusic, //needed for Lines UMain; //needed for Player -constructor TSong.create( const aFileName : WideString ); +constructor TSong.Create(); begin +end; +constructor TSong.Create( const aFileName : WideString ); +begin Mult := 1; - MultBPM := 4; - - fFileName := aFileName; - if fileexists( aFileName ) then - begin - self.Path := ExtractFilePath( aFileName ); self.Folder := ExtractFilePath( aFileName ); self.FileName := ExtractFileName( aFileName ); - -(* - + (* if ReadTXTHeader( aFileName ) then - begin - LoadSong(); - end else begin Log.LogError('Error Loading SongHeader, abort Song Loading'); Exit; end; -*) + *) end; - end; //Load TXT Song diff --git a/Game/Code/Classes/USongs.pas b/Game/Code/Classes/USongs.pas index df748e74..fd9accb5 100644 --- a/Game/Code/Classes/USongs.pas +++ b/Game/Code/Classes/USongs.pas @@ -53,7 +53,6 @@ type Length: string; end; - {$IFDEF USE_PSEUDO_THREAD} TSongs = class( TPseudoThread ) {$ELSE} @@ -72,7 +71,6 @@ type protected procedure Execute; override; public -// Song : array of TSong; // array of songs SongList : TList; // array of songs Selected : integer; // selected song index constructor create(); @@ -96,8 +94,8 @@ type CatNumShow: integer; // Category Number being seen CatCount: integer; //Number of Categorys + procedure SortSongs(); procedure Refresh; // refreshes arrays by recreating them from Songs array -// procedure Sort(Order: integer); procedure ShowCategory(Index: integer); // expands all songs in category procedure HideCategory(Index: integer); // hides all songs in category procedure ClickCategoryButton(Index: integer); // uses ShowCategory and HideCategory when needed @@ -197,8 +195,6 @@ begin end; procedure TSongs.int_LoadSongList; -const - cUSNGPath = '/usr/share/games/ultrastar-ng/songs'; begin try fProcessing := true; @@ -211,12 +207,6 @@ begin if UserSongPath <> SongPath then BrowseDir(UserSongPath); -(* - if ( cUSNGPath <> SongPath ) AND - ( cUSNGPath <> UserSongPath ) then - BrowseDir( cUSNGPath ); // todo : JB this is REAL messy, -*) // we should have some sort of path manager that lets us specify X number of extra paths to search - if assigned( CatSongs ) then CatSongs.Refresh; @@ -317,112 +307,69 @@ begin end; +(* + * Comparison functions for sorting + *) + +function CompareByEdition(Song1, Song2: Pointer): integer; +begin + Result := CompareText(TSong(Song1).Edition, TSong(Song2).Edition); +end; + +function CompareByGenre(Song1, Song2: Pointer): integer; +begin + Result := CompareText(TSong(Song1).Genre, TSong(Song2).Genre); +end; + +function CompareByTitle(Song1, Song2: Pointer): integer; +begin + Result := CompareText(TSong(Song1).Title, TSong(Song2).Title); +end; + +function CompareByArtist(Song1, Song2: Pointer): integer; +begin + Result := CompareText(TSong(Song1).Artist, TSong(Song2).Artist); +end; + +function CompareByFolder(Song1, Song2: Pointer): integer; +begin + Result := CompareText(TSong(Song1).Folder, TSong(Song2).Folder); +end; + +function CompareByLanguage(Song1, Song2: Pointer): integer; +begin + Result := CompareText(TSong(Song1).Language, TSong(Song2).Language); +end; + procedure TSongs.Sort(Order: integer); var - S: integer; - S2: integer; - TempSong: TSong; + CompareFunc: TListSortCompare; begin + // FIXME: what is the difference between artist and artist2, etc.? case Order of sEdition: // by edition - begin - for S2 := 0 to SongList.Count -1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Edition, TSong( SongList[S-1] ).Edition) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; + CompareFunc := CompareByEdition; sGenre: // by genre - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Genre, TSong( SongList[S-1] ).Genre) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; + CompareFunc := CompareByGenre; sTitle: // by title - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Title, TSong( SongList[S-1] ).Title) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - - end; + CompareFunc := CompareByTitle; sArtist: // by artist - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Artist, TSong( SongList[S-1] ).Artist) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; + CompareFunc := CompareByArtist; sFolder: // by folder - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Folder, TSong( SongList[S-1] ).Folder) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; + CompareFunc := CompareByFolder; sTitle2: // by title2 - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Title, TSong( SongList[S-1] ).Title) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - - end; + CompareFunc := CompareByTitle; sArtist2: // by artist2 - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Artist, TSong( SongList[S-1] ).Artist) < 0 then - begin - // zamiana miejscami - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; + CompareFunc := CompareByArtist; sLanguage: // by Language - begin - for S2 := 0 to SongList.Count-1 do - for S := 1 to SongList.Count-1 do - if CompareText(TSong( SongList[S] ).Language, TSong( SongList[S-1] ).Language) < 0 then - begin - TempSong := SongList[S-1]; - SongList[S-1] := SongList[S]; - SongList[S] := TempSong; - end; - end; - + CompareFunc := CompareByLanguage; end; // case + + // Note: Do not use TList.Sort() as it uses QuickSort which is instable. + // For example, if a list is sorted by title first and + // by artist afterwards, the songs of an artist will not be sorted by title anymore. + // The stable MergeSort guarantees to maintain this order. + MergeSort(SongList, CompareFunc); end; function TSongs.FindSongFile(Dir, Mask: widestring): widestring; @@ -436,315 +383,245 @@ begin FindClose(SR); end; -procedure TCatSongs.Refresh; -var - S: integer; // temporary song index - CatLen: integer; // length of CatSongs.Song - Letter: char; // current letter for sorting using letter - SS: string; // current edition for sorting using edition, genre etc. - Order: integer; // number used for ordernum - Letter2: char; // - CatNumber:integer; // Number of Song in Category +procedure TCatSongs.SortSongs(); begin - CatNumShow := -1; -// Songs.Sort(0); // by title - -case Ini.Sorting of + case Ini.Sorting of sEdition: begin - Songs.Sort(sArtist); - Songs.Sort(sEdition); - end; + Songs.Sort(sTitle); + Songs.Sort(sArtist); + Songs.Sort(sEdition); + end; sGenre: begin - Songs.Sort(sArtist); - Songs.Sort(sGenre); - end; + Songs.Sort(sTitle); + Songs.Sort(sArtist); + Songs.Sort(sGenre); + end; sLanguage: begin - Songs.Sort(sArtist); - Songs.Sort(sLanguage); - end; - sFolder: begin - Songs.Sort(sArtist); - Songs.Sort(sFolder); - end; - sTitle: Songs.Sort(sTitle); - sArtist: Songs.Sort(sArtist); - sTitle2: Songs.Sort(sTitle2); // by title2 - sArtist2: Songs.Sort(sArtist2); // by artist2 - + Songs.Sort(sTitle); + Songs.Sort(sArtist); + Songs.Sort(sLanguage); + end; + sFolder: begin + Songs.Sort(sTitle); + Songs.Sort(sArtist); + Songs.Sort(sFolder); + end; + sTitle: begin + Songs.Sort(sTitle); + end; + sArtist: begin + Songs.Sort(sTitle); + Songs.Sort(sArtist); + end; + sTitle2: begin + Songs.Sort(sArtist2); + Songs.Sort(sTitle2); + end; + sArtist2: begin + Songs.Sort(sTitle2); + Songs.Sort(sArtist2); + end; end; // case +end; + +procedure TCatSongs.Refresh; +var + SongIndex: integer; + CurSong: TSong; + CatIndex: integer; // index of current song in Song + Letter: char; // current letter for sorting using letter + CurCategory: string; // current edition for sorting using edition, genre etc. + Order: integer; // number used for ordernum + LetterTmp: char; + CatNumber: integer; // Number of Song in Category + + procedure AddCategoryButton(const CategoryName: string); + var + PrevCatBtnIndex: integer; + begin + Inc(Order); + CatIndex := Length(Song); + SetLength(Song, CatIndex+1); + Song[CatIndex] := TSong.Create(); + Song[CatIndex].Artist := '[' + CategoryName + ']'; + Song[CatIndex].Main := true; + Song[CatIndex].OrderTyp := 0; + Song[CatIndex].OrderNum := Order; + Song[CatIndex].Cover := CatCovers.GetCover(Ini.Sorting, CategoryName); + Song[CatIndex].Visible := true; + + // set number of songs in previous category + PrevCatBtnIndex := CatIndex - CatNumber - 1; + if ((PrevCatBtnIndex >= 0) and Song[PrevCatBtnIndex].Main) then + Song[PrevCatBtnIndex].CatNumber := CatNumber; + + CatNumber := 0; + end; +begin + CatNumShow := -1; + + SortSongs(); - Letter := ' '; - SS := ''; + CurCategory := ''; Order := 0; CatNumber := 0; - //Songs leeren - SetLength (Song, 0); + // Note: do NOT set Letter to ' ', otherwise no category-button will be + // created for songs beginning with ' ' if songs of this category exist. + // TODO: trim song-properties so ' ' will not occur as first chararcter. + Letter := #0; + + // clear song-list + for SongIndex := 0 to Songs.SongList.Count-1 do + begin + // free category buttons + // Note: do NOT delete songs, they are just references to Songs.SongList entries + CurSong := TSong(Songs.SongList[SongIndex]); + if (CurSong.Main) then + CurSong.Free; + end; + SetLength(Song, 0); - for S := 0 to Songs.SongList.Count-1 do + for SongIndex := 0 to Songs.SongList.Count-1 do begin + CurSong := TSong(Songs.SongList[SongIndex]); + // if tabs are on, add section buttons for each new section if (Ini.Tabs = 1) then - if (Ini.Sorting = sEdition) and (CompareText(SS, TSong( Songs.SongList[S] ).Edition) <> 0) then begin - // add Category Button - Inc(Order); - SS := TSong( Songs.SongList[S] ).Edition; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + SS + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - - - // 0.4.3 - // if SS = 'Singstar' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Part 2' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar German' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Spanish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Italian' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar French' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar.jpg'; - // if SS = 'Singstar Party' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Party.jpg'; - // if SS = 'Singstar Popworld' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Popworld.jpg'; - // if SS = 'Singstar 80s' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg'; - // if SS = 'Singstar 80s Polish' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar 80s.jpg'; - // if SS = 'Singstar Rocks' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Rocks.jpg'; - // if SS = 'Singstar Anthems' then CatSongs.Song[CatLen].Cover := CoversPath + 'Singstar Anthems.jpg'; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';//} - - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then + begin + if (Ini.Sorting = sEdition) and + (CompareText(CurCategory, CurSong.Edition) <> 0) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; + CurCategory := CurSong.Edition; + + // TODO: remove this block if it is not needed anymore + { + if CurSection = 'Singstar Part 2' then CoverName := 'Singstar'; + if CurSection = 'Singstar German' then CoverName := 'Singstar'; + if CurSection = 'Singstar Spanish' then CoverName := 'Singstar'; + if CurSection = 'Singstar Italian' then CoverName := 'Singstar'; + if CurSection = 'Singstar French' then CoverName := 'Singstar'; + if CurSection = 'Singstar 80s Polish' then CoverName := 'Singstar 80s'; + } + + // add Category Button + AddCategoryButton(CurCategory); + end - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sGenre) and (CompareText(SS, TSong( Songs.SongList[S] ).Genre) <> 0) then begin - // add Genre Button - Inc(Order); - SS := TSong( Songs.SongList[S] ).Genre; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := SS; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then + else if (Ini.Sorting = sGenre) and + (CompareText(CurCategory, CurSong.Genre) <> 0) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; + CurCategory := CurSong.Genre; + // add Genre Button + AddCategoryButton(CurCategory); + end - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sLanguage) and (CompareText(SS, TSong( Songs.SongList[S] ).Language) <> 0) then begin - // add Language Button - Inc(Order); - SS := TSong( Songs.SongList[S] ).Language; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := SS; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then + else if (Ini.Sorting = sLanguage) and + (CompareText(CurCategory, CurSong.Language) <> 0) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; + CurCategory := CurSong.Language; + // add Language Button + AddCategoryButton(CurCategory); + end - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sTitle) and - (Length(TSong( Songs.SongList[S] ).Title)>=1) and - (Letter <> UpperCase(TSong( Songs.SongList[S] ).Title)[1]) then begin - // add a letter Category Button - Inc(Order); - Letter := Uppercase(TSong( Songs.SongList[S] ).Title)[1]; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - - {// cover-patch - if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then + else if (Ini.Sorting = sTitle) and + (Length(CurSong.Title) >= 1) and + (Letter <> UpperCase(CurSong.Title)[1]) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; + Letter := Uppercase(CurSong.Title)[1]; + // add a letter Category Button + AddCategoryButton(Letter); + end - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sArtist) and (Length(TSong( Songs.SongList[S] ).Artist)>=1) and - (Letter <> UpperCase(TSong( Songs.SongList[S] ).Artist)[1]) then begin - // add a letter Category Button - Inc(Order); - Letter := UpperCase(TSong( Songs.SongList[S] ).Artist)[1]; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then + else if (Ini.Sorting = sArtist) and + (Length(CurSong.Artist) >= 1) and + (Letter <> UpperCase(CurSong.Artist)[1]) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; + Letter := UpperCase(CurSong.Artist)[1]; + // add a letter Category Button + AddCategoryButton(Letter); + end - CatSongs.Song[CatLen].Visible := true; - end - - else if (Ini.Sorting = sFolder) and (CompareText(SS, TSong( Songs.SongList[S] ).Folder) <> 0) then begin - // 0.5.0: add folder tab - Inc(Order); - SS := TSong( Songs.SongList[S] ).Folder; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := SS; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + SS + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + SS + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, SS); - - //CatNumber Patch - if (SS <> '') then + else if (Ini.Sorting = sFolder) and + (CompareText(CurCategory, CurSong.Folder) <> 0) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; - - CatSongs.Song[CatLen].Visible := true; - end + CurCategory := CurSong.Folder; + // add folder tab + AddCategoryButton(CurCategory); + end - else if (Ini.Sorting = sTitle2) AND (Length(TSong( Songs.SongList[S] ).Title)>=1) then begin - if (ord(TSong( Songs.SongList[S] ).Title[1]) > 47) and (ord(TSong( Songs.SongList[S] ).Title[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(TSong( Songs.SongList[S] ).Title)[1]; - if (Letter <> Letter2) then begin - // add a letter Category Button - Inc(Order); - Letter := Letter2; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + 'Title' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Title' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then + else if (Ini.Sorting = sTitle2) and + (Length(CurSong.Title) >= 1) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; - end; + // pack all numbers into a category named '#' + if (CurSong.Title[1] >= '0') and (CurSong.Title[1] <= '9') then + LetterTmp := '#' + else + LetterTmp := UpperCase(CurSong.Title)[1]; - CatSongs.Song[CatLen].Visible := true; - end; - end + if (Letter <> LetterTmp) then + begin + Letter := LetterTmp; + // add a letter Category Button + AddCategoryButton(Letter); + end; + end - else if (Ini.Sorting = sArtist2) AND (Length(TSong( Songs.SongList[S] ).Artist)>=1) then begin - if (ord(TSong( Songs.SongList[S] ).Artist[1]) > 47) and (ord(TSong( Songs.SongList[S] ).Artist[1]) < 58) then Letter2 := '#' else Letter2 := UpperCase(TSong( Songs.SongList[S] ).Artist)[1]; - if (Letter <> Letter2) then begin - // add a letter Category Button - Inc(Order); - Letter := Letter2; - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); - CatSongs.Song[CatLen].Artist := '[' + Letter + ']'; - CatSongs.Song[CatLen].Main := true; - CatSongs.Song[CatLen].OrderTyp := 0; -// Order := ord(Letter); - CatSongs.Song[CatLen].OrderNum := Order; - - {// cover-patch - if FileExists(CoversPath + 'Artist' + Letter + '.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'Artist' + Letter + '.jpg' - else if FileExists(CoversPath + 'NoCover.jpg') then CatSongs.Song[CatLen].Cover := CoversPath + 'NoCover.jpg';} - CatSongs.Song[CatLen].Cover := CatCovers.GetCover(Ini.Sorting, Letter); - - //CatNumber Patch - if (Letter <> ' ') then + else if (Ini.Sorting = sArtist2) and + (Length(CurSong.Artist)>=1) then + begin + // pack all numbers into a category named '#' + if (CurSong.Artist[1] >= '0') and (CurSong.Artist[1] <= '9') then + LetterTmp := '#' + else + LetterTmp := UpperCase(CurSong.Artist)[1]; + + if (Letter <> LetterTmp) then begin - Song[CatLen - CatNumber - 1].CatNumber := CatNumber;//Set CatNumber of Categroy - CatNumber := 0; + Letter := LetterTmp; + // add a letter Category Button + AddCategoryButton(Letter); end; - - CatSongs.Song[CatLen].Visible := true; end; end; + CatIndex := Length(Song); + SetLength(Song, CatIndex+1); - CatLen := Length(CatSongs.Song); - SetLength(CatSongs.Song, CatLen+1); + Inc(CatNumber); // increase number of songs in category - Inc (CatNumber); //Increase Number in Cat + // copy reference to current song + Song[CatIndex] := CurSong; - CatSongs.Song[CatLen] := TSong( Songs.SongList[S] ); - CatSongs.Song[CatLen].OrderNum := Order; // assigns category - CatSongs.Song[CatLen].CatNumber := CatNumber; + // set song's category info + CurSong.OrderNum := Order; // assigns category + CurSong.CatNumber := CatNumber; - if (Ini.Tabs = 0) then CatSongs.Song[CatLen].Visible := true - else if (Ini.Tabs = 1) then CatSongs.Song[CatLen].Visible := false; -// if (Ini.Tabs = 1) and (Order = 1) then CatSongs.Song[CatLen].Visible := true; // open first tab -//CatSongs.Song[CatLen].Visible := true; + if (Ini.Tabs = 0) then + CurSong.Visible := true + else if (Ini.Tabs = 1) then + CurSong.Visible := false; + { + if (Ini.Tabs = 1) and (Order = 1) then + begin + //open first tab + CurSong.Visible := true; + end; + CurSong.Visible := true; + } + end; + // set CatNumber of last category + if (Ini.Tabs_at_startup = 1) and (High(Song) >= 1) then + begin + // set number of songs in previous category + SongIndex := CatIndex - CatNumber; + if ((SongIndex >= 0) and Song[SongIndex].Main) then + Song[SongIndex].CatNumber := CatNumber; end; -//CatNumber Patch - Set CatNumber of Last Category -if (ini.Tabs_at_startup = 1) And (high(Song) >=1) then - Song[CatLen - CatNumber].CatNumber := CatNumber;//Set CatNumber of Categroy -//CatCount Patch -CatCount := Order; + + // update number of categories + CatCount := Order; end; procedure TCatSongs.ShowCategory(Index: integer); @@ -754,7 +631,7 @@ begin CatNumShow := Index; for S := 0 to high(CatSongs.Song) do begin - if (CatSongs.Song[S].OrderNum = Index) AND (Not CatSongs.Song[S].Main) then + if (CatSongs.Song[S].OrderNum = Index) and (not CatSongs.Song[S].Main) then CatSongs.Song[S].Visible := true else CatSongs.Song[S].Visible := false; @@ -777,9 +654,9 @@ var begin Num := CatSongs.Song[Index].OrderNum; if Num <> CatNumShow then - begin + begin ShowCategory(Num); - end + end else begin ShowCategoryList; end; @@ -806,18 +683,18 @@ end; function TCatSongs.FindNextVisible(SearchFrom:integer): integer;//Find next Visible Song var I: Integer; - begin +begin Result := -1; I := SearchFrom + 1; while not CatSongs.Song[I].Visible do - begin + begin Inc (I); if (I>high(CatSongs.Song)) then I := low(CatSongs.Song); if (I = SearchFrom) then //Make One Round and no song found->quit break; - end; end; +end; //Wrong song selected when tabs on bug End function TCatSongs.VisibleSongs: integer; @@ -842,7 +719,7 @@ function TCatSongs.SetFilter(FilterStr: String; const fType: Byte): Cardinal; var I, J: Integer; cString: String; - SearchStr: Array of String; + SearchStr: array of String; begin {fType: 0: All 1: Title @@ -853,18 +730,18 @@ begin //Create Search Array SetLength(SearchStr, 1); I := Pos (' ', FilterStr); - While (I <> 0) do + while (I <> 0) do begin SetLength (SearchStr, Length(SearchStr) + 1); cString := Copy(FilterStr, 1, I-1); - if (cString <> ' ') AND (cString <> '') then + 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 + if (FilterStr <> ' ') and (FilterStr <> '') then SearchStr[High(SearchStr)] := FilterStr; for I:=0 to High(Song) do begin @@ -877,9 +754,9 @@ begin end; Song[i].Visible:=True; //Look for every Searched Word - For J := 0 to High(SearchStr) do + for J := 0 to High(SearchStr) do begin - Song[i].Visible := Song[i].Visible AND AnsiContainsText(cString, SearchStr[J]) + Song[i].Visible := Song[i].Visible and AnsiContainsText(cString, SearchStr[J]) end; if Song[i].Visible then Inc(Result); @@ -891,7 +768,7 @@ begin end else begin for i:=0 to High(Song) do begin - Song[i].Visible:=(Ini.Tabs=1)=Song[i].Main; + Song[i].Visible := (Ini.Tabs=1) = Song[i].Main; CatNumShow := -1; end; Result := 0; -- cgit v1.2.3