Improve song selection screen (#932)

* Redesign song selection screen

* Fix SonarCloud issues

* Add TileCaption to SConfig test file

---------

Co-authored-by: Florian Ostertag <flokuep@users.noreply.github.com>
This commit is contained in:
McSchneidarandFlorian Ostertag authored and GitHub committed 2026-10-21 10:25:40 +02:00
1 parent 6601f41aac
commit 74653ab977
19 files changed
+1710 -345

No files matched your search

+4
View File
@@ -217,6 +217,10 @@
<string name="TR_SCREENSONG_NEWPLAYLIST">New playlist</string>
<string name="TR_SCREENSONG_SONGOPTIONS">Song Options</string>
<string name="TR_SCREENSONG_LENGTH">Song length</string>
<string name="TR_SCREENSONG_YEAR">Year</string>
<string name="TR_SCREENSONG_TIMESPLAYED">Times sung</string>
<string name="TR_SCREENSONG_OPTIONSSELECTION">Selection</string>
<string name="TR_SCREENSONG_OPTIONSSINGALL">Sing all</string>
<string name="TR_SCREENSONG_AUDIOMODE">Audio mode</string>
<string name="TR_SCREENSONG_PLAYLIST">Playlist</string>
<string name="TR_SCREENSONG_PLAYERSELECT">Player selection</string>
@@ -1,8 +1,31 @@
ScreenSong
++++++++++
Version 16:
Add (optional):
<StaticScrollBar> and <StaticScrollBarThumb> to SongMenu.SongMenuTileBoard and SongMenu.SongMenuList (position relative to TileRect, moved with TileRectSmall)
<StaticTileCaptionBG>, <TextTileArtist> and <TextTileTitle> to SongMenu.SongMenuTileBoard (caption on the selected tile, coordinates relative to the tile)
Add:
<StaticOptionsCover>, <TextOptionsSongTitle> and <TextOptionsSongArtist> (song header of the song options)
<StaticOptionsGroupGame>, <StaticOptionsGroupAudio>, <StaticOptionsGroupPlayer> and <StaticOptionsGroupPlaylist> (groups of the song options, using the new skin <OptionsGroupSmall>)
<StaticOptionsGroupRandom>, <StaticOptionsGroupPlaylistOpen>, <StaticOptionsGroupSingAll>, <StaticOptionsGroupSingAllSingle>, <StaticOptionsGroupRandomMedley> and <StaticOptionsGroupMedley> (groups of the general and medley options, using the new skins <OptionsGroupSmall> and <OptionsGroupLarge>)
<TextOptionsGeneralSelection>, <TextOptionsGeneralPlaylist>, <TextOptionsGeneralSingAll> and <TextOptionsGeneralMedley> (headings of the general options)
<StaticOptionsIconSing>, <StaticOptionsIconGame>, <StaticOptionsIconAudio>, <StaticOptionsIconPlayer>, <StaticOptionsIconPlaylist>, <StaticOptionsIconAdd>, <StaticOptionsIconHighscore> and <StaticOptionsIconClose> (icons of the song options)
<StaticInfoYear>, <StaticInfoLength>, <StaticInfoHighscore>, <StaticInfoPlayed> and <StaticInfoIcons> (info tiles and icon bar below the cover, using the new skins <InfoTile> and <InfoBar>)
<TextInfoYear>, <TextInfoLength>, <TextInfoHighscore>, <TextInfoPlayed>, <TextInfoHighscoreValue> and <TextInfoPlayedValue> (labels and values of the info tiles)
Change:
SongMenu.SongMenuList shows title and artist in two lines (artist first if sorted by artist letter), the selected row is shown larger (ListLength 12, SpaceH 4)
SongMenu: TextTitle and TextArtist are shown in a bar at the bottom of the cover, TextSongYear and TextSongLength are shown in the info tiles
StaticOptionsBG covers the whole left column, the preview of the song menu is hidden while the song options are shown
Fix:
<InstrumentalIcon> skin name in SongMenu
++++++++++
Version 15:
(2026 Oct 16)
Add:
<SelectSlideAudioMode> in <Playlist> (audio mode for each playlist entry, only shown if the song has an instrumental file)
@@ -339,6 +339,10 @@
<CoverTile>CoverTile.png</CoverTile>
<PlayerTile>PlayerTile.png</PlayerTile>
<CoverTextBackground>CoverTextBackground.png</CoverTextBackground>
<InfoTile>InfoTile.png</InfoTile>
<InfoBar>InfoBar.png</InfoBar>
<OptionsGroupSmall>OptionsGroupSmall.png</OptionsGroupSmall>
<OptionsGroupLarge>OptionsGroupLarge.png</OptionsGroupLarge>
<Cursor>Cursor.png</Cursor>
<TimeBar>TimeBar.png</TimeBar>
<TimeLine>TimeLine.png</TimeLine>
+4
View File
@@ -339,6 +339,10 @@
<CoverTile>CoverTile.png</CoverTile>
<PlayerTile>PlayerTile.png</PlayerTile>
<CoverTextBackground>CoverTextBackground.png</CoverTextBackground>
<InfoTile>InfoTile.png</InfoTile>
<InfoBar>InfoBar.png</InfoBar>
<OptionsGroupSmall>OptionsGroupSmall.png</OptionsGroupSmall>
<OptionsGroupLarge>OptionsGroupLarge.png</OptionsGroupLarge>
<Cursor>Cursor.png</Cursor>
<TimeBar>TimeBar.png</TimeBar>
<TimeLine>TimeLine.png</TimeLine>
+4
View File
@@ -339,6 +339,10 @@
<CoverTile>CoverTile.png</CoverTile>
<PlayerTile>PlayerTile.png</PlayerTile>
<CoverTextBackground>CoverTextBackground.png</CoverTextBackground>
<InfoTile>InfoTile.png</InfoTile>
<InfoBar>InfoBar.png</InfoBar>
<OptionsGroupSmall>OptionsGroupSmall.png</OptionsGroupSmall>
<OptionsGroupLarge>OptionsGroupLarge.png</OptionsGroupLarge>
<Cursor>Cursor.png</Cursor>
<TimeBar>TimeBar.png</TimeBar>
<TimeLine>TimeLine.png</TimeLine>
+4
View File
@@ -339,6 +339,10 @@
<CoverTile>CoverTile.png</CoverTile>
<PlayerTile>PlayerTile.png</PlayerTile>
<CoverTextBackground>CoverTextBackground.png</CoverTextBackground>
<InfoTile>InfoTile.png</InfoTile>
<InfoBar>InfoBar.png</InfoBar>
<OptionsGroupSmall>OptionsGroupSmall.png</OptionsGroupSmall>
<OptionsGroupLarge>OptionsGroupLarge.png</OptionsGroupLarge>
<Cursor>Cursor.png</Cursor>
<TimeBar>TimeBar.png</TimeBar>
<TimeLine>TimeLine.png</TimeLine>
+4
View File
@@ -339,6 +339,10 @@
<CoverTile>CoverTile.png</CoverTile>
<PlayerTile>PlayerTile.png</PlayerTile>
<CoverTextBackground>CoverTextBackground.png</CoverTextBackground>
<InfoTile>InfoTile.png</InfoTile>
<InfoBar>InfoBar.png</InfoBar>
<OptionsGroupSmall>OptionsGroupSmall.png</OptionsGroupSmall>
<OptionsGroupLarge>OptionsGroupLarge.png</OptionsGroupLarge>
<Cursor>Cursor.png</Cursor>
<TimeBar>TimeBar.png</TimeBar>
<TimeLine>TimeLine.png</TimeLine>
+4
View File
@@ -339,6 +339,10 @@
<CoverTile>CoverTile.png</CoverTile>
<PlayerTile>PlayerTile.png</PlayerTile>
<CoverTextBackground>CoverTextBackground.png</CoverTextBackground>
<InfoTile>InfoTile.png</InfoTile>
<InfoBar>InfoBar.png</InfoBar>
<OptionsGroupSmall>OptionsGroupSmall.png</OptionsGroupSmall>
<OptionsGroupLarge>OptionsGroupLarge.png</OptionsGroupLarge>
<Cursor>Cursor.png</Cursor>
<TimeBar>TimeBar.png</TimeBar>
<TimeLine>TimeLine.png</TimeLine>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 951 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

File diff suppressed because it is too large. Load diff
@@ -71,6 +71,7 @@
<NumPlayers>2</NumPlayers>
<Tabs>TR_CONFIG_OFF</Tabs>
<AutoplayPreviews>TR_CONFIG_OFF</AutoplayPreviews>
<TileCaption>TR_CONFIG_ON</TileCaption>
<AutoplayPreviewDelay>500</AutoplayPreviewDelay>
<LyricsPosition>TR_CONFIG_LYRICSPOSITION_BOTTOM</LyricsPosition>
<MinLineBreakTime>0.1</MinLineBreakTime>
+247 -2
View File
@@ -42,7 +42,7 @@ namespace Vocaluxe.Screens
// Version number for theme files. Increment it, if you've changed something on the theme files!
protected override int _ScreenVersion
{
get { return 15; }
get { return 16; }
}
private const string _TextCategory = "TextCategory";
@@ -58,6 +58,23 @@ namespace Vocaluxe.Screens
private const string _TextOptionsPlayerSelect = "TextOptionsPlayerSelect";
private const string _TextOptionsPlaylist = "TextOptionsPlaylist";
private const string _TextShortInfoTop = "TextShortInfoTop";
private const string _TextOptionsSongTitle = "TextOptionsSongTitle";
private const string _TextOptionsSongArtist = "TextOptionsSongArtist";
private const string _TextOptionsGeneralSelection = "TextOptionsGeneralSelection";
private const string _TextOptionsGeneralPlaylist = "TextOptionsGeneralPlaylist";
private const string _TextOptionsGeneralSingAll = "TextOptionsGeneralSingAll";
private const string _TextOptionsGeneralMedley = "TextOptionsGeneralMedley";
private static readonly string[] _TextsOptionsGeneral =
{
_TextOptionsGeneralSelection, _TextOptionsGeneralPlaylist, _TextOptionsGeneralSingAll, _TextOptionsGeneralMedley
};
private const string _TextInfoYear = "TextInfoYear";
private const string _TextInfoLength = "TextInfoLength";
private const string _TextInfoHighscore = "TextInfoHighscore";
private const string _TextInfoPlayed = "TextInfoPlayed";
private const string _TextInfoHighscoreValue = "TextInfoHighscoreValue";
private const string _TextInfoPlayedValue = "TextInfoPlayedValue";
private const string _ButtonOpenOptions = "ButtonOpenOptions";
private const string _ButtonOptionsSing = "ButtonOptionsSing";
@@ -83,6 +100,42 @@ namespace Vocaluxe.Screens
private const string _StaticSearchBar = "StaticSearchBar";
private const string _StaticOptionsBG = "StaticOptionsBG";
private const string _StaticShortInfoTop = "StaticShortInfoTop";
private const string _StaticOptionsCover = "StaticOptionsCover";
private const string _StaticInfoYear = "StaticInfoYear";
private const string _StaticInfoLength = "StaticInfoLength";
private const string _StaticInfoHighscore = "StaticInfoHighscore";
private const string _StaticInfoPlayed = "StaticInfoPlayed";
private const string _StaticInfoIcons = "StaticInfoIcons";
private const string _StaticOptionsGroupGame = "StaticOptionsGroupGame";
private const string _StaticOptionsGroupAudio = "StaticOptionsGroupAudio";
private const string _StaticOptionsGroupPlayer = "StaticOptionsGroupPlayer";
private const string _StaticOptionsGroupPlaylist = "StaticOptionsGroupPlaylist";
private const string _StaticOptionsIconSing = "StaticOptionsIconSing";
private const string _StaticOptionsIconGame = "StaticOptionsIconGame";
private const string _StaticOptionsIconAudio = "StaticOptionsIconAudio";
private const string _StaticOptionsIconPlayer = "StaticOptionsIconPlayer";
private const string _StaticOptionsIconPlaylist = "StaticOptionsIconPlaylist";
private const string _StaticOptionsIconAdd = "StaticOptionsIconAdd";
private const string _StaticOptionsIconHighscore = "StaticOptionsIconHighscore";
private const string _StaticOptionsIconClose = "StaticOptionsIconClose";
private const string _StaticOptionsGroupRandom = "StaticOptionsGroupRandom";
private const string _StaticOptionsGroupPlaylistOpen = "StaticOptionsGroupPlaylistOpen";
private const string _StaticOptionsGroupSingAll = "StaticOptionsGroupSingAll";
private const string _StaticOptionsGroupSingAllSingle = "StaticOptionsGroupSingAllSingle";
private const string _StaticOptionsGroupRandomMedley = "StaticOptionsGroupRandomMedley";
private const string _StaticOptionsGroupMedley = "StaticOptionsGroupMedley";
private static readonly string[] _StaticsOptionsGeneral =
{
_StaticOptionsGroupRandom, _StaticOptionsGroupPlaylistOpen, _StaticOptionsGroupSingAll, _StaticOptionsGroupSingAllSingle, _StaticOptionsGroupRandomMedley,
_StaticOptionsGroupMedley
};
private static readonly string[] _StaticsOptionsSong =
{
_StaticOptionsGroupGame, _StaticOptionsGroupPlayer, _StaticOptionsGroupPlaylist, _StaticOptionsIconSing, _StaticOptionsIconGame, _StaticOptionsIconPlayer,
_StaticOptionsIconPlaylist, _StaticOptionsIconAdd, _StaticOptionsIconHighscore
};
private const string _SongMenuName = "SongMenu";
private const string _PlaylistName = "Playlist";
@@ -104,6 +157,7 @@ namespace Vocaluxe.Screens
private int _SelectedSongId;
private int _SelectedCategoryIndex;
private int _InfoSongId = -1;
private ISongMenu _SongMenu;
private CPlaylist _Playlist;
@@ -206,8 +260,24 @@ namespace Vocaluxe.Screens
tlist.Add(_TextOptionsPlaylist);
tlist.Add(_TextShortInfoTop);
tlist.Add(_TextOptionsSongTitle);
tlist.Add(_TextOptionsSongArtist);
tlist.AddRange(_TextsOptionsGeneral);
tlist.Add(_TextInfoYear);
tlist.Add(_TextInfoLength);
tlist.Add(_TextInfoHighscore);
tlist.Add(_TextInfoPlayed);
tlist.Add(_TextInfoHighscoreValue);
tlist.Add(_TextInfoPlayedValue);
_ThemeStatics = new string[] { _StaticSearchBar, _StaticOptionsBG, _StaticShortInfoTop };
_ThemeStatics = new string[]
{
_StaticSearchBar, _StaticOptionsBG, _StaticShortInfoTop, _StaticOptionsCover, _StaticInfoYear, _StaticInfoLength, _StaticInfoHighscore, _StaticInfoPlayed,
_StaticInfoIcons, _StaticOptionsGroupGame, _StaticOptionsGroupAudio, _StaticOptionsGroupPlayer, _StaticOptionsGroupPlaylist, _StaticOptionsIconSing,
_StaticOptionsIconGame, _StaticOptionsIconAudio, _StaticOptionsIconPlayer, _StaticOptionsIconPlaylist, _StaticOptionsIconAdd, _StaticOptionsIconHighscore,
_StaticOptionsIconClose, _StaticOptionsGroupRandom, _StaticOptionsGroupPlaylistOpen, _StaticOptionsGroupSingAll, _StaticOptionsGroupSingAllSingle,
_StaticOptionsGroupRandomMedley, _StaticOptionsGroupMedley
};
_ThemeTexts = tlist.ToArray();
_ThemeButtons = blist.ToArray();
_ThemeSelectSlides = new string[]
@@ -897,6 +967,7 @@ namespace Vocaluxe.Screens
_SelectedSongId = -1;
_SelectedCategoryIndex = -2;
_InfoSongId = -1;
_Sso = CParty.GetSongSelectionOptions();
CSongs.Sort(_Sso.Sorting.SongSorting, _Sso.Sorting.Tabs, _Sso.Sorting.IgnoreArticles, _Sso.Sorting.SearchString, _Sso.Sorting.DuetOptions,
@@ -1044,9 +1115,59 @@ namespace Vocaluxe.Screens
}
_UpdatePartyModeOptions();
_UpdateSongInfo();
return true;
}
private void _UpdateSongInfo()
{
CSong song = null;
var songNr = _SongMenu.GetPreviewSongNr();
if (CSongs.IsInCategory && songNr >= 0 && songNr < CSongs.VisibleSongs.Count)
{
song = CSongs.VisibleSongs[songNr];
}
var visible = song != null && _CurSongOptionsView == ESongOptionsView.None;
foreach (var staticName in new[] { _StaticInfoYear, _StaticInfoLength, _StaticInfoHighscore, _StaticInfoPlayed, _StaticInfoIcons })
{
_Statics[staticName].Visible = visible;
}
foreach (var textName in new[] { _TextInfoYear, _TextInfoLength, _TextInfoHighscore, _TextInfoPlayed, _TextInfoHighscoreValue, _TextInfoPlayedValue })
{
_Texts[textName].Visible = visible;
}
if (song == null)
{
return;
}
_Texts[_TextInfoPlayedValue].Text = song.NumPlayed.ToString();
if (song.Id == _InfoSongId)
{
return;
}
if (!CSongs.SongsLoaded)
{
_Texts[_TextInfoHighscoreValue].Text = "-";
return;
}
_InfoSongId = song.Id;
var scores = CDataBase.LoadScore(song.Id, EGameMode.TR_GAMEMODE_NORMAL, EHighscoreStyle.TR_CONFIG_HIGHSCORE_LIST_BEST);
if (scores == null || scores.Count == 0)
{
_Texts[_TextInfoHighscoreValue].Text = "-";
return;
}
var best = scores.OrderByDescending(score => score.Score).First();
_Texts[_TextInfoHighscoreValue].Text = best.Score + " (" + best.Name + ")";
}
private void _PreloadVisibleCovers()
{
if (CSongs.IsInCategory)
@@ -1753,9 +1874,33 @@ namespace Vocaluxe.Screens
_Texts[_TextOptionsAudioMode].Visible = false;
_Texts[_TextOptionsPlayerSelect].Visible = false;
_Texts[_TextOptionsPlaylist].Visible = false;
_Texts[_TextOptionsSongTitle].Visible = false;
_Texts[_TextOptionsSongArtist].Visible = false;
_Statics[_StaticOptionsCover].Visible = false;
foreach (var staticName in _StaticsOptionsSong)
{
_Statics[staticName].Visible = false;
}
_Statics[_StaticOptionsGroupAudio].Visible = false;
_Statics[_StaticOptionsIconAudio].Visible = false;
_Statics[_StaticOptionsIconClose].Visible = false;
_SetSongOptionsOffsetY(0f);
_SetGeneralOptionsOffsetY(0f, 0f);
foreach (var staticName in _StaticsOptionsGeneral)
{
_Statics[staticName].Visible = false;
}
foreach (var textName in _TextsOptionsGeneral)
{
_Texts[textName].Visible = false;
}
_Statics[_StaticOptionsBG].Visible = false;
_Statics[_StaticSearchBar].Visible = !_Sso.Selection.PartyMode;
_Buttons[_ButtonOpenOptions].Visible = true;
_SongMenu.PreviewVisible = true;
if (view == ESongOptionsView.None)
{
@@ -1785,6 +1930,8 @@ namespace Vocaluxe.Screens
_Buttons[_ButtonOptionsClose].Visible = true;
_Statics[_StaticOptionsBG].Visible = true;
_Buttons[_ButtonOpenOptions].Visible = false;
_Statics[_StaticOptionsIconClose].Visible = true;
_SongMenu.PreviewVisible = false;
if (view == ESongOptionsView.Song)
{
_ShowSongOptionsSong();
@@ -1799,6 +1946,54 @@ namespace Vocaluxe.Screens
}
}
private void _SetSongOptionsOffsetY(float offset)
{
_SetOffsetY(offset,
new[]
{
_StaticOptionsGroupPlayer, _StaticOptionsGroupPlaylist, _StaticOptionsIconPlayer, _StaticOptionsIconPlaylist, _StaticOptionsIconAdd,
_StaticOptionsIconHighscore, _StaticOptionsIconClose
},
new[] { _TextOptionsPlayerSelect, _TextOptionsPlaylist },
new[] { _SelectSlideOptionsPlayerSelect, _SelectSlideOptionsPlaylistAdd },
new[] { _ButtonOptionsPlaylist, _ButtonOptionsHighscore, _ButtonOptionsClose });
}
private void _SetGeneralOptionsOffsetY(float singAllOffset, float medleyOffset)
{
_SetOffsetY(singAllOffset, new[] { _StaticOptionsGroupSingAll, _StaticOptionsGroupSingAllSingle }, new[] { _TextOptionsGeneralSingAll }, new string[0],
new[] { _ButtonOptionsSingAll, _ButtonOptionsSingAllVisible });
_SetOffsetY(medleyOffset, new[] { _StaticOptionsGroupRandomMedley }, new[] { _TextOptionsGeneralMedley }, new string[0], new[] { _ButtonOptionsRandomMedley });
}
private static float _GetThemeY(CStatic element)
{
return ((SThemeStatic)element.GetTheme()).Rect.Y;
}
private void _SetOffsetY(float offset, string[] staticNames, string[] textNames, string[] slideNames, string[] buttonNames)
{
foreach (var staticName in staticNames)
{
_Statics[staticName].Y = _GetThemeY(_Statics[staticName]) + offset;
}
foreach (var textName in textNames)
{
_Texts[textName].Y = ((SThemeText)_Texts[textName].GetTheme()).Y + offset;
}
foreach (var slideName in slideNames)
{
_SelectSlides[slideName].Y = ((SThemeSelectSlide)_SelectSlides[slideName].GetTheme()).Rect.Y + offset;
}
foreach (var buttonName in buttonNames)
{
_Buttons[buttonName].Y = ((SThemeButton)_Buttons[buttonName].GetTheme()).Rect.Y + offset;
}
}
private void _CheckAndAddGameMode(EGameMode gameMode)
{
if (CSongs.VisibleSongs[_SongMenu.GetPreviewSongNr()].IsGameModeAvailable(gameMode))
@@ -1866,6 +2061,28 @@ namespace Vocaluxe.Screens
_Buttons[_ButtonOptionsSing].Visible = true;
_Buttons[_ButtonOptionsPlaylist].Visible = true;
_Buttons[_ButtonOptionsHighscore].Visible = true;
_Texts[_TextOptionsTitle].Visible = false;
_Texts[_TextOptionsSongTitle].Text = currentSong.Title;
_Texts[_TextOptionsSongTitle].Visible = true;
_Texts[_TextOptionsSongArtist].Text = currentSong.Artist;
_Texts[_TextOptionsSongArtist].Visible = true;
_Statics[_StaticOptionsCover].Texture = currentSong.CoverTextureSmall;
_Statics[_StaticOptionsCover].Aspect = EAspect.Crop;
_Statics[_StaticOptionsCover].Visible = true;
foreach (var staticName in _StaticsOptionsSong)
{
_Statics[staticName].Visible = true;
}
_Statics[_StaticOptionsGroupAudio].Visible = _SelectSlides[_SelectSlideOptionsAudioMode].Visible;
_Statics[_StaticOptionsIconAudio].Visible = _SelectSlides[_SelectSlideOptionsAudioMode].Visible;
if (!_SelectSlides[_SelectSlideOptionsAudioMode].Visible)
{
_SetSongOptionsOffsetY(_GetThemeY(_Statics[_StaticOptionsGroupAudio]) - _GetThemeY(_Statics[_StaticOptionsGroupPlayer]));
}
_SelectElement(_Buttons[_ButtonOptionsSing]);
_SetSelectSlidePlaylistToCurrentPlaylist();
}
@@ -1895,6 +2112,33 @@ namespace Vocaluxe.Screens
_SelectSlides[_SelectSlideOptionsPlaylistOpen].Visible = true;
}
_Statics[_StaticOptionsGroupRandom].Visible = true;
_Statics[_StaticOptionsGroupPlaylistOpen].Visible = _SelectSlides[_SelectSlideOptionsPlaylistOpen].Visible;
_Statics[_StaticOptionsGroupSingAll].Visible = CSongs.IsInCategory;
_Statics[_StaticOptionsGroupSingAllSingle].Visible = !CSongs.IsInCategory;
_Statics[_StaticOptionsGroupRandomMedley].Visible = true;
foreach (var textName in _TextsOptionsGeneral)
{
_Texts[textName].Visible = true;
}
_Texts[_TextOptionsGeneralPlaylist].Visible = _SelectSlides[_SelectSlideOptionsPlaylistOpen].Visible;
var singAllOffset = 0f;
if (!_SelectSlides[_SelectSlideOptionsPlaylistOpen].Visible)
{
singAllOffset = _GetThemeY(_Statics[_StaticOptionsGroupPlaylistOpen]) - _GetThemeY(_Statics[_StaticOptionsGroupSingAll]);
}
var medleyOffset = singAllOffset;
if (!CSongs.IsInCategory)
{
medleyOffset += ((SThemeStatic)_Statics[_StaticOptionsGroupSingAllSingle].GetTheme()).Rect.H -
((SThemeStatic)_Statics[_StaticOptionsGroupSingAll].GetTheme()).Rect.H;
}
_SetGeneralOptionsOffsetY(singAllOffset, medleyOffset);
// ReSharper disable ConvertIfStatementToConditionalTernaryExpression
if (_Buttons[_ButtonOptionsRandom].Visible)
// ReSharper restore ConvertIfStatementToConditionalTernaryExpression
@@ -1914,6 +2158,7 @@ namespace Vocaluxe.Screens
_Texts[_TextOptionsPlaylist].Visible = false;
_Buttons[_ButtonOptionsStartMedley].Visible = true;
_SelectSlides[_SelectSlideOptionsNumMedleySongs].Visible = true;
_Statics[_StaticOptionsGroupMedley].Visible = true;
_SelectSlides[_SelectSlideOptionsNumMedleySongs].Clear();
if (CSongs.IsInCategory)
{
@@ -15,8 +15,10 @@
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Diagnostics;
using System.Xml.Serialization;
using VocaluxeLib.Draw;
using VocaluxeLib.PartyModes;
namespace VocaluxeLib.Menu.SongMenu
@@ -78,6 +80,9 @@ namespace VocaluxeLib.Menu.SongMenu
public SThemeStatic StaticVideoIcon;
public SThemeStatic StaticMedleyCalcIcon;
public SThemeStatic StaticMedleyTagIcon;
public SThemeStatic? StaticScrollBar;
public SThemeStatic? StaticScrollBarThumb;
}
public struct SThemeSongMenuTileBoard
@@ -129,6 +134,12 @@ namespace VocaluxeLib.Menu.SongMenu
public SThemeStatic StaticVideoIcon;
public SThemeStatic StaticMedleyCalcIcon;
public SThemeStatic StaticMedleyTagIcon;
public SThemeStatic? StaticScrollBar;
public SThemeStatic? StaticScrollBarThumb;
public SThemeStatic? StaticTileCaptionBG;
public SThemeText? TextTileArtist;
public SThemeText? TextTileTitle;
}
public abstract class CSongMenuFramework : CMenuElementBase, ISongMenu
@@ -179,6 +190,11 @@ namespace VocaluxeLib.Menu.SongMenu
protected System.Timers.Timer _AutoplayTimer = new System.Timers.Timer();
protected volatile bool _AutoplayPending = false;
private const float _ScrollDuration = 150f;
private readonly Stopwatch _ScrollTimer = new Stopwatch();
private float _ScrollStart;
private int _ScrollTarget;
private SColorF _ColorInternal;
protected SColorF _Color
{
@@ -191,6 +207,7 @@ namespace VocaluxeLib.Menu.SongMenu
}
public virtual bool SmallView { get; set; }
public bool PreviewVisible { get; set; } = true;
public abstract float SelectedTileZoomFactor { get; }
// This is the nr of the current selection (song or category)
protected virtual int _SelectionNr { get; set; }
@@ -502,6 +519,107 @@ namespace VocaluxeLib.Menu.SongMenu
_AutoplayTimer.Start();
}
protected void _SetScrollTarget(int target, bool animate, int maxDistance)
{
if (!animate)
{
_ScrollTimer.Reset();
_ScrollTarget = target;
return;
}
if (target == _ScrollTarget)
{
return;
}
var start = _GetScrollPosition();
_ScrollStart = start.Clamp((float)(target - maxDistance), target + maxDistance);
_ScrollTarget = target;
_ScrollTimer.Restart();
}
protected float _GetScrollPosition()
{
if (!_ScrollTimer.IsRunning)
{
return _ScrollTarget;
}
var progress = _ScrollTimer.ElapsedMilliseconds / _ScrollDuration;
if (progress >= 1f)
{
_ScrollTimer.Reset();
return _ScrollTarget;
}
var eased = 1f - (1f - progress) * (1f - progress);
return _ScrollStart + (_ScrollTarget - _ScrollStart) * eased;
}
protected bool _IsScrolling()
{
return Math.Abs(_GetScrollPosition() - _ScrollTarget) > 0.001f;
}
protected void _DrawClipped(CTextureRef texture, SRectF rect, SColorF color, EAspect aspect)
{
var top = Math.Max(rect.Y, Rect.Y);
var bottom = Math.Min(rect.Bottom, Rect.Bottom);
if (bottom <= top)
{
return;
}
var bounds = new SRectF(rect.X, top, rect.W, bottom - top, rect.Z);
if (texture == null)
{
CBase.Drawing.DrawRect(color, bounds);
return;
}
CBase.Drawing.DrawTexture(texture, CHelper.FitInBounds(rect, texture.OrigAspect, aspect), color, bounds);
}
protected float _GetVisibleFraction(SRectF rect)
{
if (rect.H <= 0)
{
return 0f;
}
var visible = Math.Min(rect.Bottom, Rect.Bottom) - Math.Max(rect.Y, Rect.Y);
return (visible / rect.H).Clamp(0f, 1f);
}
protected void _DrawScrollBar(CStatic scrollBar, CStatic scrollBarThumb, SRectF normalRect, float position, int numVisible, int numTotal)
{
if (scrollBar == null || numTotal <= numVisible)
{
return;
}
var barTheme = (SThemeStatic)scrollBar.GetTheme();
var track = barTheme.Rect;
track.X += Rect.Right - normalRect.Right;
track.Y += Rect.Y - normalRect.Y;
track.H += Rect.H - normalRect.H;
scrollBar.MaxRect = track;
scrollBar.Draw(EAspect.Stretch);
if (scrollBarThumb == null)
{
return;
}
var thumbTheme = (SThemeStatic)scrollBarThumb.GetTheme();
var thumbH = Math.Min(track.H, Math.Max(track.H * numVisible / numTotal, thumbTheme.Rect.W * 3f));
var progress = (position / (numTotal - numVisible)).Clamp(0f, 1f);
scrollBarThumb.MaxRect = new SRectF(track.X + thumbTheme.Rect.X - barTheme.Rect.X, track.Y + (track.H - thumbH) * progress, thumbTheme.Rect.W, thumbH,
thumbTheme.Rect.Z);
scrollBarThumb.Draw(EAspect.Stretch);
}
#region ThemeEdit
public void MoveElement(int stepX, int stepY)
{
+283 -85
View File
@@ -17,6 +17,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
using VocaluxeLib.Draw;
@@ -30,6 +31,7 @@ namespace VocaluxeLib.Menu.SongMenu
private SRectF _ScrollRect;
private List<CStatic> _Tiles;
private List<CText> _Texts;
private List<CText> _SubTexts;
private List<CStatic> _RowBackgrounds;
private readonly CStatic _CoverBig;
private readonly CStatic _TextBG;
@@ -49,11 +51,21 @@ namespace VocaluxeLib.Menu.SongMenu
private readonly CText _SongLength;
private readonly CText _SongYear;
private readonly CStatic _ScrollBar;
private readonly CStatic _ScrollBarThumb;
private CText _ScrollText;
private CText _ScrollSubText;
private float _SpaceW;
private float _SpaceH;
private int _TileW;
private int _TileH;
private float _TileH;
private const float _SelectedRowScale = 1.3f;
private const float _ExpandDuration = 120f;
private readonly Stopwatch _ExpandTimer = new Stopwatch();
private int _ExpandedNr = -1;
private int _PrevExpandedNr = -1;
private int _ListLength;
@@ -70,7 +82,7 @@ namespace VocaluxeLib.Menu.SongMenu
public override float SelectedTileZoomFactor
{
get { return 1.2f; }
get { return 1f; }
}
protected override int _SelectionNr
@@ -118,6 +130,7 @@ namespace VocaluxeLib.Menu.SongMenu
base._PreviewNr = value;
_UpdatePreview();
_UpdateExpandedRow();
}
}
@@ -141,6 +154,16 @@ namespace VocaluxeLib.Menu.SongMenu
_VocalsIcon = new CStatic(_Theme.SongMenuList.StaticVocalsIcon, _PartyModeId);
_SubElements.AddRange(new IMenuElement[]
{ _Artist, _Title, _SongLength, _SongYear, _DuetIcon, _RapIcon, _VideoIcon, _MedleyCalcIcon, _MedleyTagIcon, _InstrumentalIcon, _VocalsIcon });
if (_Theme.SongMenuList.StaticScrollBar.HasValue)
{
_ScrollBar = new CStatic(_Theme.SongMenuList.StaticScrollBar.Value, _PartyModeId);
}
if (_Theme.SongMenuList.StaticScrollBarThumb.HasValue)
{
_ScrollBarThumb = new CStatic(_Theme.SongMenuList.StaticScrollBarThumb.Value, _PartyModeId);
}
}
private void _ReadSubTheme()
@@ -158,6 +181,16 @@ namespace VocaluxeLib.Menu.SongMenu
_Theme.SongMenuList.StaticVocalsIcon = (SThemeStatic)_VocalsIcon.GetTheme();
_Theme.SongMenuList.StaticTextBG = (SThemeStatic)_TextBG.GetTheme();
_Theme.SongMenuList.StaticVideoIcon = (SThemeStatic)_VideoIcon.GetTheme();
if (_ScrollBar != null)
{
_Theme.SongMenuList.StaticScrollBar = (SThemeStatic)_ScrollBar.GetTheme();
}
if (_ScrollBarThumb != null)
{
_Theme.SongMenuList.StaticScrollBarThumb = (SThemeStatic)_ScrollBarThumb.GetTheme();
}
}
public override object GetTheme()
@@ -178,10 +211,7 @@ namespace VocaluxeLib.Menu.SongMenu
{
MaxRect = SmallView ? _Theme.SongMenuList.TileRectSmall : _Theme.SongMenuList.TileRect;
_TileW = (int)((MaxRect.H - _SpaceH * (_ListLength - 1)) / _ListLength);
_TileH = _TileW;
var _ListTextWidth = MaxRect.W - (_TileW + _SpaceW);
_TileH = (MaxRect.H - _SpaceH * (_ListLength - 1)) / (_ListLength - 1 + _SelectedRowScale);
_CoverBGTexture = CBase.Themes.GetSkinTexture(_Theme.CoverBackground, _PartyModeId);
_CoverBigBGTexture = CBase.Themes.GetSkinTexture(_Theme.CoverBigBackground, _PartyModeId);
@@ -190,58 +220,151 @@ namespace VocaluxeLib.Menu.SongMenu
_RowBackgrounds = new List<CStatic>();
_Tiles = new List<CStatic>();
_Texts = new List<CText>();
_SubTexts = new List<CText>();
for (var i = 0; i < _ListLength; i++)
{
//Create Cover
var y = Rect.Y + i * (_TileH + _SpaceH);
var bgHeight = _TileH + 8f;
var rowRect = new SRectF(Rect.X, y - 4f, Rect.W, bgHeight, Rect.Z + 0.05f);
var rowBackground = new CStatic(_PartyModeId, _CoverBGTexture, _Color, rowRect);
var rowBackground = new CStatic(_PartyModeId, _CoverBGTexture, _Color, Rect);
rowBackground.Color = new SColorF(1f, 1f, 1f, 0f);
_RowBackgrounds.Add(rowBackground);
var rect = new SRectF(Rect.X, y, _TileW, _TileH, Rect.Z);
var rect = new SRectF(Rect.X, Rect.Y, _TileH, _TileH, Rect.Z);
var tile = new CStatic(_PartyModeId, _CoverBGTexture, _Color, rect);
_Tiles.Add(tile);
//Create text
var textRect = new SRectF(MaxRect.X + (_TileW + _SpaceW), y, _ListTextWidth, _TileH, Rect.Z);
var text = new CText(textRect.X, textRect.Y, textRect.Z, textRect.H, textRect.W, EAlignment.Left, EStyle.Normal, "Normal", _Artist.Color, "");
text.MaxRect = new SRectF(text.MaxRect.X, text.MaxRect.Y, MaxRect.W + MaxRect.X - text.Rect.X - 5f, text.MaxRect.H, text.MaxRect.Z);
text.ResizeAlign = EHAlignment.Center;
_Texts.Add(text);
_Texts.Add(_CreateRowText(1f));
_SubTexts.Add(_CreateRowText(0.7f));
}
_ScrollText = _CreateRowText(1f);
_ScrollSubText = _CreateRowText(0.7f);
_ScrollRect = CBase.Settings.GetRenderRect();
_ExpandTimer.Reset();
_PrevExpandedNr = -1;
}
private CText _CreateRowText(float alpha)
{
var color = new SColorF(_Artist.Color.R, _Artist.Color.G, _Artist.Color.B, _Artist.Color.A * alpha);
var text = new CText(Rect.X, Rect.Y, Rect.Z, _TileH, Rect.W, EAlignment.Left, EStyle.Normal, "Normal", color, "");
text.ResizeAlign = EHAlignment.Center;
return text;
}
private float _GetExpandProgress()
{
if (!_ExpandTimer.IsRunning)
{
return 1f;
}
var progress = _ExpandTimer.ElapsedMilliseconds / _ExpandDuration;
if (progress >= 1f)
{
_ExpandTimer.Reset();
_PrevExpandedNr = -1;
return 1f;
}
return 1f - (1f - progress) * (1f - progress);
}
private float _GetRowHeight(int index, float progress)
{
var extra = _TileH * (_SelectedRowScale - 1f);
if (index == _ExpandedNr)
{
return _TileH + extra * progress;
}
if (index == _PrevExpandedNr)
{
return _TileH + extra * (1f - progress);
}
return _TileH;
}
private SRectF _GetRowRect(int index, float position, float progress)
{
var y = Rect.Y + (index - position) * (_TileH + _SpaceH);
for (var i = (int)Math.Floor(position); i < index; i++)
{
y += _GetRowHeight(i, progress) - _TileH;
}
return new SRectF(Rect.X, y, Rect.W, _GetRowHeight(index, progress), Rect.Z);
}
private void _LayoutRowTexts(CText title, CText artist, SRectF row, int index, bool isInCategory)
{
var x = row.X + row.H + _SpaceW;
var w = Rect.Right - x - 5f;
var itemCount = isInCategory ? CBase.Songs.GetNumSongsVisible() : CBase.Songs.GetNumCategories();
if (index >= itemCount)
{
title.Text = "";
artist.Text = "";
return;
}
title.Font.Style = index == _ExpandedNr ? EStyle.Bold : EStyle.Normal;
title.Font.Height = row.H * 0.56f;
title.MaxRect = new SRectF(x, row.Y, w, title.Font.Height, Rect.Z);
title.Text = _GetItemTitle(index, isInCategory);
artist.Font.Height = row.H * 0.42f;
artist.MaxRect = new SRectF(x, row.Y + row.H * 0.56f, w, artist.Font.Height, Rect.Z);
artist.Text = _GetItemSubTitle(index, isInCategory);
}
private void _UpdateRowLayout()
{
var progress = _GetExpandProgress();
var isInCategory = CBase.Songs.IsInCategory();
for (var i = 0; i < _Tiles.Count; i++)
{
var index = i + _Offset;
var row = _GetRowRect(index, _Offset, progress);
_Tiles[i].MaxRect = new SRectF(row.X, row.Y, row.H, row.H, row.Z);
_RowBackgrounds[i].MaxRect = new SRectF(row.X, row.Y - 4f, row.W, row.H + 8f, row.Z + 0.05f);
_RowBackgrounds[i].Color = new SColorF(1f, 1f, 1f, index == _ExpandedNr ? 0.25f : 0f);
_LayoutRowTexts(_Texts[i], _SubTexts[i], row, index, isInCategory);
}
}
private void _UpdateExpandedRow()
{
var expandedNr = _SelectionNr >= 0 ? _SelectionNr : _PreviewNr;
if (expandedNr == _ExpandedNr)
{
return;
}
_PrevExpandedNr = _ExpandedNr;
_ExpandedNr = expandedNr;
_ExpandTimer.Restart();
}
private void _UpdateTileSelection()
{
for (var i = 0; i < _Tiles.Count; i++)
foreach (var tile in _Tiles)
{
_Tiles[i].Selected = false;
if (i < _RowBackgrounds.Count)
{
_RowBackgrounds[i].Color = new SColorF(1f, 1f, 1f, 0f);
}
tile.Selected = false;
}
var tileNr = _SelectionNr - _Offset;
if (tileNr >= 0 && tileNr < _Tiles.Count)
{
_Tiles[tileNr].Selected = true;
if (tileNr < _RowBackgrounds.Count)
{
_RowBackgrounds[tileNr].Color = new SColorF(1f, 1f, 1f, 0.25f);
}
}
_UpdateExpandedRow();
}
public override void Update(SScreenSongOptions songOptions)
@@ -297,14 +420,14 @@ namespace VocaluxeLib.Menu.SongMenu
}
_CoverBig.Texture = category.CoverTextureBig;
_Artist.Text = category.Name;
_Title.Text = category.Name;
return;
}
_CoverBig.Texture = song.CoverTextureBig;
_Artist.Text = song.Artist;
_Title.Text = song.Title;
_SongYear.Text = song.Year;
_SongYear.Text = string.IsNullOrEmpty(song.Year) ? "-" : song.Year;
_DuetIcon.Visible = song.IsDuet;
_RapIcon.Visible = song.IsRap;
_VideoIcon.Visible = song.Video != "";
@@ -325,11 +448,11 @@ namespace VocaluxeLib.Menu.SongMenu
}
_CoverBig.Texture = category.CoverTextureBig;
_Artist.Text = category.Name;
_Title.Text = category.Name;
var num = category.GetNumSongsNotSung();
var songOrSongs = num == 1 ? "TR_SCREENSONG_NUMSONG" : "TR_SCREENSONG_NUMSONGS";
_Title.Text = CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
_Artist.Text = CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
}
}
@@ -651,43 +774,39 @@ namespace VocaluxeLib.Menu.SongMenu
public override void Draw()
{
foreach (var rowBackground in _RowBackgrounds)
if (_IsScrolling())
{
rowBackground.Draw(EAspect.Stretch);
_DrawScrollingList();
}
foreach (var tile in _Tiles)
else
{
if (tile.Selected)
_UpdateRowLayout();
foreach (var rowBackground in _RowBackgrounds)
{
tile.Draw(EAspect.Crop, SelectedTileZoomFactor, -0.1f);
rowBackground.Draw(EAspect.Stretch);
}
else
foreach (var tile in _Tiles)
{
var aspect = tile.Texture != _CoverBGTexture ? EAspect.Crop : EAspect.Stretch;
tile.Draw(aspect);
}
//highlight the text of the selected song
for (var i = 0; i < _Texts.Count; i++)
{
_Texts[i].Draw();
_SubTexts[i].Draw();
}
}
//highlight the text of the selected song
var i = 0;
foreach (var text in _Texts)
{
if (i < _Tiles.Count && _Tiles[i].Selected)
{
text.Font.Style = EStyle.Bold;
}
else if (i < _Tiles.Count)
{
text.Font.Style = EStyle.Normal;
}
else
{
text.Text = "";
}
var itemCount = CBase.Songs.IsInCategory() ? CBase.Songs.GetNumSongsVisible() : CBase.Songs.GetNumCategories();
_DrawScrollBar(_ScrollBar, _ScrollBarThumb, _Theme.SongMenuList.TileRect, _GetScrollPosition(), _ListLength, itemCount);
text.Draw();
i++;
if (!PreviewVisible)
{
return;
}
_TextBG.Draw();
@@ -720,6 +839,93 @@ namespace VocaluxeLib.Menu.SongMenu
}
}
private void _DrawScrollingList()
{
var position = _GetScrollPosition();
var progress = _GetExpandProgress();
var isInCategory = CBase.Songs.IsInCategory();
var itemCount = isInCategory ? CBase.Songs.GetNumSongsVisible() : CBase.Songs.GetNumCategories();
for (var index = Math.Max((int)Math.Floor(position), 0); index < itemCount; index++)
{
var row = _GetRowRect(index, position, progress);
if (row.Y >= Rect.Bottom)
{
break;
}
if (index == _ExpandedNr)
{
_DrawClipped(_CoverBGTexture, new SRectF(row.X, row.Y - 4f, row.W, row.H + 8f, row.Z + 0.05f), new SColorF(1f, 1f, 1f, 0.25f), EAspect.Stretch);
}
var rect = new SRectF(row.X, row.Y, row.H, row.H, row.Z);
_DrawClipped(_GetCoverTexture(index, isInCategory), rect, new SColorF(1f, 1f, 1f, 1f), EAspect.Crop);
_LayoutRowTexts(_ScrollText, _ScrollSubText, row, index, isInCategory);
var visibleFraction = _GetVisibleFraction(rect);
_ScrollText.Alpha = visibleFraction;
_ScrollText.Draw();
_ScrollSubText.Alpha = visibleFraction;
_ScrollSubText.Draw();
}
}
private static CTextureRef _GetCoverTexture(int index, bool isInCategory)
{
return isInCategory ? CBase.Songs.GetVisibleSong(index).CoverTextureSmall : CBase.Songs.GetCategory(index).CoverTextureSmall;
}
private static string _GetItemText(int index, bool isInCategory)
{
if (isInCategory)
{
var song = CBase.Songs.GetVisibleSong(index);
if (CBase.Config.GetSongSorting() == ESongSorting.TR_CONFIG_TITLE_LETTER)
{
return song.Title + " - " + song.Artist;
}
return song.Artist + " - " + song.Title;
}
var category = CBase.Songs.GetCategory(index);
var num = category.GetNumSongsNotSung();
var songOrSongs = num == 1 ? "TR_SCREENSONG_NUMSONG" : "TR_SCREENSONG_NUMSONGS";
return category.Name + " " + CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
}
private static bool _IsSortedByArtistLetter()
{
return CBase.Config.GetSongSorting() == ESongSorting.TR_CONFIG_ARTIST_LETTER;
}
private static string _GetItemTitle(int index, bool isInCategory)
{
if (!isInCategory)
{
return CBase.Songs.GetCategory(index).Name;
}
var song = CBase.Songs.GetVisibleSong(index);
return _IsSortedByArtistLetter() ? song.Artist : song.Title;
}
private static string _GetItemSubTitle(int index, bool isInCategory)
{
if (isInCategory)
{
var song = CBase.Songs.GetVisibleSong(index);
return _IsSortedByArtistLetter() ? song.Title : song.Artist;
}
var num = CBase.Songs.GetCategory(index).GetNumSongsNotSung();
var songOrSongs = num == 1 ? "TR_SCREENSONG_NUMSONG" : "TR_SCREENSONG_NUMSONGS";
return CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
}
public override CStatic GetSelectedSongCover()
{
return _Tiles.FirstOrDefault(tile => tile.Selected);
@@ -734,7 +940,8 @@ namespace VocaluxeLib.Menu.SongMenu
continue;
}
return CHelper.IsInBounds(_Tiles[i].Rect, mEvent) || CHelper.IsInBounds(_Texts[i].Rect, mEvent);
var tileRect = _Tiles[i].Rect;
return CHelper.IsInBounds(new SRectF(tileRect.X, tileRect.Y, Rect.W, tileRect.H, tileRect.Z), mEvent);
}
return false;
@@ -836,42 +1043,31 @@ namespace VocaluxeLib.Menu.SongMenu
return;
}
if (force)
{
_ExpandTimer.Reset();
_ExpandedNr = -1;
_PrevExpandedNr = -1;
}
for (var i = 0; i < _Tiles.Count; i++)
{
if (i + offset < itemCount)
{
_Tiles[i].Color = new SColorF(1f, 1f, 1f, 1f);
if (isInCategory)
{
var currentSong = CBase.Songs.GetVisibleSong(i + offset);
_Tiles[i].Texture = currentSong.CoverTextureSmall;
if (CBase.Config.GetSongSorting() == ESongSorting.TR_CONFIG_TITLE_LETTER)
{
_Texts[i].Text = currentSong.Title + " - " + currentSong.Artist;
}
else
{
_Texts[i].Text = currentSong.Artist + " - " + currentSong.Title;
}
}
else
{
var currentCat = CBase.Songs.GetCategory(i + offset);
_Tiles[i].Texture = currentCat.CoverTextureSmall;
var num = currentCat.GetNumSongsNotSung();
var songOrSongs = num == 1 ? "TR_SCREENSONG_NUMSONG" : "TR_SCREENSONG_NUMSONGS";
_Texts[i].Text = currentCat.Name + " " + CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
}
_Tiles[i].Texture = _GetCoverTexture(i + offset, isInCategory);
_Texts[i].Text = _GetItemText(i + offset, isInCategory);
}
else
{
_Tiles[i].Texture = _CoverBGTexture;
_Tiles[i].Color.A = 0;
_Texts[i].Text = "";
_SubTexts[i].Text = "";
}
}
_SetScrollTarget(offset, !force && offset != _Offset, _ListLength);
_Offset = offset;
_UpdateTileSelection();
}
@@ -886,6 +1082,8 @@ namespace VocaluxeLib.Menu.SongMenu
// Those are drawn seperately so they are not in the above list
_CoverBig.LoadSkin();
_TextBG.LoadSkin();
_ScrollBar?.LoadSkin();
_ScrollBarThumb?.LoadSkin();
base.LoadSkin();
}
+209 -13
View File
@@ -47,6 +47,12 @@ namespace VocaluxeLib.Menu.SongMenu
private CText _SongLength;
private CText _SongYear;
private readonly CStatic _ScrollBar;
private readonly CStatic _ScrollBarThumb;
private readonly CStatic _TileCaptionBG;
private readonly CText _TileArtist;
private readonly CText _TileTitle;
private int _NumW;
private int _NumH;
@@ -62,6 +68,8 @@ namespace VocaluxeLib.Menu.SongMenu
private bool _MouseWasInRect;
private const float _UnfocusedAlpha = 0.85f;
private readonly List<IMenuElement> _SubElements = new List<IMenuElement>();
public override float SelectedTileZoomFactor
@@ -136,6 +144,31 @@ namespace VocaluxeLib.Menu.SongMenu
_VocalsIcon = new CStatic(_Theme.SongMenuTileBoard.StaticVocalsIcon, _PartyModeId);
_SubElements.AddRange(new IMenuElement[]
{ _Artist, _Title, _SongLength, _SongYear, _DuetIcon, _RapIcon, _VideoIcon, _MedleyCalcIcon, _MedleyTagIcon, _InstrumentalIcon, _VocalsIcon });
if (_Theme.SongMenuTileBoard.StaticScrollBar.HasValue)
{
_ScrollBar = new CStatic(_Theme.SongMenuTileBoard.StaticScrollBar.Value, _PartyModeId);
}
if (_Theme.SongMenuTileBoard.StaticScrollBarThumb.HasValue)
{
_ScrollBarThumb = new CStatic(_Theme.SongMenuTileBoard.StaticScrollBarThumb.Value, _PartyModeId);
}
if (_Theme.SongMenuTileBoard.StaticTileCaptionBG.HasValue)
{
_TileCaptionBG = new CStatic(_Theme.SongMenuTileBoard.StaticTileCaptionBG.Value, _PartyModeId);
}
if (_Theme.SongMenuTileBoard.TextTileArtist.HasValue)
{
_TileArtist = new CText(_Theme.SongMenuTileBoard.TextTileArtist.Value, _PartyModeId);
}
if (_Theme.SongMenuTileBoard.TextTileTitle.HasValue)
{
_TileTitle = new CText(_Theme.SongMenuTileBoard.TextTileTitle.Value, _PartyModeId);
}
}
private void _UpdateTileSelection()
@@ -167,6 +200,31 @@ namespace VocaluxeLib.Menu.SongMenu
_Theme.SongMenuTileBoard.StaticVideoIcon = (SThemeStatic)_VideoIcon.GetTheme();
_Theme.SongMenuTileBoard.StaticInstrumentalIcon = (SThemeStatic)_InstrumentalIcon.GetTheme();
_Theme.SongMenuTileBoard.StaticVocalsIcon = (SThemeStatic)_VocalsIcon.GetTheme();
if (_ScrollBar != null)
{
_Theme.SongMenuTileBoard.StaticScrollBar = (SThemeStatic)_ScrollBar.GetTheme();
}
if (_ScrollBarThumb != null)
{
_Theme.SongMenuTileBoard.StaticScrollBarThumb = (SThemeStatic)_ScrollBarThumb.GetTheme();
}
if (_TileCaptionBG != null)
{
_Theme.SongMenuTileBoard.StaticTileCaptionBG = (SThemeStatic)_TileCaptionBG.GetTheme();
}
if (_TileArtist != null)
{
_Theme.SongMenuTileBoard.TextTileArtist = (SThemeText)_TileArtist.GetTheme();
}
if (_TileTitle != null)
{
_Theme.SongMenuTileBoard.TextTileTitle = (SThemeText)_TileTitle.GetTheme();
}
}
public override object GetTheme()
@@ -271,14 +329,14 @@ namespace VocaluxeLib.Menu.SongMenu
}
_CoverBig.Texture = category.CoverTextureBig;
_Artist.Text = category.Name;
_Title.Text = category.Name;
return;
}
_CoverBig.Texture = song.CoverTextureBig;
_Artist.Text = song.Artist;
_Title.Text = song.Title;
_SongYear.Text = song.Year;
_SongYear.Text = string.IsNullOrEmpty(song.Year) ? "-" : song.Year;
_DuetIcon.Visible = song.IsDuet;
_RapIcon.Visible = song.IsRap;
_VideoIcon.Visible = song.Video != "";
@@ -299,11 +357,11 @@ namespace VocaluxeLib.Menu.SongMenu
}
_CoverBig.Texture = category.CoverTextureBig;
_Artist.Text = category.Name;
_Title.Text = category.Name;
var num = category.GetNumSongsNotSung();
var songOrSongs = num == 1 ? "TR_SCREENSONG_NUMSONG" : "TR_SCREENSONG_NUMSONGS";
_Title.Text = CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
_Artist.Text = CBase.Language.Translate(songOrSongs).Replace("%v", num.ToString());
}
}
@@ -623,17 +681,42 @@ namespace VocaluxeLib.Menu.SongMenu
public override void Draw()
{
foreach (var tile in _Tiles)
if (_IsScrolling())
{
if (tile.Selected)
_DrawScrollingTiles();
}
else
{
var focusNr = _GetFocusNr();
var dimTiles = focusNr >= _Offset && focusNr < _Offset + _Tiles.Count;
for (var i = 0; i < _Tiles.Count; i++)
{
tile.Draw(EAspect.Crop, SelectedTileZoomFactor, -0.1f);
}
else
{
var aspect = tile.Texture != _CoverBGTexture ? EAspect.Crop : EAspect.Stretch;
tile.Draw(aspect);
var tile = _Tiles[i];
tile.Alpha = dimTiles && i + _Offset != focusNr ? _UnfocusedAlpha : 1f;
if (tile.Selected)
{
var frame = tile.Rect.Scale(SelectedTileZoomFactor);
CBase.Drawing.DrawRect(new SColorF(1f, 1f, 1f, 0.9f), new SRectF(frame.X - 3f, frame.Y - 3f, frame.W + 6f, frame.H + 6f, frame.Z - 0.05f));
tile.Draw(EAspect.Crop, SelectedTileZoomFactor, -0.1f);
}
else
{
var aspect = tile.Texture != _CoverBGTexture ? EAspect.Crop : EAspect.Stretch;
tile.Draw(aspect);
}
}
_DrawTileCaption();
}
var itemCount = CBase.Songs.IsInCategory() ? CBase.Songs.GetNumSongsVisible() : CBase.Songs.GetNumCategories();
_DrawScrollBar(_ScrollBar, _ScrollBarThumb, _Theme.SongMenuTileBoard.TileRect, _GetScrollPosition(), _NumH, (itemCount + _NumW - 1) / _NumW);
if (!PreviewVisible)
{
return;
}
_TextBG.Draw();
@@ -666,6 +749,114 @@ namespace VocaluxeLib.Menu.SongMenu
}
}
private void _DrawScrollingTiles()
{
var position = _GetScrollPosition();
var firstRow = (int)Math.Floor(position);
var isInCategory = CBase.Songs.IsInCategory();
var itemCount = isInCategory ? CBase.Songs.GetNumSongsVisible() : CBase.Songs.GetNumCategories();
var focusNr = _GetFocusNr();
for (var row = Math.Max(firstRow, 0); row <= firstRow + _NumH; row++)
{
var y = Rect.Y + (row - position) * (_TileH + _Theme.SongMenuTileBoard.SpaceH);
for (var col = 0; col < _NumW; col++)
{
var index = row * _NumW + col;
var rect = new SRectF(Rect.X + col * (_TileW + _Theme.SongMenuTileBoard.SpaceW), y, _TileW, _TileH, Rect.Z);
if (index < itemCount)
{
var alpha = focusNr >= 0 && index != focusNr ? _UnfocusedAlpha : 1f;
_DrawClipped(_GetCoverTexture(index, isInCategory), rect, new SColorF(1f, 1f, 1f, alpha), EAspect.Crop);
}
else
{
_DrawClipped(_CoverBGTexture, rect, _Color, EAspect.Stretch);
}
}
}
}
private int _GetFocusNr()
{
return _SelectionNr >= 0 ? _SelectionNr : _PreviewNr;
}
private void _DrawTileCaption()
{
if ((_TileCaptionBG == null && _TileArtist == null && _TileTitle == null) || CBase.Config.GetTileCaption() == EOffOn.TR_CONFIG_OFF)
{
return;
}
var tile = GetSelectedSongCover();
if (tile == null)
{
return;
}
string artist;
string title;
if (CBase.Songs.IsInCategory())
{
var song = CBase.Songs.GetVisibleSong(_SelectionNr);
if (song == null)
{
return;
}
artist = song.Artist;
title = song.Title;
}
else
{
var category = CBase.Songs.GetCategory(_SelectionNr);
if (category == null)
{
return;
}
var num = category.GetNumSongsNotSung();
artist = category.Name;
title = CBase.Language.Translate(num == 1 ? "TR_SCREENSONG_NUMSONG" : "TR_SCREENSONG_NUMSONGS").Replace("%v", num.ToString());
}
var rect = tile.Rect;
CBase.Drawing.PushTransform(SelectedTileZoomFactor, rect.X + rect.W / 2f, rect.Y + rect.H / 2f, 0f, 1f);
if (_TileCaptionBG != null)
{
var bgRect = ((SThemeStatic)_TileCaptionBG.GetTheme()).Rect;
_TileCaptionBG.MaxRect = new SRectF(rect.X + bgRect.X, rect.Y + bgRect.Y, Math.Min(bgRect.W, rect.W - bgRect.X), bgRect.H, rect.Z - 0.2f);
_TileCaptionBG.Draw(EAspect.Stretch);
}
_DrawTileCaptionText(_TileArtist, artist, rect);
_DrawTileCaptionText(_TileTitle, title, rect);
CBase.Drawing.PopTransform();
}
private static void _DrawTileCaptionText(CText text, string value, SRectF tileRect)
{
if (text == null)
{
return;
}
var theme = (SThemeText)text.GetTheme();
text.X = tileRect.X + theme.X;
text.Y = tileRect.Y + theme.Y;
text.Z = tileRect.Z - 0.3f;
text.Text = value;
text.Draw();
}
private static CTextureRef _GetCoverTexture(int index, bool isInCategory)
{
return isInCategory ? CBase.Songs.GetVisibleSong(index).CoverTextureSmall : CBase.Songs.GetCategory(index).CoverTextureSmall;
}
public override CStatic GetSelectedSongCover()
{
return _Tiles.FirstOrDefault(tile => tile.Selected);
@@ -757,7 +948,7 @@ namespace VocaluxeLib.Menu.SongMenu
{
if (itemCount > i + offset)
{
_Tiles[i].Texture = isInCategory ? CBase.Songs.GetVisibleSong(i + offset).CoverTextureSmall : CBase.Songs.GetCategory(i + offset).CoverTextureSmall;
_Tiles[i].Texture = _GetCoverTexture(i + offset, isInCategory);
_Tiles[i].Color = new SColorF(1f, 1f, 1f, 1f);
}
else
@@ -767,6 +958,7 @@ namespace VocaluxeLib.Menu.SongMenu
}
}
_SetScrollTarget(offset / _NumW, !force && offset != _Offset, _NumH);
_Offset = offset;
}
@@ -781,6 +973,10 @@ namespace VocaluxeLib.Menu.SongMenu
// Those are drawn seperately so they are not in the above list
_CoverBig.LoadSkin();
_TextBG.LoadSkin();
foreach (var themeable in new IThemeable[] { _ScrollBar, _ScrollBarThumb, _TileCaptionBG, _TileArtist, _TileTitle }.Where(t => t != null))
{
themeable.LoadSkin();
}
Init();
}
+1
View File
@@ -46,5 +46,6 @@ namespace VocaluxeLib.Menu.SongMenu
int GetPreviewSong();
bool SmallView { get; set; }
bool PreviewVisible { get; set; }
}
}