Files
Vocaluxe/Vocaluxe/Screens/CScreenStatistics.cs
T
McSchneidarandFlorian Ostertag 2cdd30c6fc Small improvements for 3 screens (#934)
* Improve profile and player selection screens

- Ask before deleting a profile, Delete only removes a character while editing the name
- Ask to save or discard unsaved profile changes when leaving the profile screen
- Restore the previous name with Escape and prevent empty profile names
- Stop the webcam when leaving the profile screen and discard snapshots on avatar change
- Show inactive profiles dimmed in the profile screen
- Play the missing mic/profile warning each time the player selection is shown
- Fix crash when clicking a profile after removing a player with Delete in fast selection
- Keep the duet part selection when profiles are reloaded
- Only save the player number when it has changed

* Use party mode selection look in statistics screens

- Tiles and selection use the ButtonTile skin like the party mode selection, the selected tile uses the selection color of the skin
- The detail list uses the CoverTextBackground skin, inner cards and row stripes the ButtonTile skin
- More space between the title and the columns of the best list
- Show the date in the recently sung list left aligned inside the list

* Changelog

* Improve sing screen and redesign pause menu

- Fix jumping to the old pause position after restarting or skipping a song in vocals mode
- Keep name and avatar hidden for players without a valid profile
- Show the placeholder avatar for profiles without avatar image
- Hide player information and rating popups during the start countdown
- Fix pause select slides not being shown or hidden
- Show "no more songs" only when Ctrl+S is pressed
- Select "Continue" when opening the pause menu with Escape
- Darken the game behind the pause menu
- Pause buttons as vertical list with icons, hidden buttons leave no gaps (visible buttons are placed in the slots of all pause buttons)
- New PauseButton skin with rounded corners for wide buttons, used for the pause buttons and the vocals volume selection
- Larger pause title centered above the pause panels
- Info panel with cover, title, artist, song progress and player scores
- Vocals volume selection with icon and centered caption in the full width of the info panel, showing five values
- Pause panels and icons are animated together with the pause buttons

---------

Co-authored-by: Florian Ostertag <flokuep@users.noreply.github.com>
2026-10-21 12:05:18 +02:00

292 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#region license
// This file is part of Vocaluxe.
//
// Vocaluxe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Vocaluxe is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Linq;
using System.Windows.Forms;
using Vocaluxe.Base;
using VocaluxeLib;
using VocaluxeLib.Menu;
namespace Vocaluxe.Screens
{
public class CScreenStatistics : CMenu
{
protected override int _ScreenVersion
{
get { return 2; }
}
private const int _NumTiles = 4;
private const int _NumMostSung = 2;
private const int _NumRecent = 5;
private const int _NumDifficulties = 3;
private const int _NumBest = 3;
private const int _NumPlayers = 4;
private const string _StaticTileSelection = "StaticTileSelection";
private const string _TextSongsValue = "TextSongsValue";
private const string _TextSungValue = "TextSungValue";
private const string _TextPlayersValue = "TextPlayersValue";
private const string _TextCoverage = "TextCoverage";
private const string _ProgressBarCoverage = "ProgressBarCoverage";
private string[] _StaticTile;
private string[] _TextMostSung;
private string[] _TextRecentDate;
private string[] _TextRecentSong;
private string[] _TextRecentScore;
private string[,] _TextBestName;
private string[,] _TextBestScore;
private string[,] _StaticBestMedal;
private string[] _StaticAvatar;
private string[] _TextPlayerName;
private string[] _TextPlayerAverage;
private int _SelectedTile;
public override EMusicType CurrentMusicType
{
get { return EMusicType.Background; }
}
public override void Init()
{
base.Init();
_StaticTile = Enumerable.Range(1, _NumTiles).Select(i => "StaticTile" + i).ToArray();
_TextMostSung = Enumerable.Range(1, _NumMostSung).Select(i => "TextMostSung" + i).ToArray();
_TextRecentDate = Enumerable.Range(1, _NumRecent).Select(i => "TextRecentDate" + i).ToArray();
_TextRecentSong = Enumerable.Range(1, _NumRecent).Select(i => "TextRecentSong" + i).ToArray();
_TextRecentScore = Enumerable.Range(1, _NumRecent).Select(i => "TextRecentScore" + i).ToArray();
_StaticAvatar = Enumerable.Range(1, _NumPlayers).Select(i => "StaticAvatar" + i).ToArray();
_TextPlayerName = Enumerable.Range(1, _NumPlayers).Select(i => "TextPlayerName" + i).ToArray();
_TextPlayerAverage = Enumerable.Range(1, _NumPlayers).Select(i => "TextPlayerAverage" + i).ToArray();
_TextBestName = new string[_NumDifficulties, _NumBest];
_TextBestScore = new string[_NumDifficulties, _NumBest];
_StaticBestMedal = new string[_NumDifficulties, _NumBest];
for (var d = 0; d < _NumDifficulties; d++)
{
for (var i = 0; i < _NumBest; i++)
{
_TextBestName[d, i] = "TextBestName" + (d + 1) + (i + 1);
_TextBestScore[d, i] = "TextBestScore" + (d + 1) + (i + 1);
_StaticBestMedal[d, i] = "StaticBestMedal" + (d + 1) + (i + 1);
}
}
_ThemeStatics = _StaticTile.Concat(_StaticAvatar).Concat(_StaticBestMedal.Cast<string>()).Concat(new[] { _StaticTileSelection }).ToArray();
_ThemeTexts = new[] { _TextSongsValue, _TextSungValue, _TextPlayersValue, _TextCoverage }
.Concat(_TextMostSung).Concat(_TextRecentDate).Concat(_TextRecentSong).Concat(_TextRecentScore)
.Concat(_TextBestName.Cast<string>()).Concat(_TextBestScore.Cast<string>())
.Concat(_TextPlayerName).Concat(_TextPlayerAverage).ToArray();
_ThemeProgressBars = new[] { _ProgressBarCoverage };
}
public override void LoadTheme(string xmlPath)
{
base.LoadTheme(xmlPath);
foreach (var avatar in _StaticAvatar)
{
_Statics[avatar].Aspect = EAspect.Crop;
}
}
public override void OnShow()
{
base.OnShow();
_UpdateOverview();
_UpdateRecent();
_UpdateBest();
_UpdatePlayers();
_SelectTile(_SelectedTile);
}
public override bool HandleInput(SKeyEvent keyEvent)
{
base.HandleInput(keyEvent);
if (keyEvent.KeyPressed)
{
return true;
}
switch (keyEvent.Key)
{
case Keys.Left:
case Keys.Right:
_SelectTile(_SelectedTile ^ 1);
break;
case Keys.Up:
case Keys.Down:
_SelectTile(_SelectedTile ^ 2);
break;
case Keys.Enter:
_OpenDetail();
break;
case Keys.Escape:
case Keys.Back:
CGraphics.FadeTo(EScreen.Main);
break;
}
return true;
}
public override bool HandleMouse(SMouseEvent mouseEvent)
{
base.HandleMouse(mouseEvent);
for (var i = 0; i < _NumTiles; i++)
{
if (CHelper.IsInBounds(_Statics[_StaticTile[i]].Rect, mouseEvent))
{
_SelectTile(i);
if (mouseEvent.LB)
{
_OpenDetail();
}
}
}
if (mouseEvent.RB)
{
CGraphics.FadeTo(EScreen.Main);
}
return true;
}
public override bool UpdateGame()
{
return true;
}
private void _SelectTile(int tile)
{
_SelectedTile = tile;
var selection = _Statics[_StaticTileSelection];
var rect = _Statics[_StaticTile[tile]].Rect;
selection.X = rect.X;
selection.Y = rect.Y;
selection.W = rect.W;
selection.H = rect.H;
for (var i = 0; i < _StaticTile.Length; i++)
{
_Statics[_StaticTile[i]].Visible = i != tile;
}
}
private void _OpenDetail()
{
CScreenStatisticsDetail.Page = (EStatisticsPage)_SelectedTile;
CGraphics.FadeTo(EScreen.StatisticsDetail);
}
private void _UpdateOverview()
{
_Texts[_TextSongsValue].Text = CStatistics.NumSongs.ToString("N0");
_Texts[_TextSungValue].Text = CStatistics.NumSungSongs.ToString("N0");
_Texts[_TextPlayersValue].Text = CStatistics.NumPlayers.ToString("N0");
_Texts[_TextCoverage].Text = string.Format(CLanguage.Translate("TR_SCREENSTATISTICS_COVERAGE"), CStatistics.Coverage);
_ProgressBars[_ProgressBarCoverage].Progress = CStatistics.Coverage / 100f;
var mostSung = CStatistics.GetMostSung(_NumMostSung);
for (var i = 0; i < _NumMostSung; i++)
{
_Texts[_TextMostSung[i]].Visible = i < mostSung.Count;
if (i < mostSung.Count)
{
_Texts[_TextMostSung[i]].Text = mostSung[i].NumPlayed + "× " + mostSung[i].Artist + " - " + mostSung[i].Title;
}
}
}
private void _UpdateRecent()
{
var scores = CDataBase.LoadRecentScores(_NumRecent);
for (var i = 0; i < _NumRecent; i++)
{
var isEntry = i < scores.Count;
_Texts[_TextRecentDate[i]].Visible = isEntry;
_Texts[_TextRecentScore[i]].Visible = isEntry;
_Texts[_TextRecentSong[i]].Visible = isEntry || i == 0;
if (!isEntry)
{
_Texts[_TextRecentSong[i]].Text = "TR_SCREENSTATISTICS_NODATA";
continue;
}
_Texts[_TextRecentDate[i]].Text = CStatistics.FormatDate(scores[i].Date, false);
_Texts[_TextRecentSong[i]].Text = scores[i].Artist + " - " + scores[i].Title + " · " + scores[i].PlayerName;
_Texts[_TextRecentScore[i]].Text = scores[i].Score.ToString();
}
}
private void _UpdateBest()
{
for (var d = 0; d < _NumDifficulties; d++)
{
var scores = CDataBase.LoadTopScores((EGameDifficulty)d, _NumBest);
for (var i = 0; i < _NumBest; i++)
{
var isEntry = i < scores.Count;
_Texts[_TextBestName[d, i]].Visible = isEntry;
_Texts[_TextBestScore[d, i]].Visible = isEntry;
_Statics[_StaticBestMedal[d, i]].Visible = isEntry;
if (isEntry)
{
_Texts[_TextBestName[d, i]].Text = scores[i].PlayerName;
_Texts[_TextBestScore[d, i]].Text = scores[i].Score.ToString();
}
}
}
}
private void _UpdatePlayers()
{
var players = CDataBase.LoadPlayerStatistics();
for (var i = 0; i < _NumPlayers; i++)
{
var isEntry = i < players.Count;
_Texts[_TextPlayerName[i]].Visible = isEntry;
_Texts[_TextPlayerAverage[i]].Visible = isEntry;
_Statics[_StaticAvatar[i]].Visible = false;
if (!isEntry)
{
continue;
}
_Texts[_TextPlayerName[i]].Text = string.Format(CLanguage.Translate("TR_SCREENSTATISTICS_PLAYERSONGS"), players[i].PlayerName, players[i].NumSongs);
_Texts[_TextPlayerAverage[i]].Text = string.Format(CLanguage.Translate("TR_SCREENSTATISTICS_AVERAGE"), Math.Round(players[i].AverageScore).ToString("N0"));
var avatar = CStatistics.GetAvatar(players[i].PlayerName);
_Statics[_StaticAvatar[i]].Texture = avatar;
_Statics[_StaticAvatar[i]].Visible = avatar != null;
}
}
}
}