From 2cdd30c6fc012591572bdc42693d846f19760b87 Mon Sep 17 00:00:00 2001 From: McSchneidar <262792195+McSchneidar@users.noreply.github.com> Date: Wed, 21 Oct 2026 12:05:18 +0200 Subject: [PATCH] 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 --- Output/Languages/en.xml | 5 + .../Changelog/Changelog_ScreenProfiles.txt | 4 + .../Themes/Changelog/Changelog_ScreenSing.txt | 26 + .../Changelog/Changelog_ScreenStatistics.txt | 10 +- .../Changelog_ScreenStatisticsDetail.txt | 8 + Output/Themes/Vocaluxe 2024/01_Standard.xml | 1 + Output/Themes/Vocaluxe 2024/02.xml | 1 + Output/Themes/Vocaluxe 2024/03.xml | 1 + Output/Themes/Vocaluxe 2024/04.xml | 1 + Output/Themes/Vocaluxe 2024/05.xml | 1 + Output/Themes/Vocaluxe 2024/06.xml | 1 + Output/Themes/Vocaluxe 2024/PauseButton.png | Bin 0 -> 717 bytes .../Vocaluxe 2024/Screens/ScreenProfiles.xml | 132 +++- .../Vocaluxe 2024/Screens/ScreenSing.xml | 663 ++++++++++++++---- .../Screens/ScreenStatistics.xml | 140 ++-- .../Screens/ScreenStatisticsDetail.xml | 65 +- Vocaluxe/Screens/CScreenNames.cs | 23 +- Vocaluxe/Screens/CScreenProfiles.cs | 405 ++++++++--- Vocaluxe/Screens/CScreenSing.cs | 227 ++++-- Vocaluxe/Screens/CScreenStatistics.cs | 7 +- Vocaluxe/Screens/CScreenStatisticsDetail.cs | 17 +- VocaluxeLib/Menu/CNameSelection.cs | 15 +- 22 files changed, 1324 insertions(+), 429 deletions(-) create mode 100644 Output/Themes/Vocaluxe 2024/PauseButton.png diff --git a/Output/Languages/en.xml b/Output/Languages/en.xml index d40203e7..8f0acff1 100644 --- a/Output/Languages/en.xml +++ b/Output/Languages/en.xml @@ -7,6 +7,9 @@ Save Back Start + Yes + No + Cancel Audio streams Video streams Textures @@ -280,6 +283,8 @@ Save snapshot Delete snapshot Webcam + Do you really want to delete the profile %s? + Do you want to save your changes? Options Game Sound diff --git a/Output/Themes/Changelog/Changelog_ScreenProfiles.txt b/Output/Themes/Changelog/Changelog_ScreenProfiles.txt index 0f2cf2ff..f388cbb1 100644 --- a/Output/Themes/Changelog/Changelog_ScreenProfiles.txt +++ b/Output/Themes/Changelog/Changelog_ScreenProfiles.txt @@ -1,4 +1,8 @@ ScreenProfiles +++++++++++ +Version 5: +Add: , , , , (popup to confirm deleting a profile and to save changes before leaving) + ++++++++++ Version 4: Add: diff --git a/Output/Themes/Changelog/Changelog_ScreenSing.txt b/Output/Themes/Changelog/Changelog_ScreenSing.txt index 5289cf9a..99d141bd 100644 --- a/Output/Themes/Changelog/Changelog_ScreenSing.txt +++ b/Output/Themes/Changelog/Changelog_ScreenSing.txt @@ -1,4 +1,30 @@ ScreenSing ++++++++++ +Version 16 + +Add: +, , , , Icons of the pause buttons, they move with their button and use the text color of their button + Cover of the current song + Progress of the current song, the width is scaled by the progress + Only visible in vocals audio mode, keeps its horizontal distance to the left edge of + - + + + + - + - + +Change: +Visible pause buttons are placed without gaps in the slots of all pause buttons (sorted by Y, then X) in the order Continue, Skip, RestartRound, RestartGame, Cancel + Shows only the title of the song +Statics starting with "StaticPause" that do not cover the whole screen are animated together with the pause buttons + ++++++++++ +Version 15 + +Add: + Darkens the game behind the pause menu (all statics starting with "StaticPause" are shown in the pause menu) + +++++++++ Version 14 diff --git a/Output/Themes/Changelog/Changelog_ScreenStatistics.txt b/Output/Themes/Changelog/Changelog_ScreenStatistics.txt index 28ccf365..703413be 100644 --- a/Output/Themes/Changelog/Changelog_ScreenStatistics.txt +++ b/Output/Themes/Changelog/Changelog_ScreenStatistics.txt @@ -1,8 +1,16 @@ ScreenStatistics +++++++++++ +Version 2: + +Change (same look as the party mode selection): + to use the skin ButtonTile with ButtonMainColor + uses the skin ButtonTile with ButtonSelColor and replaces the selected tile (like in ScreenParty) + to use the skin ButtonTile with ButtonMainColor +Columns of the best list (, , , , ) moved 20 pixels down + ++++++++++ Version 1: -(2026 Oct 16) New screen: statistics dashboard with four tiles (overview, recently sung, best list per difficulty, players) Help text at the bottom of the screen diff --git a/Output/Themes/Changelog/Changelog_ScreenStatisticsDetail.txt b/Output/Themes/Changelog/Changelog_ScreenStatisticsDetail.txt index f228b95f..e66bfd50 100644 --- a/Output/Themes/Changelog/Changelog_ScreenStatisticsDetail.txt +++ b/Output/Themes/Changelog/Changelog_ScreenStatisticsDetail.txt @@ -1,5 +1,13 @@ ScreenStatisticsDetail +++++++++++ +Version 2: +(2026 Oct 18) + +Change (same look as the party mode selection): + uses the skin CoverTextBackground with StaticColorAlpha + use the skin ButtonTile with ButtonMainColor + ++++++++++ Version 1: (2026 Oct 16) diff --git a/Output/Themes/Vocaluxe 2024/01_Standard.xml b/Output/Themes/Vocaluxe 2024/01_Standard.xml index 7a8124ea..e42d6274 100644 --- a/Output/Themes/Vocaluxe 2024/01_Standard.xml +++ b/Output/Themes/Vocaluxe 2024/01_Standard.xml @@ -382,6 +382,7 @@ NoAvatar.png SongMenu.png PauseBG.png + PauseButton.png EnergyBeam.png SearchBar.png PlaylistBG.png diff --git a/Output/Themes/Vocaluxe 2024/02.xml b/Output/Themes/Vocaluxe 2024/02.xml index fda8eb94..9798bffd 100644 --- a/Output/Themes/Vocaluxe 2024/02.xml +++ b/Output/Themes/Vocaluxe 2024/02.xml @@ -382,6 +382,7 @@ NoAvatar.png SongMenu.png PauseBG.png + PauseButton.png EnergyBeam.png SearchBar.png PlaylistBG.png diff --git a/Output/Themes/Vocaluxe 2024/03.xml b/Output/Themes/Vocaluxe 2024/03.xml index a687f190..97dd35ac 100644 --- a/Output/Themes/Vocaluxe 2024/03.xml +++ b/Output/Themes/Vocaluxe 2024/03.xml @@ -382,6 +382,7 @@ NoAvatar.png SongMenu.png PauseBG.png + PauseButton.png EnergyBeam.png SearchBar.png PlaylistBG.png diff --git a/Output/Themes/Vocaluxe 2024/04.xml b/Output/Themes/Vocaluxe 2024/04.xml index 94de6ff7..0585625c 100644 --- a/Output/Themes/Vocaluxe 2024/04.xml +++ b/Output/Themes/Vocaluxe 2024/04.xml @@ -382,6 +382,7 @@ NoAvatar.png SongMenu.png PauseBG.png + PauseButton.png EnergyBeam.png SearchBar.png PlaylistBG.png diff --git a/Output/Themes/Vocaluxe 2024/05.xml b/Output/Themes/Vocaluxe 2024/05.xml index b272f2bc..194b797e 100644 --- a/Output/Themes/Vocaluxe 2024/05.xml +++ b/Output/Themes/Vocaluxe 2024/05.xml @@ -382,6 +382,7 @@ NoAvatar.png SongMenu.png PauseBG.png + PauseButton.png EnergyBeam.png SearchBar.png PlaylistBG.png diff --git a/Output/Themes/Vocaluxe 2024/06.xml b/Output/Themes/Vocaluxe 2024/06.xml index 8cbb05bb..9b058273 100644 --- a/Output/Themes/Vocaluxe 2024/06.xml +++ b/Output/Themes/Vocaluxe 2024/06.xml @@ -382,6 +382,7 @@ NoAvatar.png SongMenu.png PauseBG.png + PauseButton.png EnergyBeam.png SearchBar.png PlaylistBG.png diff --git a/Output/Themes/Vocaluxe 2024/PauseButton.png b/Output/Themes/Vocaluxe 2024/PauseButton.png new file mode 100644 index 0000000000000000000000000000000000000000..a6d95449b9e7e0357feffd4f8c9a7629840fa2e2 GIT binary patch literal 717 zcmeAS@N?(olHy`uVBq!ia0y~yU{(OKQ#jawWL;oLKLZ2P6i*k&kcwMx?{4gEF%WSL z6n|hPvy)A#fZyeEJ-1H$A#D?;uvxO!RtGa5q=rB1-jW+#HKDxpdfDrDtPBhv(rjlf zl;bVDE#d!gql6Fx!;b?+;!5Ek1NW2xZHTWB)vRarFcbkQbbYGlaD<(K!NA1noVmQ+ zZYBl>x7xm`=NTV8kYQkusGTwI*Xwpi28M=yfjzjyUfVY;Lm^Vb7=M*))SU4 rkL(rCt_E87;lr(qePt*7dp|NyN%;CmEjMr?&_D)HS3j3^P6 ScreenProfiles - 4 + 5 @@ -36,6 +36,17 @@ -1 + + PopupBG + + + 0 + 0 + 1920 + 1080 + -10 + + @@ -122,6 +133,20 @@ Outline TR_SCREENPROFILES_ACTIVE + + 960 + 405 + -11 + 40.5 + 900 + + + Center + Center + + Outline + + + + + diff --git a/Output/Themes/Vocaluxe 2024/Screens/ScreenSing.xml b/Output/Themes/Vocaluxe 2024/Screens/ScreenSing.xml index 77b69377..c0e8fa49 100644 --- a/Output/Themes/Vocaluxe 2024/Screens/ScreenSing.xml +++ b/Output/Themes/Vocaluxe 2024/Screens/ScreenSing.xml @@ -2,7 +2,7 @@ ScreenSing - 14 + 16 @@ -169,6 +169,22 @@ 0 + + + + 0 + 0 + 0 + 0.55 + + + 0 + 0 + 1920 + 1080 + -2.05 + + PauseBG @@ -180,6 +196,195 @@ -2.1 + + CoverTextBackground + + + 105 + 240 + 660 + 720 + -2.105 + + + + CoverTextBackground + + + 855 + 240 + 960 + 720 + -2.105 + + + + PlayIcon + + + 157.5 + 285.5 + 44 + 44 + -2.13 + + + + NextIcon + + + 157.5 + 375.5 + 44 + 44 + -2.13 + + + + RepeatIcon + + + 157.5 + 465.5 + 44 + 44 + -2.13 + + + + RepeatIcon + + + 157.5 + 555.5 + 44 + 44 + -2.13 + + + + CloseIcon + + + 157.5 + 645.5 + 44 + 44 + -2.13 + + + + + + + 900 + 285 + 180 + 180 + -2.11 + + + + TimeLine + + 0.2 + + + 900 + 490 + 870 + 6 + -2.11 + + + + TimeLine + + + 900 + 490 + 870 + 6 + -2.12 + + + + + + + 900 + 560 + 60 + 60 + -2.11 + + + + + + + 1350 + 560 + 60 + 60 + -2.11 + + + + + + + 900 + 630 + 60 + 60 + -2.11 + + + + + + + 1350 + 630 + 60 + 60 + -2.11 + + + + + + + 900 + 700 + 60 + 60 + -2.11 + + + + + + + 1350 + 700 + 60 + 60 + -2.11 + + + + VocalsIcon + + + 1109 + 784 + 44 + 44 + -2.11 + + @@ -698,9 +903,9 @@ 960 - 675 + 55 -2.11 - 150 + 130 0 @@ -711,31 +916,241 @@ TR_SCREENSING_PAUSE - 960 - 15 + 1110 + 310 -2.11 - 60 - 0 - - - Center - Center - - Normal - - - - 217.5 - 818 - -2.11 - 40.5 - 520 + 48 + 660 Left Center Outline + + + + 1110 + 370 + -2.11 + 36 + 660 + + + Left + Center + + Outline + + + + 900 + 508 + -2.11 + 30 + 300 + + + Left + Center + + Outline + + + + 1770 + 508 + -2.11 + 30 + 300 + + + Right + Center + + Outline + + + + 975 + 572 + -2.11 + 36 + 240 + + + Left + Center + + Outline + + + + 1320 + 572 + -2.11 + 36 + 0 + + + Right + Center + + Outline + + + + 1425 + 572 + -2.11 + 36 + 240 + + + Left + Center + + Outline + + + + 1770 + 572 + -2.11 + 36 + 0 + + + Right + Center + + Outline + + + + 975 + 642 + -2.11 + 36 + 240 + + + Left + Center + + Outline + + + + 1320 + 642 + -2.11 + 36 + 0 + + + Right + Center + + Outline + + + + 1425 + 642 + -2.11 + 36 + 240 + + + Left + Center + + Outline + + + + 1770 + 642 + -2.11 + 36 + 0 + + + Right + Center + + Outline + + + + 975 + 712 + -2.11 + 36 + 240 + + + Left + Center + + Outline + + + + 1320 + 712 + -2.11 + 36 + 0 + + + Right + Center + + Outline + + + + 1425 + 712 + -2.11 + 36 + 240 + + + Left + Center + + Outline + + + + 1770 + 712 + -2.11 + 36 + 0 + + + Right + Center + + Outline + + + + 1335 + 786 + -2.11 + 40.5 + 810 + + + Center + Center + + Outline TR_SCREENSING_VOCALSVOLUME @@ -1367,180 +1782,140 @@ - + @@ -1614,43 +1989,43 @@ - + PauseButton SelectSlideArrowLeft SelectSlideArrowRight - SelectSlide + PauseButton SelectSlideArrowLeft SelectSlideArrowRight - 752 - 820 - 958 - 40 + 900 + 855 + 870 + 75 -2.11 - 757.5 - 822.5 - 35 - 35 + 906 + 868.5 + 48 + 48 -2.11 - 1667.5 - 822.5 - 35 - 35 + 1716 + 868.5 + 48 + 48 -2.11 - - + + - - + + 40.5 - 75 + 60 0 - 300 + 140 Outline Bold 5 diff --git a/Output/Themes/Vocaluxe 2024/Screens/ScreenStatistics.xml b/Output/Themes/Vocaluxe 2024/Screens/ScreenStatistics.xml index eb5f0203..4ec0276a 100644 --- a/Output/Themes/Vocaluxe 2024/Screens/ScreenStatistics.xml +++ b/Output/Themes/Vocaluxe 2024/Screens/ScreenStatistics.xml @@ -2,7 +2,7 @@ ScreenStatistics - 1 + 2 @@ -26,13 +26,8 @@ - - - 0 - 0 - 0 - 0.45 - + ButtonTile + 90 165 @@ -42,13 +37,8 @@ - - - 0 - 0 - 0 - 0.45 - + ButtonTile + 975 165 @@ -58,13 +48,8 @@ - - - 0 - 0 - 0 - 0.45 - + ButtonTile + 90 600 @@ -74,13 +59,8 @@ - - - 0 - 0 - 0 - 0.45 - + ButtonTile + 975 600 @@ -90,13 +70,8 @@ - - - 0.2 - 0.8 - 0.99 - 0.25 - + ButtonTile + 90 165 @@ -150,16 +125,11 @@ - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 119 - 658 + 678 257 300 0.8 @@ -170,7 +140,7 @@ 131 - 728 + 748 26 26 0 @@ -181,7 +151,7 @@ 131 - 806 + 826 26 26 0 @@ -192,23 +162,18 @@ 131 - 884 + 904 26 26 0 - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 389 - 658 + 678 257 300 0.8 @@ -219,7 +184,7 @@ 401 - 728 + 748 26 26 0 @@ -230,7 +195,7 @@ 401 - 806 + 826 26 26 0 @@ -241,23 +206,18 @@ 401 - 884 + 904 26 26 0 - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 659 - 658 + 678 257 300 0.8 @@ -268,7 +228,7 @@ 671 - 728 + 748 26 26 0 @@ -279,7 +239,7 @@ 671 - 806 + 826 26 26 0 @@ -290,7 +250,7 @@ 671 - 884 + 904 26 26 0 @@ -734,7 +694,7 @@ 249 - 668 + 688 -1 32 0 @@ -748,7 +708,7 @@ 167 - 722 + 742 -1 36 110 @@ -762,7 +722,7 @@ 366 - 722 + 742 -1 36 0 @@ -776,7 +736,7 @@ 167 - 800 + 820 -1 36 110 @@ -790,7 +750,7 @@ 366 - 800 + 820 -1 36 0 @@ -804,7 +764,7 @@ 167 - 878 + 898 -1 36 110 @@ -818,7 +778,7 @@ 366 - 878 + 898 -1 36 0 @@ -832,7 +792,7 @@ 519 - 668 + 688 -1 32 0 @@ -846,7 +806,7 @@ 437 - 722 + 742 -1 36 110 @@ -860,7 +820,7 @@ 636 - 722 + 742 -1 36 0 @@ -874,7 +834,7 @@ 437 - 800 + 820 -1 36 110 @@ -888,7 +848,7 @@ 636 - 800 + 820 -1 36 0 @@ -902,7 +862,7 @@ 437 - 878 + 898 -1 36 110 @@ -916,7 +876,7 @@ 636 - 878 + 898 -1 36 0 @@ -930,7 +890,7 @@ 789 - 668 + 688 -1 32 0 @@ -944,7 +904,7 @@ 707 - 722 + 742 -1 36 110 @@ -958,7 +918,7 @@ 906 - 722 + 742 -1 36 0 @@ -972,7 +932,7 @@ 707 - 800 + 820 -1 36 110 @@ -986,7 +946,7 @@ 906 - 800 + 820 -1 36 0 @@ -1000,7 +960,7 @@ 707 - 878 + 898 -1 36 110 @@ -1014,7 +974,7 @@ 906 - 878 + 898 -1 36 0 diff --git a/Output/Themes/Vocaluxe 2024/Screens/ScreenStatisticsDetail.xml b/Output/Themes/Vocaluxe 2024/Screens/ScreenStatisticsDetail.xml index d165c777..e8c3ce68 100644 --- a/Output/Themes/Vocaluxe 2024/Screens/ScreenStatisticsDetail.xml +++ b/Output/Themes/Vocaluxe 2024/Screens/ScreenStatisticsDetail.xml @@ -2,7 +2,7 @@ ScreenStatisticsDetail - 1 + 2 @@ -26,13 +26,8 @@ - - - 0 - 0 - 0 - 0.45 - + CoverTextBackground + 90 185 @@ -42,13 +37,8 @@ - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 100 241 @@ -58,13 +48,8 @@ - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 100 361 @@ -74,13 +59,8 @@ - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 100 481 @@ -90,13 +70,8 @@ - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 100 601 @@ -106,13 +81,8 @@ - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 100 721 @@ -122,13 +92,8 @@ - - - 1 - 1 - 1 - 0.07 - + ButtonTile + 100 841 diff --git a/Vocaluxe/Screens/CScreenNames.cs b/Vocaluxe/Screens/CScreenNames.cs index b2306381..d2f7aa9a 100644 --- a/Vocaluxe/Screens/CScreenNames.cs +++ b/Vocaluxe/Screens/CScreenNames.cs @@ -266,6 +266,7 @@ namespace Vocaluxe.Screens //Reset all values _SelectingFastPlayerNr = 0; _SelectingKeyboardActive = false; + _SelectingFast = false; _NameSelections[_NameSelection].FastSelection(false, -1); //Update Tiles-List _NameSelections[_NameSelection].UpdateList(); @@ -363,7 +364,7 @@ namespace Vocaluxe.Screens _SelectingFastPlayerNr = 6; break; default: - _UpdatePlayerNumber(); + _UpdatePlayerNumberIfChanged(); break; } @@ -542,7 +543,7 @@ namespace Vocaluxe.Screens } else { - _UpdatePlayerNumber(); + _UpdatePlayerNumberIfChanged(); } //Update Tiles-List @@ -640,7 +641,7 @@ namespace Vocaluxe.Screens { if (_ProfilesChanged || _AvatarsChanged) { - _LoadProfiles(); + _LoadProfiles(false); } for (var i = 1; i <= CGame.NumPlayers; i++) @@ -662,9 +663,10 @@ namespace Vocaluxe.Screens { base.OnShow(); CRecord.Start(); + _HasPlayedWarningSound = false; _NameSelections[_NameSelection].Init(); - _LoadProfiles(); + _LoadProfiles(true); _SelectElement(_Buttons[_ButtonStart]); } @@ -689,7 +691,7 @@ namespace Vocaluxe.Screens } } - private void _LoadProfiles() + private void _LoadProfiles(bool initDuetParts) { _NameSelections[_NameSelection].UpdateList(); @@ -709,6 +711,7 @@ namespace Vocaluxe.Screens _Texts[_TextPlayer[i]].Text = CProfiles.GetPlayerName(CGame.Players[i].ProfileId, i + 1); if (CGame.GetNumSongs() == 1 && firstSong.IsDuet) { + var duetPart = _SelectSlides[_SelectSlideDuetPlayer[i]].Selection; _SelectSlides[_SelectSlideDuetPlayer[i]].Clear(); _SelectSlides[_SelectSlideDuetPlayer[i]].Visible = i + 1 <= CGame.NumPlayers; @@ -717,7 +720,7 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlideDuetPlayer[i]].AddValue(firstSong.Notes.VoiceNames[j]); } - _SelectSlides[_SelectSlideDuetPlayer[i]].Selection = i % 2; + _SelectSlides[_SelectSlideDuetPlayer[i]].Selection = initDuetParts || duetPart < 0 ? i % 2 : duetPart; } else { @@ -754,6 +757,14 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlidePlayerNumber].Selection = CConfig.Config.Game.NumPlayers - 1; } + private void _UpdatePlayerNumberIfChanged() + { + if (_SelectSlides[_SelectSlidePlayerNumber].Selection + 1 != CConfig.Config.Game.NumPlayers) + { + _UpdatePlayerNumber(); + } + } + private void _UpdatePlayerNumber() { CConfig.Config.Game.NumPlayers = _SelectSlides[_SelectSlidePlayerNumber].Selection + 1; diff --git a/Vocaluxe/Screens/CScreenProfiles.cs b/Vocaluxe/Screens/CScreenProfiles.cs index 074799bc..58444a8e 100644 --- a/Vocaluxe/Screens/CScreenProfiles.cs +++ b/Vocaluxe/Screens/CScreenProfiles.cs @@ -36,12 +36,19 @@ namespace Vocaluxe.Screens PlayerName } + enum EProfilesPopup + { + None, + Delete, + UnsavedChanges + } + public class CScreenProfiles : CMenu { // Version number for theme files. Increment it, if you've changed something on the theme files! protected override int _ScreenVersion { - get { return 4; } + get { return 5; } } private const string _SelectSlideProfiles = "SelectSlideProfiles"; @@ -60,6 +67,11 @@ namespace Vocaluxe.Screens private const string _ButtonTakeSnapshot = "ButtonTakeSnapshot"; private const string _NameSelection = "NameSelection"; private const string _StaticAvatar = "StaticAvatar"; + private const string _StaticPopupBG = "StaticPopupBG"; + private const string _TextPopup = "TextPopup"; + private const string _ButtonPopupYes = "ButtonPopupYes"; + private const string _ButtonPopupNo = "ButtonPopupNo"; + private const string _ButtonPopupCancel = "ButtonPopupCancel"; private bool _ProfilesChanged; private bool _AvatarsChanged; private bool _SelectingKeyboardActive; @@ -67,6 +79,9 @@ namespace Vocaluxe.Screens private Dictionary _SelectSlideGuids = new Dictionary(); private EEditMode _EditMode; + private EProfilesPopup _Popup; + private bool _UnsavedChanges; + private string _NameBeforeEdit = string.Empty; private CTextureRef _WebcamTexture; private Bitmap _Snapshot; @@ -76,9 +91,13 @@ namespace Vocaluxe.Screens base.Init(); _ThemeButtons = new string[] - { _ButtonPlayerName, _ButtonExit, _ButtonSave, _ButtonNew, _ButtonDelete, _ButtonWebcam, _ButtonSaveSnapshot, _ButtonDiscardSnapshot, _ButtonTakeSnapshot }; + { + _ButtonPlayerName, _ButtonExit, _ButtonSave, _ButtonNew, _ButtonDelete, _ButtonWebcam, _ButtonSaveSnapshot, _ButtonDiscardSnapshot, _ButtonTakeSnapshot, + _ButtonPopupYes, _ButtonPopupNo, _ButtonPopupCancel + }; _ThemeSelectSlides = new string[] { _SelectSlideProfiles, _SelectSlideDifficulty, _SelectSlideAvatars, _SelectSlideUserRole, _SelectSlideActive }; - _ThemeStatics = new string[] { _StaticAvatar }; + _ThemeStatics = new string[] { _StaticAvatar, _StaticPopupBG }; + _ThemeTexts = new string[] { _TextPopup }; _ThemeNameSelections = new string[] { _NameSelection }; _EditMode = EEditMode.None; @@ -100,10 +119,18 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlideUserRole].SetValues(0); _SelectSlides[_SelectSlideActive].SetValues(0); _Statics[_StaticAvatar].Aspect = EAspect.Crop; + _NameSelections[_NameSelection].ShowInactive = true; + _ShowPopup(EProfilesPopup.None); } public override bool HandleInput(SKeyEvent keyEvent) { + if (_Popup != EProfilesPopup.None) + { + _HandlePopupInput(keyEvent); + return true; + } + if (_SelectingKeyboardActive) { switch (keyEvent.Key) @@ -163,6 +190,7 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlideProfiles].RenameValue( CProfiles.AddGetPlayerName(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), keyEvent.Unicode)); _ProfilesChanged = true; + _UnsavedChanges = true; break; } } @@ -173,11 +201,11 @@ namespace Vocaluxe.Screens case Keys.Escape: if (_EditMode == EEditMode.PlayerName) { - _EditMode = EEditMode.None; + _EndNameEdit(true); } else { - CGraphics.FadeTo(EScreen.Main); + _Leave(); } break; @@ -185,7 +213,7 @@ namespace Vocaluxe.Screens case Keys.Enter: if (_Buttons[_ButtonExit].Selected) { - CGraphics.FadeTo(EScreen.Main); + _Leave(); } else if (_Buttons[_ButtonSave].Selected) { @@ -197,18 +225,11 @@ namespace Vocaluxe.Screens } else if (_Buttons[_ButtonPlayerName].Selected) { - if (CProfiles.NumProfiles > 0 && _EditMode != EEditMode.PlayerName) - { - _EditMode = EEditMode.PlayerName; - } - else - { - _EditMode = EEditMode.None; - } + _ToggleNameEdit(); } else if (_Buttons[_ButtonDelete].Selected) { - _DeleteProfile(); + _RequestDeleteProfile(); } else if (_Buttons[_ButtonWebcam].Selected) { @@ -230,44 +251,27 @@ namespace Vocaluxe.Screens break; case Keys.Back: + case Keys.Delete: if (_EditMode == EEditMode.PlayerName) { _SelectSlides[_SelectSlideProfiles].RenameValue( CProfiles.GetDeleteCharInPlayerName(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag))); _ProfilesChanged = true; + _UnsavedChanges = true; + } + else if (keyEvent.Key == Keys.Delete) + { + _RequestDeleteProfile(); } else { - CGraphics.FadeTo(EScreen.Main); + _Leave(); } break; - - case Keys.Delete: - _DeleteProfile(); - break; } - if (_SelectSlides[_SelectSlideDifficulty].Selected) - { - CProfiles.SetDifficulty(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - (EGameDifficulty)_SelectSlides[_SelectSlideDifficulty].Selection); - } - else if (_SelectSlides[_SelectSlideAvatars].Selected) - { - CProfiles.SetAvatar(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - _SelectSlides[_SelectSlideAvatars].SelectedTag); - } - else if (_SelectSlides[_SelectSlideUserRole].Selected) - { - CProfiles.SetUserRoleProfile(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - (EUserRole)_SelectSlides[_SelectSlideUserRole].Selection); - } - else if (_SelectSlides[_SelectSlideActive].Selected) - { - CProfiles.SetActive(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - (EOffOn)_SelectSlides[_SelectSlideActive].Selection); - } + _ApplySelectSlideValues(); } return true; @@ -275,6 +279,12 @@ namespace Vocaluxe.Screens public override bool HandleMouse(SMouseEvent mouseEvent) { + if (_Popup != EProfilesPopup.None) + { + _HandlePopupMouse(mouseEvent); + return true; + } + if (_EditMode == EEditMode.None) { base.HandleMouse(mouseEvent); @@ -293,7 +303,7 @@ namespace Vocaluxe.Screens { if (_Buttons[_ButtonExit].Selected) { - CGraphics.FadeTo(EScreen.Main); + _Leave(); } else if (_Buttons[_ButtonSave].Selected) { @@ -305,42 +315,16 @@ namespace Vocaluxe.Screens } else if (_Buttons[_ButtonDelete].Selected) { - _DeleteProfile(); + _RequestDeleteProfile(); } else if (_Buttons[_ButtonPlayerName].Selected) { - if (CProfiles.NumProfiles > 0 && _EditMode != EEditMode.PlayerName) - { - _EditMode = EEditMode.PlayerName; - } - else - { - _EditMode = EEditMode.None; - } + _ToggleNameEdit(); } - else if (_SelectSlides[_SelectSlideDifficulty].Selected) + else if (_SelectSlides[_SelectSlideDifficulty].Selected || _SelectSlides[_SelectSlideAvatars].Selected || + _SelectSlides[_SelectSlideUserRole].Selected || _SelectSlides[_SelectSlideActive].Selected) { - CProfiles.SetDifficulty(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - (EGameDifficulty)_SelectSlides[_SelectSlideDifficulty].Selection); - } - else if (_SelectSlides[_SelectSlideAvatars].Selected) - { - CProfiles.SetAvatar(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - _SelectSlides[_SelectSlideAvatars].SelectedTag); - if (CWebcam.IsDeviceAvailable() && _WebcamTexture != null) - { - _OnDiscardSnapshot(); - } - } - else if (_SelectSlides[_SelectSlideUserRole].Selected) - { - CProfiles.SetUserRoleProfile(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - (EUserRole)_SelectSlides[_SelectSlideUserRole].Selection); - } - else if (_SelectSlides[_SelectSlideActive].Selected) - { - CProfiles.SetActive(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), - (EOffOn)_SelectSlides[_SelectSlideActive].Selection); + _ApplySelectSlideValues(); } else if (_Buttons[_ButtonWebcam].Selected) { @@ -362,7 +346,7 @@ namespace Vocaluxe.Screens if (mouseEvent.RB) { - CGraphics.FadeTo(EScreen.Main); + _Leave(); } if (mouseEvent.Wheel != 0 && CHelper.IsInBounds(_NameSelections[_NameSelection].Rect, mouseEvent)) @@ -435,9 +419,260 @@ namespace Vocaluxe.Screens base.OnClose(); _EditMode = EEditMode.None; _SelectingKeyboardActive = false; + _ShowPopup(EProfilesPopup.None); _OnDiscardSnapshot(); } + private void _Leave() + { + _EndNameEdit(false); + if (_UnsavedChanges) + { + _ShowPopup(EProfilesPopup.UnsavedChanges); + return; + } + + CGraphics.FadeTo(EScreen.Main); + } + + private void _DiscardChanges() + { + _UnsavedChanges = false; + CProfiles.LoadProfiles(); + } + + private void _ShowPopup(EProfilesPopup popup) + { + _Popup = popup; + var visible = popup != EProfilesPopup.None; + _Statics[_StaticPopupBG].Visible = visible; + _Texts[_TextPopup].Visible = visible; + _Buttons[_ButtonPopupYes].Visible = visible; + _Buttons[_ButtonPopupNo].Visible = popup == EProfilesPopup.UnsavedChanges; + _Buttons[_ButtonPopupCancel].Visible = visible; + + switch (popup) + { + case EProfilesPopup.Delete: + var name = CProfiles.GetPlayerName(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag)); + _Texts[_TextPopup].Text = CLanguage.Translate("TR_SCREENPROFILES_POPUP_DELETE").Replace("%s", name); + _SelectElement(_Buttons[_ButtonPopupCancel]); + break; + + case EProfilesPopup.UnsavedChanges: + _Texts[_TextPopup].Text = CLanguage.Translate("TR_SCREENPROFILES_POPUP_UNSAVED"); + _SelectElement(_Buttons[_ButtonPopupYes]); + break; + } + } + + private List _GetPopupButtons() + { + return new[] { _ButtonPopupYes, _ButtonPopupNo, _ButtonPopupCancel }.Where(name => _Buttons[name].Visible).ToList(); + } + + private void _HandlePopupInput(SKeyEvent keyEvent) + { + if (keyEvent.KeyPressed) + { + return; + } + + var buttons = _GetPopupButtons(); + var selected = buttons.FindIndex(name => _Buttons[name].Selected); + switch (keyEvent.Key) + { + case Keys.Left: + case Keys.Up: + _SelectElement(_Buttons[buttons[(selected - 1 + buttons.Count) % buttons.Count]]); + break; + + case Keys.Right: + case Keys.Down: + case Keys.Tab: + _SelectElement(_Buttons[buttons[(selected + 1) % buttons.Count]]); + break; + + case Keys.Escape: + case Keys.Back: + _ExecutePopupButton(_ButtonPopupCancel); + break; + + case Keys.Enter: + _ExecutePopupButton(selected >= 0 ? buttons[selected] : _ButtonPopupCancel); + break; + } + } + + private void _HandlePopupMouse(SMouseEvent mouseEvent) + { + foreach (var name in _GetPopupButtons()) + { + if (!CHelper.IsInBounds(_Buttons[name].Rect, mouseEvent)) + { + continue; + } + + if (!_Buttons[name].Selected) + { + _SelectElement(_Buttons[name]); + } + + if (mouseEvent.LB) + { + _ExecutePopupButton(name); + } + + return; + } + + if (mouseEvent.RB) + { + _ExecutePopupButton(_ButtonPopupCancel); + } + } + + private void _ExecutePopupButton(string button) + { + var popup = _Popup; + _ShowPopup(EProfilesPopup.None); + + if (popup == EProfilesPopup.Delete) + { + if (button == _ButtonPopupYes) + { + _DeleteProfile(); + } + + _SelectElement(_Buttons[_ButtonDelete]); + } + else if (popup == EProfilesPopup.UnsavedChanges) + { + if (button == _ButtonPopupCancel) + { + _SelectElement(_Buttons[_ButtonSave]); + return; + } + + if (button == _ButtonPopupYes) + { + _SaveProfiles(); + } + else + { + _DiscardChanges(); + } + + CGraphics.FadeTo(EScreen.Main); + } + } + + private void _RequestDeleteProfile() + { + _EndNameEdit(false); + if (!CProfiles.IsProfileIdValid(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag))) + { + return; + } + + _ShowPopup(EProfilesPopup.Delete); + } + + private void _ToggleNameEdit() + { + if (_EditMode == EEditMode.PlayerName) + { + _EndNameEdit(false); + } + else + { + _StartNameEdit(); + } + } + + private void _StartNameEdit() + { + var id = _GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag); + if (!CProfiles.IsProfileIdValid(id)) + { + return; + } + + _NameBeforeEdit = CProfiles.GetPlayerName(id); + _EditMode = EEditMode.PlayerName; + } + + private void _EndNameEdit(bool restore) + { + if (_EditMode != EEditMode.PlayerName) + { + return; + } + + _EditMode = EEditMode.None; + var id = _GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag); + if (!restore && !string.IsNullOrWhiteSpace(CProfiles.GetPlayerName(id))) + { + return; + } + + var name = string.IsNullOrWhiteSpace(_NameBeforeEdit) ? CProfiles.GetPlayerName(Guid.Empty) : _NameBeforeEdit; + CProfiles.SetPlayerName(id, name); + _SelectSlides[_SelectSlideProfiles].RenameValue(name); + _ProfilesChanged = true; + } + + private void _ApplySelectSlideValues() + { + var id = _GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag); + if (!CProfiles.IsProfileIdValid(id)) + { + return; + } + + if (_SelectSlides[_SelectSlideDifficulty].Selected) + { + var difficulty = (EGameDifficulty)_SelectSlides[_SelectSlideDifficulty].Selection; + if (difficulty != CProfiles.GetDifficulty(id)) + { + CProfiles.SetDifficulty(id, difficulty); + _UnsavedChanges = true; + } + } + else if (_SelectSlides[_SelectSlideAvatars].Selected) + { + var avatarId = _SelectSlides[_SelectSlideAvatars].SelectedTag; + if (avatarId != CProfiles.GetAvatarId(id)) + { + CProfiles.SetAvatar(id, avatarId); + _UnsavedChanges = true; + if (_WebcamTexture != null || CWebcam.IsCapturing()) + { + _ResetSnapshot(); + } + } + } + else if (_SelectSlides[_SelectSlideUserRole].Selected) + { + var userRole = (EUserRole)_SelectSlides[_SelectSlideUserRole].Selection; + if (userRole != CProfiles.GetUserRoleProfile(id)) + { + CProfiles.SetUserRoleProfile(id, userRole); + _UnsavedChanges = true; + } + } + else if (_SelectSlides[_SelectSlideActive].Selected) + { + var active = (EOffOn)_SelectSlides[_SelectSlideActive].Selection; + if (active != CProfiles.GetActive(id)) + { + CProfiles.SetActive(id, active); + _UnsavedChanges = true; + _NameSelections[_NameSelection].UpdateList(); + } + } + } + private void _OnProfileChanged(EProfileChangedFlags flags) { if (EProfileChangedFlags.Avatar == (EProfileChangedFlags.Avatar & flags)) @@ -484,14 +719,23 @@ namespace Vocaluxe.Screens private void _OnDiscardSnapshot() { + _ResetSnapshot(); + _SelectElement(_Buttons[_ButtonWebcam]); + } + + private void _ResetSnapshot() + { + if (CWebcam.IsCapturing()) + { + CWebcam.Stop(); + } + _Snapshot = null; CDraw.RemoveTexture(ref _WebcamTexture); _Buttons[_ButtonSaveSnapshot].Visible = false; _Buttons[_ButtonDiscardSnapshot].Visible = false; _Buttons[_ButtonTakeSnapshot].Visible = false; _Buttons[_ButtonWebcam].Visible = CWebcam.IsDeviceAvailable(); - - _SelectElement(_Buttons[_ButtonWebcam]); } private void _OnSaveSnapshot() @@ -509,6 +753,7 @@ namespace Vocaluxe.Screens var id = CProfiles.NewAvatar(file); CProfiles.SetAvatar(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), id); + _UnsavedChanges = true; _LoadAvatars(false); _NameSelections[_NameSelection].UpdateList(); @@ -535,7 +780,7 @@ namespace Vocaluxe.Screens private void _NewProfile() { - _EditMode = EEditMode.None; + _EndNameEdit(false); var id = CProfiles.NewProfile(); _LoadProfiles(false); var num = CProfiles.NumProfiles; @@ -546,20 +791,23 @@ namespace Vocaluxe.Screens _NameSelections[_NameSelection].UpdateList(); _SelectElement(_Buttons[_ButtonPlayerName]); + _UnsavedChanges = true; + _NameBeforeEdit = string.Empty; _EditMode = EEditMode.PlayerName; } private void _SaveProfiles() { - _EditMode = EEditMode.None; + _EndNameEdit(false); CProfiles.SaveProfiles(); + _UnsavedChanges = false; _LoadProfiles(true); _NameSelections[_NameSelection].UpdateList(); } private void _DeleteProfile() { - _EditMode = EEditMode.None; + _EndNameEdit(false); CProfiles.DeleteProfile(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag)); _SelectSlideGuids.Remove(_SelectSlides[_SelectSlideProfiles].SelectedTag); @@ -660,6 +908,7 @@ namespace Vocaluxe.Screens return; } + _EndNameEdit(false); var entry = _SelectSlideGuids.FirstOrDefault(x => x.Value.Equals(profileId)); if (_SelectSlideGuids.ContainsKey(entry.Key)) { diff --git a/Vocaluxe/Screens/CScreenSing.cs b/Vocaluxe/Screens/CScreenSing.cs index 7894bdae..e6330cfc 100644 --- a/Vocaluxe/Screens/CScreenSing.cs +++ b/Vocaluxe/Screens/CScreenSing.cs @@ -39,7 +39,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 14; } + get { return 16; } } private struct STimeRect @@ -57,6 +57,11 @@ namespace Vocaluxe.Screens private const string _TextMedleyCountdown = "TextMedleyCountdown"; private const string _TextPauseSongName = "TextPauseSongName"; private const string _TextPauseVocalsVolume = "TextPauseVocalsVolume"; + private const string _TextPauseArtist = "TextPauseArtist"; + private const string _TextPauseTimeCurrent = "TextPauseTimeCurrent"; + private const string _TextPauseTimeRemaining = "TextPauseTimeRemaining"; + private const string _TextPauseName = "TextPauseNameP"; + private const string _TextPauseScore = "TextPauseScoreP"; private string[,,] _TextScores; private string[,,] _TextNames; private List _TextsPause; @@ -75,6 +80,10 @@ namespace Vocaluxe.Screens private const string _StaticLyricHelperDuet = "StaticLyricHelperDuet"; private const string _StaticLyricHelperTop = "StaticLyricHelperTop"; private const string _StaticCountdownRing = "StaticCountdownRing"; + private const string _StaticPauseCover = "StaticPauseCover"; + private const string _StaticPauseTimeLineProgress = "StaticPauseTimeLineProgress"; + private const string _StaticPauseVocalsIcon = "StaticPauseVocalsIcon"; + private const string _StaticPauseAvatar = "StaticPauseAvatarP"; private List _StaticsPause; private string[,,] _StaticScores; @@ -89,6 +98,14 @@ namespace Vocaluxe.Screens private const string _ButtonRestartGame = "ButtonRestartGame"; private const string _ButtonSkip = "ButtonSkip"; + private static readonly string[] _PauseButtons = { _ButtonContinue, _ButtonSkip, _ButtonRestartRound, _ButtonRestartGame, _ButtonCancel }; + private static readonly string[] _PauseIcons = + { "StaticPauseIconContinue", "StaticPauseIconSkip", "StaticPauseIconRestartRound", "StaticPauseIconRestartGame", "StaticPauseIconCancel" }; + private SRectF[] _PauseButtonSlots; + private SRectF[] _PauseIconOffsets; + private float _PauseTimeLineW; + private float _PauseVocalsIconOffset; + private const string _SelectSlidePauseVocalsVolume = "SelectSlidePauseVocalsVolume"; private List _SelectSlidesPause; @@ -261,6 +278,18 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlidePauseVocalsVolume].Selection = CConfig.VocalsVolume / 5; _Statics[_StaticCountdownRing].Visible = false; + _PauseButtonSlots = _PauseButtons.Select(b => _Buttons[b].Rect).OrderBy(r => r.Y).ThenBy(r => r.X).ToArray(); + _PauseIconOffsets = new SRectF[_PauseButtons.Length]; + for (var i = 0; i < _PauseButtons.Length; i++) + { + var button = _Buttons[_PauseButtons[i]].Rect; + var icon = _Statics[_PauseIcons[i]].Rect; + _PauseIconOffsets[i] = new SRectF(icon.X - button.X, icon.Y - button.Y, icon.W, icon.H, icon.Z); + } + + _PauseTimeLineW = _Statics[_StaticPauseTimeLineProgress].W; + _PauseVocalsIconOffset = _Statics[_StaticPauseVocalsIcon].X - _Texts[_TextPauseVocalsVolume].Rect.X; + //Automatically find statics and texts with pause prefix foreach (var s in _Statics.Where(s => s.ThemeLoaded && s.GetThemeName().StartsWith("StaticPause"))) { @@ -272,7 +301,7 @@ namespace Vocaluxe.Screens _TextsPause.Add(t.GetThemeName()); } - foreach (var t in _Texts.Where(s => s.ThemeLoaded && s.GetThemeName().StartsWith("SelectSlidePause"))) + foreach (var t in _SelectSlides.Where(s => s.ThemeLoaded && s.GetThemeName().StartsWith("SelectSlidePause"))) { _SelectSlidesPause.Add(t.GetThemeName()); } @@ -290,7 +319,7 @@ namespace Vocaluxe.Screens _TogglePause(); if (_Pause) { - _SelectElement(_Buttons[_ButtonCancel]); + _SelectElement(_Buttons[_ButtonContinue]); } break; @@ -332,16 +361,16 @@ namespace Vocaluxe.Screens break; case Keys.S: - if (CGame.NumRounds > CGame.RoundNr) + if (keyEvent.ModCtrl) { - if (keyEvent.ModCtrl) + if (CGame.NumRounds > CGame.RoundNr) { _NextSong(); } - } - else - { - _ShowInfoText(CBase.Language.Translate("TR_SCREENSING_NOMORESONGS")); + else + { + _ShowInfoText(CBase.Language.Translate("TR_SCREENSING_NOMORESONGS")); + } } break; @@ -650,6 +679,7 @@ namespace Vocaluxe.Screens else if (_StartDelayed) { _UpdateStartCountdown(); + _UpdateRatingPopups(); return true; } @@ -1001,7 +1031,7 @@ namespace Vocaluxe.Screens } } - private void _UpdateDuetNames(CText textName, Stopwatch timer) + private void _UpdateDuetNames(CText textName, Stopwatch timer, CLyric lyric) { if (timer.IsRunning) { @@ -1029,7 +1059,7 @@ namespace Vocaluxe.Screens timer.Stop(); } } - else if (!timer.IsRunning && timer.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainTop].Alpha > 0 && CGame.GetSong().IsDuet) + else if (!timer.IsRunning && timer.ElapsedMilliseconds == 0 && lyric.Alpha > 0 && CGame.GetSong().IsDuet) { timer.Start(); } @@ -1047,42 +1077,9 @@ namespace Vocaluxe.Screens } //Timer for first duet-part - _UpdateDuetNames(_Texts[_TextDuetName1], _TimerDuetText1); + _UpdateDuetNames(_Texts[_TextDuetName1], _TimerDuetText1, _Lyrics[_LyricMainTop]); //Timer for second duet-part - if (_TimerDuetText2.IsRunning) - { - var t = _TimerDuetText2.ElapsedMilliseconds / 1000f; - if (t < 10f) - { - _Texts[_TextDuetName2].Visible = true; - - if (t < 3f) - { - _Texts[_TextDuetName2].Color.A = (3f - (3f - t)) / 3f; - } - else if (t < 7f) - { - _Texts[_TextDuetName2].Color.A = 1f; - } - else - { - _Texts[_TextDuetName2].Color.A = (3f - (t - 7f)) / 3f; - } - } - else - { - _Texts[_TextDuetName2].Visible = false; - _TimerDuetText2.Stop(); - } - } - else if (!_TimerDuetText2.IsRunning && _TimerDuetText2.ElapsedMilliseconds == 0 && _Lyrics[_LyricMainDuet].Alpha > 0 && CGame.GetSong().IsDuet) - { - _TimerDuetText2.Start(); - } - else - { - _Texts[_TextDuetName2].Visible = false; - } + _UpdateDuetNames(_Texts[_TextDuetName2], _TimerDuetText2, _Lyrics[_LyricMainDuet]); } private void _UpdateTimeLine() @@ -1298,6 +1295,11 @@ namespace Vocaluxe.Screens } } + if (_Pause) + { + _UpdatePauseIconColors(); + } + var pauseAnimation = _GetPauseAnimation(out var pauseAlpha, out var pauseScale); if (pauseAnimation) { @@ -1457,14 +1459,28 @@ namespace Vocaluxe.Screens _Texts[_TextMedleyCountdown].Text = string.Empty; _Texts[_TextMedleyCountdown].Visible = true; + _SetPlayerInfoAlpha(0f); return; } _StartSongNow(); } + private void _SetPlayerInfoAlpha(float alpha) + { + for (var p = 0; p < CGame.NumPlayers; p++) + { + _Statics[_PlayerStaticAvatar[p]].Alpha = alpha; + _Statics[_PlayerStaticScore[p]].Alpha = alpha; + _Texts[_PlayerTextName[p]].Alpha = alpha; + _Texts[_PlayerTextScore[p]].Alpha = alpha; + _ProgressBars[_PlayerProgressBarRating[p]].Alpha = alpha; + } + } + private void _StartSongNow() { + _SetPlayerInfoAlpha(1f); _PrepareTimeLine(); CSound.Play(_CurrentStream); @@ -1625,7 +1641,7 @@ namespace Vocaluxe.Screens _PauseAnimationBackgrounds.Clear(); _PauseAnimationElements.Clear(); - _PauseAnimationBackgrounds.AddRange(_StaticsPause.Select(s => (IMenuElement)_Statics[s]).Where(s => s.Visible)); + _PauseAnimationBackgrounds.AddRange(_StaticsPause.Select(s => (IMenuElement)_Statics[s]).Where(s => s.Visible && _IsFullScreen(s))); var elements = new List { @@ -1636,9 +1652,89 @@ namespace Vocaluxe.Screens _Buttons[_ButtonRestartRound], _SelectSlides[_SelectSlidePauseVocalsVolume] }; + elements.AddRange(_StaticsPause.Select(s => (IMenuElement)_Statics[s]).Where(s => !_IsFullScreen(s))); elements.AddRange(_SelectSlidesPause.Select(s => (IMenuElement)_SelectSlides[s])); elements.AddRange(_TextsPause.Select(s => (IMenuElement)_Texts[s])); - _PauseAnimationElements.AddRange(elements.Distinct().Where(e => e.Visible)); + _PauseAnimationElements.AddRange(elements.Distinct().Where(e => e.Visible).OrderByDescending(e => e.Rect.Z)); + } + + private static bool _IsFullScreen(IMenuElement element) + { + return element.Rect.W >= CSettings.RenderW && element.Rect.H >= CSettings.RenderH; + } + + private void _ArrangePauseButtons() + { + var slot = 0; + for (var i = 0; i < _PauseButtons.Length; i++) + { + var button = _Buttons[_PauseButtons[i]]; + var icon = _Statics[_PauseIcons[i]]; + icon.Visible = button.Visible; + if (!button.Visible) + { + continue; + } + + var rect = _PauseButtonSlots[slot++]; + button.X = rect.X; + button.Y = rect.Y; + icon.X = rect.X + _PauseIconOffsets[i].X; + icon.Y = rect.Y + _PauseIconOffsets[i].Y; + } + } + + private void _UpdatePauseIconColors() + { + for (var i = 0; i < _PauseButtons.Length; i++) + { + var text = _Buttons[_PauseButtons[i]].Text; + _Statics[_PauseIcons[i]].Color = text.Selected ? text.SelColor : text.Color; + } + } + + private void _UpdatePauseInfo() + { + var song = CGame.GetSong(); + if (song != null) + { + var endTime = Math.Abs(song.End) > 0.001 ? song.End : CSound.GetLength(_CurrentStream); + var length = endTime - song.Start; + var currentTime = Math.Max(0f, _CurrentTime - song.Start); + + _Texts[_TextPauseTimeCurrent].Text = _FormatPauseTime(currentTime); + _Texts[_TextPauseTimeRemaining].Text = "-" + _FormatPauseTime(Math.Max(0f, endTime - _CurrentTime)); + _Statics[_StaticPauseTimeLineProgress].W = length > 0f ? _PauseTimeLineW * Math.Min(1f, currentTime / length) : 0f; + } + + for (var i = 0; i < CSettings.MaxNumPlayer; i++) + { + var avatar = _Statics[_StaticPauseAvatar + (i + 1)]; + var name = _Texts[_TextPauseName + (i + 1)]; + var score = _Texts[_TextPauseScore + (i + 1)]; + var visible = i < CGame.NumPlayers && CProfiles.IsProfileIdValid(CGame.Players[i].ProfileId); + + avatar.Visible = visible; + name.Visible = visible; + score.Visible = visible; + if (!visible) + { + continue; + } + + avatar.Texture = CProfiles.GetAvatarTextureFromProfile(CGame.Players[i].ProfileId) ?? CBase.Themes.GetSkinTexture("NoAvatar", PartyModeId); + avatar.Aspect = EAspect.Crop; + name.Text = CProfiles.GetPlayerName(CGame.Players[i].ProfileId); + score.Text = CGame.Players[i].Points.ToString(CGame.Players[i].Points < 10000 ? "0000" : "00000"); + score.Color = new SColorF(CBase.Themes.GetPlayerColor(i + 1), score.Color.A); + } + } + + private static string _FormatPauseTime(float time) + { + var min = (int)Math.Floor(time / 60f); + var sec = (int)(time - min * 60f); + return min.ToString("00") + ":" + sec.ToString("00"); } private void _SetPause(bool paused) @@ -1676,6 +1772,14 @@ namespace Vocaluxe.Screens _SelectSlides[_SelectSlidePauseVocalsVolume].Visible = _Pause && CGame.AudioMode == EAudioMode.TR_AUDIOMODE_VOCALS; _Texts[_TextPauseVocalsVolume].Visible = _Pause && CGame.AudioMode == EAudioMode.TR_AUDIOMODE_VOCALS; + _Statics[_StaticPauseVocalsIcon].Visible = _Pause && CGame.AudioMode == EAudioMode.TR_AUDIOMODE_VOCALS; + + if (_Pause) + { + _ArrangePauseButtons(); + _UpdatePauseInfo(); + _Statics[_StaticPauseVocalsIcon].X = _Texts[_TextPauseVocalsVolume].Rect.X + _PauseVocalsIconOffset; + } if (pauseChanged && paused) { @@ -1731,8 +1835,13 @@ namespace Vocaluxe.Screens CConfig.VocalsVolume = _SelectSlides[_SelectSlidePauseVocalsVolume].Selection * 5; CConfig.SaveConfig(); CSound.SetStreamVolume(_CurrentStreamVocals, CConfig.VocalsVolume); - CSound.SetPosition(_CurrentStream, _PausePosition); - CSound.SetPosition(_CurrentStreamVocals, _PausePosition); + if (_PausePosition >= 0f) + { + CSound.SetPosition(_CurrentStream, _PausePosition); + CSound.SetPosition(_CurrentStreamVocals, _PausePosition); + _PausePosition = -1f; + } + // Start both streams simultaneously CSound.Play(_CurrentStream); CSound.Play(_CurrentStreamVocals); @@ -1780,7 +1889,10 @@ namespace Vocaluxe.Screens } _Texts[_TextSongName].Text = songname; - _Texts[_TextPauseSongName].Text = songname; + _Texts[_TextPauseSongName].Text = rounds > 1 ? song.Title + " (" + CGame.RoundNr + "/" + rounds + ")" : song.Title; + _Texts[_TextPauseArtist].Text = song.Artist; + _Statics[_StaticPauseCover].Texture = song.CoverTextureSmall; + _Statics[_StaticPauseCover].Aspect = EAspect.Crop; if (CGame.AudioMode == EAudioMode.TR_AUDIOMODE_INSTRUMENTAL || CGame.AudioMode == EAudioMode.TR_AUDIOMODE_KARAOKE) { @@ -1928,6 +2040,7 @@ namespace Vocaluxe.Screens _CurrentStreamVocals = -1; } + _PausePosition = -1f; CRecord.Stop(); if (_CurrentVideo != null) { @@ -2091,10 +2204,11 @@ namespace Vocaluxe.Screens _SingNotes[_SingBars].Visible = true; } - _Texts[_PlayerTextName[player]].Visible = CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || - CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_NAME; - _Statics[_PlayerStaticAvatar[player]].Visible = CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || - CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_AVATAR; + var validProfile = CProfiles.IsProfileIdValid(CGame.Players[player].ProfileId); + _Texts[_PlayerTextName[player]].Visible = validProfile && (CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || + CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_NAME); + _Statics[_PlayerStaticAvatar[player]].Visible = validProfile && (CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_BOTH || + CConfig.Config.Theme.PlayerInfo == EPlayerInfo.TR_CONFIG_PLAYERINFO_AVATAR); } _Lyrics[_LyricMain].Alpha = 0f; @@ -2643,7 +2757,8 @@ namespace Vocaluxe.Screens { if (CProfiles.IsProfileIdValid(CGame.Players[i].ProfileId)) { - _Statics[_PlayerStaticAvatar[i]].Texture = CProfiles.GetAvatarTextureFromProfile(CGame.Players[i].ProfileId); + _Statics[_PlayerStaticAvatar[i]].Texture = CProfiles.GetAvatarTextureFromProfile(CGame.Players[i].ProfileId) ?? + CBase.Themes.GetSkinTexture("NoAvatar", PartyModeId); } else { diff --git a/Vocaluxe/Screens/CScreenStatistics.cs b/Vocaluxe/Screens/CScreenStatistics.cs index 14937a02..4b18ef42 100644 --- a/Vocaluxe/Screens/CScreenStatistics.cs +++ b/Vocaluxe/Screens/CScreenStatistics.cs @@ -28,7 +28,7 @@ namespace Vocaluxe.Screens { protected override int _ScreenVersion { - get { return 1; } + get { return 2; } } private const int _NumTiles = 4; @@ -191,6 +191,11 @@ namespace Vocaluxe.Screens 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() diff --git a/Vocaluxe/Screens/CScreenStatisticsDetail.cs b/Vocaluxe/Screens/CScreenStatisticsDetail.cs index 2de1ef32..55cc7f48 100644 --- a/Vocaluxe/Screens/CScreenStatisticsDetail.cs +++ b/Vocaluxe/Screens/CScreenStatisticsDetail.cs @@ -38,7 +38,7 @@ namespace Vocaluxe.Screens { protected override int _ScreenVersion { - get { return 1; } + get { return 2; } } private sealed class CRow @@ -76,6 +76,9 @@ namespace Vocaluxe.Screens private float _MainColumnX; private float _MainColumnW; private float _ListLeft; + private float _FirstColumnX; + private float _FirstColumnW; + private EAlignment _FirstColumnAlign; private readonly List _Rows = new List(); private string[] _Headers = new string[_NumColumns]; @@ -126,6 +129,9 @@ namespace Vocaluxe.Screens _MainColumnX = _Texts[_TextCell[0, 1]].X; _MainColumnW = _Texts[_TextCell[0, 1]].W; _ListLeft = _Statics[_StaticRank[0]].X; + _FirstColumnX = _Texts[_TextCell[0, 0]].X; + _FirstColumnW = _Texts[_TextCell[0, 0]].W; + _FirstColumnAlign = _Texts[_TextCell[0, 0]].Align; } public override void OnShow() @@ -405,6 +411,15 @@ namespace Vocaluxe.Screens var mainX = string.IsNullOrEmpty(_Headers[0]) ? _ListLeft : _MainColumnX; _Texts[_TextHeader[1]].X = mainX; + + var dateColumn = Page == EStatisticsPage.Recent; + foreach (var text in Enumerable.Range(0, _NumRows).Select(r => _Texts[_TextCell[r, 0]]).Concat(new[] { _Texts[_TextHeader[0]] })) + { + text.Align = dateColumn ? EAlignment.Left : _FirstColumnAlign; + text.X = dateColumn ? _ListLeft : _FirstColumnX; + text.W = dateColumn ? _AvatarMainX - _ListLeft - 10 : _FirstColumnW; + } + for (var r = 0; r < _NumRows; r++) { _Texts[_TextCell[r, 1]].X = mainX; diff --git a/VocaluxeLib/Menu/CNameSelection.cs b/VocaluxeLib/Menu/CNameSelection.cs index 4e66c6d2..36d1f121 100644 --- a/VocaluxeLib/Menu/CNameSelection.cs +++ b/VocaluxeLib/Menu/CNameSelection.cs @@ -99,6 +99,9 @@ namespace VocaluxeLib.Menu private readonly List _VisibleProfiles; private readonly List _UsedProfiles; + private readonly HashSet _InactiveProfiles = new HashSet(); + + public bool ShowInactive; private CStatic _PlayerSelector; @@ -378,8 +381,10 @@ namespace VocaluxeLib.Menu { if (i + offset * _Theme.Tiles.NumW < _VisibleProfiles.Count) { + var alpha = _InactiveProfiles.Contains(_VisibleProfiles[i + offset * _Theme.Tiles.NumW]) ? 0.4f : 1f; _Tiles[i].Avatar.Texture = CBase.Profiles.GetAvatar(_VisibleProfiles[i + offset * _Theme.Tiles.NumW]); - _Tiles[i].Avatar.Color = new SColorF(1, 1, 1, 1); + _Tiles[i].Avatar.Color = new SColorF(1, 1, 1, alpha); + _Tiles[i].Name.Alpha = alpha; _Tiles[i].Name.Text = CBase.Profiles.GetPlayerName(_VisibleProfiles[i + offset * _Theme.Tiles.NumW]); _Tiles[i].ProfileId = _VisibleProfiles.ElementAt(i + offset * _Theme.Tiles.NumW); } @@ -387,6 +392,7 @@ namespace VocaluxeLib.Menu { _Tiles[i].Avatar.Texture = TextureEmptyTile; _Tiles[i].Avatar.Color = _ColorEmptyTile; + _Tiles[i].Name.Alpha = 1f; _Tiles[i].Name.Text = ""; _Tiles[i].ProfileId = Guid.Empty; } @@ -514,11 +520,18 @@ namespace VocaluxeLib.Menu private void _UpdateVisibleProfiles() { _VisibleProfiles.Clear(); + _InactiveProfiles.Clear(); var profiles = CBase.Profiles.GetProfiles(); foreach (var profile in profiles) { var visible = profile.Active == EOffOn.TR_CONFIG_ON; + if (!visible && ShowInactive) + { + visible = true; + _InactiveProfiles.Add(profile.Id); + } + if (visible) { if (_UsedProfiles.Contains(profile.Id) && (int)profile.UserRole >= (int)EUserRole.TR_USERROLE_NORMAL)