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:
1 parent
6601f41aac
commit
74653ab977
19 files changed
+1710
-345
No files matched your search
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -46,5 +46,6 @@ namespace VocaluxeLib.Menu.SongMenu
|
||||
int GetPreviewSong();
|
||||
|
||||
bool SmallView { get; set; }
|
||||
bool PreviewVisible { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user