From 76d26239bdb854c2bf86db23d8def0619a987ce1 Mon Sep 17 00:00:00 2001 From: Edi316 <61267443+Edi316@users.noreply.github.com> Date: Sun, 26 Apr 2026 20:50:15 +0200 Subject: [PATCH] Grid overview for profile screen (#858) * Add Profile Grid * Add Profile Grid * Add Profile Grid * Add Profile Grid * Version 4 * Add Profile Grid * Add Profile Grid * Add Profile Grid * Fix Out of Bounds Index & Player Selector Cursor * Add Profile Grid * Fix Out of Bounds Index & Player Selector Cursor --- .../Changelog/Changelog_ScreenProfiles.txt | 6 +- .../Vocaluxe 2024/Screens/ScreenProfiles.xml | 150 +++++++++------- Vocaluxe/Screens/CScreenProfiles.cs | 93 +++++++++- VocaluxeLib/Menu/CNameSelection.cs | 162 +++++++++++------- 4 files changed, 283 insertions(+), 128 deletions(-) diff --git a/Output/Themes/Changelog/Changelog_ScreenProfiles.txt b/Output/Themes/Changelog/Changelog_ScreenProfiles.txt index 3c741fc1..0f2cf2ff 100644 --- a/Output/Themes/Changelog/Changelog_ScreenProfiles.txt +++ b/Output/Themes/Changelog/Changelog_ScreenProfiles.txt @@ -1,4 +1,8 @@ ScreenProfiles +++++++++++ +Version 4: +Add: + ++++++++++ Version 3: Rename: to @@ -7,4 +11,4 @@ Rename: to Version 2: Add: , , , -++++++++++ \ No newline at end of file +++++++++++ diff --git a/Output/Themes/Vocaluxe 2024/Screens/ScreenProfiles.xml b/Output/Themes/Vocaluxe 2024/Screens/ScreenProfiles.xml index ca077519..34efd80c 100644 --- a/Output/Themes/Vocaluxe 2024/Screens/ScreenProfiles.xml +++ b/Output/Themes/Vocaluxe 2024/Screens/ScreenProfiles.xml @@ -2,7 +2,7 @@ ScreenProfiles - 3 + 4 @@ -29,7 +29,7 @@ - 1147.5 + 1340 150 240 240 @@ -53,11 +53,11 @@ TR_SCREENPROFILES_PROFILES - 112.5 - 430.5 + 730 + 435.5 0 40.5 - 0 + 295 Left @@ -67,11 +67,11 @@ TR_SCREENPROFILES_PLAYERNAME - 112.5 - 520.5 + 730 + 525.5 0 40.5 - 0 + 295 Left @@ -81,11 +81,11 @@ TR_SCREENPROFILES_GAMEDIFFICULTY - 112.5 - 610.5 + 730 + 615.5 0 40.5 - 0 + 295 Left @@ -95,11 +95,11 @@ TR_SCREENPROFILES_AVATAR - 112.5 - 700.5 + 730 + 705.5 0 40.5 - 0 + 295 Left @@ -109,11 +109,11 @@ TR_SCREENPROFILES_USERROLE - 112.5 - 790.5 + 730 + 795.5 0 40.5 - 0 + 295 Left @@ -128,20 +128,20 @@ SelectSlide - 750 + 1040 420 - 1072.5 + 840 75 0 - 532.5 - 15 + 420 + 5 0 60 - 1053 + 800 Center @@ -155,7 +155,7 @@ Button Button - 112.5 + 50 900 225 75 @@ -190,7 +190,7 @@ Button Button - 682.5 + 1050 900 225 75 @@ -225,7 +225,7 @@ Button Button - 997.5 + 1347.5 900 225 75 @@ -260,7 +260,7 @@ Button Button - 1312.5 + 1645 900 225 75 @@ -295,7 +295,7 @@ Button Button - 1627.5 + 752.5 900 225 75 @@ -330,7 +330,7 @@ Button Button - 1147.5 + 1340 270 240 75 @@ -357,7 +357,7 @@ Button Button - 1147.5 + 1340 195 240 75 @@ -384,7 +384,7 @@ Button Button - 1627.5 + 752.5 900 225 75 @@ -427,21 +427,21 @@ SelectSlideArrowLeft SelectSlideArrowRight - 750 + 1040 217.5 - 1072.5 + 840 120 0 - 757.5 + 1050 247.5 60 60 0 - 1755 + 1810 247.5 60 60 @@ -454,9 +454,9 @@ 40.5 - 75 + 65 0 - 328.8 + 630 Outline Bold 0 @@ -469,21 +469,21 @@ SelectSlideArrowLeft SelectSlideArrowRight - 750 + 1040 510 - 1072.5 + 840 75 0 - 757.5 + 1050 517.5 60 60 0 - 1755 + 1810 517.5 60 60 @@ -496,9 +496,9 @@ 40.5 - 75 + 65 0 - 313.01 + 630 Outline Bold 1 @@ -511,21 +511,21 @@ SelectSlideArrowLeft SelectSlideArrowRight - 750 + 1040 600 - 1072.5 + 840 75 0 - 757.5 + 1050 607.5 60 60 0 - 1755 + 1810 607.5 60 60 @@ -538,9 +538,9 @@ 40.5 - 75 + 65 0 - 313.01 + 630 Outline Bold 1 @@ -553,21 +553,21 @@ SelectSlideArrowLeft SelectSlideArrowRight - 750 + 1040 690 - 1072.5 + 840 75 0 - 757.5 + 1050 697.5 60 60 0 - 1755 + 1810 697.5 60 60 @@ -580,9 +580,9 @@ 40.5 - 75 + 65 0 - 469.5 + 630 Outline Bold 1 @@ -595,21 +595,21 @@ SelectSlideArrowLeft SelectSlideArrowRight - 750 + 1040 780 - 1072.5 + 840 75 0 - 757.5 + 1050 787.5 60 60 0 - 1755 + 1810 787.5 60 60 @@ -622,16 +622,44 @@ 40.5 - 75 + 65 0 - 469.5 + 630 Outline Bold 1 - + + + + 50 + 195 + 1230 + 540 + 0 + + PlayerTile + + PlayerSelector + + 150 + 150 + 4 + 4 + 10 + 10 + + -20 + 25.5 + Outline + + + + + + diff --git a/Vocaluxe/Screens/CScreenProfiles.cs b/Vocaluxe/Screens/CScreenProfiles.cs index a7365c0d..88ef1767 100644 --- a/Vocaluxe/Screens/CScreenProfiles.cs +++ b/Vocaluxe/Screens/CScreenProfiles.cs @@ -1,4 +1,4 @@ -#region license +#region license // This file is part of Vocaluxe. // // Vocaluxe is free software: you can redistribute it and/or modify @@ -41,7 +41,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 3; } + get { return 4; } } private const string _SelectSlideProfiles = "SelectSlideProfiles"; @@ -58,10 +58,11 @@ namespace Vocaluxe.Screens private const string _ButtonSaveSnapshot = "ButtonSaveSnapshot"; private const string _ButtonDiscardSnapshot = "ButtonDiscardSnapshot"; private const string _ButtonTakeSnapshot = "ButtonTakeSnapshot"; - + private const string _NameSelection = "NameSelection"; private const string _StaticAvatar = "StaticAvatar"; private bool _ProfilesChanged; private bool _AvatarsChanged; + private bool _SelectingKeyboardActive; private Dictionary _SelectSlideGuids = new Dictionary(); @@ -78,10 +79,12 @@ namespace Vocaluxe.Screens {_ButtonPlayerName, _ButtonExit, _ButtonSave, _ButtonNew, _ButtonDelete, _ButtonWebcam, _ButtonSaveSnapshot, _ButtonDiscardSnapshot, _ButtonTakeSnapshot}; _ThemeSelectSlides = new string[] {_SelectSlideProfiles, _SelectSlideDifficulty, _SelectSlideAvatars, _SelectSlideUserRole, _SelectSlideActive}; _ThemeStatics = new string[] {_StaticAvatar}; + _ThemeNameSelections = new string[] { _NameSelection }; _EditMode = EEditMode.None; _ProfilesChanged = false; _AvatarsChanged = false; + _SelectingKeyboardActive = false; CProfiles.AddProfileChangedCallback(_OnProfileChanged); } @@ -101,6 +104,46 @@ namespace Vocaluxe.Screens public override bool HandleInput(SKeyEvent keyEvent) { + if (_SelectingKeyboardActive) + { + switch (keyEvent.Key) + { + case Keys.Left: + case Keys.Right: + case Keys.Up: + case Keys.Down: + _NameSelections[_NameSelection].HandleInput(keyEvent); + return true; + + case Keys.Enter: + if (_NameSelections[_NameSelection].SelectedID != Guid.Empty) + _SelectProfileById(_NameSelections[_NameSelection].SelectedID); + + _NameSelections[_NameSelection].FastSelection(false, -1); + _SelectingKeyboardActive = false; + _SelectElement(_Buttons[_ButtonPlayerName]); + return true; + + case Keys.Escape: + case Keys.Back: + _NameSelections[_NameSelection].FastSelection(false, -1); + _SelectingKeyboardActive = false; + _SelectElement(_Buttons[_ButtonExit]); + return true; + } + } + + if (_EditMode == EEditMode.None && keyEvent.Key == Keys.Up && _Buttons[_ButtonExit].Selected) + { + if (CProfiles.NumProfiles <= 0) + return true; + + _SelectingKeyboardActive = true; + _NameSelections[_NameSelection].Init(); + _NameSelections[_NameSelection].UpdateList(); + _NameSelections[_NameSelection].FastSelection(true, 1); + } + if (_EditMode == EEditMode.None) base.HandleInput(keyEvent); @@ -199,6 +242,15 @@ namespace Vocaluxe.Screens if (_EditMode == EEditMode.None) base.HandleMouse(mouseEvent); + _NameSelections[_NameSelection].HandleMouse(mouseEvent); + + if (mouseEvent.LB && _NameSelections[_NameSelection].IsOverTile(mouseEvent)) + { + Guid profileId = _NameSelections[_NameSelection].TilePlayerID(mouseEvent); + _SelectProfileById(profileId); + return true; + } + if (mouseEvent.LB && _IsMouseOverCurSelection(mouseEvent)) { if (_Buttons[_ButtonExit].Selected) @@ -250,16 +302,29 @@ namespace Vocaluxe.Screens if (mouseEvent.RB) CGraphics.FadeTo(EScreen.Main); + + if (mouseEvent.Wheel != 0 && CHelper.IsInBounds(_NameSelections[_NameSelection].Rect, mouseEvent)) + { + int offset = _NameSelections[_NameSelection].Offset + mouseEvent.Wheel; + _NameSelections[_NameSelection].UpdateList(offset); + } + return true; } public override bool UpdateGame() { if (_AvatarsChanged) + { _LoadAvatars(true); + _NameSelections[_NameSelection].UpdateList(); + } if (_ProfilesChanged) + { _LoadProfiles(true); + _NameSelections[_NameSelection].UpdateList(); + } if (_SelectSlides[_SelectSlideProfiles].Selection > -1) { @@ -291,6 +356,7 @@ namespace Vocaluxe.Screens public override void OnShow() { base.OnShow(); + _NameSelections[_NameSelection].Init(); _LoadAvatars(false); _LoadProfiles(false); UpdateGame(); @@ -300,6 +366,7 @@ namespace Vocaluxe.Screens { base.OnClose(); _EditMode = EEditMode.None; + _SelectingKeyboardActive = false; _OnDiscardSnapshot(); } @@ -368,6 +435,7 @@ namespace Vocaluxe.Screens int id = CProfiles.NewAvatar(file); CProfiles.SetAvatar(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), id); _LoadAvatars(false); + _NameSelections[_NameSelection].UpdateList(); _SelectElement(_Buttons[_ButtonSave]); } @@ -400,6 +468,7 @@ namespace Vocaluxe.Screens CProfiles.SetAvatar(id, _SelectSlides[_SelectSlideAvatars].SelectedTag); + _NameSelections[_NameSelection].UpdateList(); _SelectElement(_Buttons[_ButtonPlayerName]); _EditMode = EEditMode.PlayerName; } @@ -408,6 +477,8 @@ namespace Vocaluxe.Screens { _EditMode = EEditMode.None; CProfiles.SaveProfiles(); + _LoadProfiles(true); + _NameSelections[_NameSelection].UpdateList(); } private void _DeleteProfile() @@ -416,6 +487,7 @@ namespace Vocaluxe.Screens CProfiles.DeleteProfile(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag)); _SelectSlideGuids.Remove(_SelectSlides[_SelectSlideProfiles].SelectedTag); + _NameSelections[_NameSelection].UpdateList(); int selection = _SelectSlides[_SelectSlideProfiles].Selection; if (_SelectSlides[_SelectSlideProfiles].NumValues - 1 > selection) @@ -462,7 +534,10 @@ namespace Vocaluxe.Screens } if (_EditMode == EEditMode.PlayerName) + { CProfiles.SetPlayerName(_GetIdFromTag(_SelectSlides[_SelectSlideProfiles].SelectedTag), name); + _NameSelections[_NameSelection].UpdateList(); + } } _ProfilesChanged = false; } @@ -489,6 +564,16 @@ namespace Vocaluxe.Screens _AvatarsChanged = false; } + private void _SelectProfileById(Guid profileId) + { + if (profileId == Guid.Empty) + return; + + KeyValuePair entry = _SelectSlideGuids.FirstOrDefault(x => x.Value.Equals(profileId)); + if (_SelectSlideGuids.ContainsKey(entry.Key)) + _SelectSlides[_SelectSlideProfiles].SelectedTag = entry.Key; + } + private Guid _GetIdFromTag(int tag) { if (tag == -1 || !_SelectSlideGuids.ContainsKey(tag)) @@ -497,4 +582,4 @@ namespace Vocaluxe.Screens return _SelectSlideGuids[tag]; } } -} \ No newline at end of file +} diff --git a/VocaluxeLib/Menu/CNameSelection.cs b/VocaluxeLib/Menu/CNameSelection.cs index 5894b8e6..44050f02 100644 --- a/VocaluxeLib/Menu/CNameSelection.cs +++ b/VocaluxeLib/Menu/CNameSelection.cs @@ -142,14 +142,17 @@ namespace VocaluxeLib.Menu { _UsedProfiles.Clear(); _PrepareTiles(); - - _PlayerSelector = new CStatic(_PartyModeID, _TextureTileSelected, new SColorF(), new SRectF(0, 0, _Theme.Tiles.W + 6, _Theme.Tiles.H + 6, Rect.Z - 0.5f)) - { - Visible = false - }; + + _PlayerSelector = new CStatic(_PartyModeID, _TextureTileSelected, new SColorF(), new SRectF(0, 0, _Theme.Tiles.W + 10, _Theme.Tiles.H + 10, Rect.Z - 0.5f)) + { + Visible = true + }; _UpdateVisibleProfiles(); UpdateList(0); + + _ActualSelection = _Tiles.FindIndex(t => t.ProfileID != Guid.Empty); + SelectedID = _ActualSelection >= 0 ? _Tiles[_ActualSelection].ProfileID : Guid.Empty; } public void Draw() @@ -181,69 +184,104 @@ namespace VocaluxeLib.Menu public void HandleInput(SKeyEvent kevent) { - switch (kevent.Key) - { - case Keys.Right: - if (_ActualSelection + 1 < _Tiles.Count) - { - if (_Tiles[_ActualSelection + 1].ProfileID != Guid.Empty) - _ActualSelection++; - } - else - { - int offset = Offset; - UpdateList(Offset + 1); - if (offset != Offset) - _ActualSelection -= _Theme.Tiles.NumW - 1; - } - break; + if (_Tiles.Count == 0 || _VisibleProfiles.Count == 0) + { + _ActualSelection = -1; + SelectedID = Guid.Empty; + return; + } - case Keys.Left: - if (_ActualSelection - 1 > -1) - _ActualSelection--; - else if (Offset > 0) + if (_ActualSelection < 0 || _ActualSelection >= _Tiles.Count || _Tiles[_ActualSelection].ProfileID == Guid.Empty) + { + _ActualSelection = _Tiles.FindIndex(t => t.ProfileID != Guid.Empty); + if (_ActualSelection < 0) { - UpdateList(Offset - 1); - _ActualSelection += _Theme.Tiles.NumW - 1; + SelectedID = Guid.Empty; + return; } - break; + } + + switch (kevent.Key) + { + case Keys.Right: + if (_ActualSelection + 1 < _Tiles.Count) + { + if (_Tiles[_ActualSelection + 1].ProfileID != Guid.Empty) + _ActualSelection++; + } + else + { + int oldOffset = Offset; + UpdateList(Offset + 1); + if (oldOffset != Offset) + _ActualSelection = Math.Max(0, _ActualSelection - (_Theme.Tiles.NumW - 1)); + } + break; - case Keys.Up: - if (_ActualSelection - _Theme.Tiles.NumW > -1) - _ActualSelection -= _Theme.Tiles.NumW; - else if (Offset > 0) - { - UpdateList(Offset - 1); - } - break; + case Keys.Left: + if (_ActualSelection - 1 >= 0) + { + _ActualSelection--; + } + else if (Offset > 0) + { + UpdateList(Offset - 1); + _ActualSelection = Math.Min(_Tiles.Count - 1, _ActualSelection + (_Theme.Tiles.NumW - 1)); + while (_ActualSelection >= 0 && _Tiles[_ActualSelection].ProfileID == Guid.Empty) + _ActualSelection--; + } + break; - case Keys.Down: - if (_ActualSelection + _Theme.Tiles.NumW < _Tiles.Count) - { - if (_Tiles[_ActualSelection + _Theme.Tiles.NumW].ProfileID != Guid.Empty) - _ActualSelection += _Theme.Tiles.NumW; - } - else - { - int offset = Offset; - UpdateList(Offset + 1); - } - if (_Tiles[_ActualSelection].ProfileID == Guid.Empty) - { - _ActualSelection = _Tiles.Count - _Theme.Tiles.NumW; - while(_Tiles[_ActualSelection + 1].ProfileID != Guid.Empty) - { - _ActualSelection++; - } - } - break; - } + case Keys.Up: + if (_ActualSelection - _Theme.Tiles.NumW >= 0) + { + _ActualSelection -= _Theme.Tiles.NumW; + } + else if (Offset > 0) + { + int currentColumn = _ActualSelection % _Theme.Tiles.NumW; + UpdateList(Offset - 1); + _ActualSelection = currentColumn; + if (_ActualSelection >= _Tiles.Count) + _ActualSelection = _Tiles.Count - 1; + while (_ActualSelection >= 0 && _Tiles[_ActualSelection].ProfileID == Guid.Empty) + _ActualSelection--; + } + break; - if (Offset * _Theme.Tiles.NumW + _ActualSelection < _VisibleProfiles.Count) - SelectedID = _VisibleProfiles.ElementAt(Offset * _Theme.Tiles.NumW + _ActualSelection); - else - SelectedID = Guid.Empty; - } + case Keys.Down: + if (_ActualSelection + _Theme.Tiles.NumW < _Tiles.Count && + _Tiles[_ActualSelection + _Theme.Tiles.NumW].ProfileID != Guid.Empty) + { + _ActualSelection += _Theme.Tiles.NumW; + } + else + { + int oldOffset = Offset; + int currentColumn = _ActualSelection % _Theme.Tiles.NumW; + UpdateList(Offset + 1); + + if (oldOffset != Offset) + { + _ActualSelection = currentColumn; + while (_ActualSelection < _Tiles.Count && _Tiles[_ActualSelection].ProfileID == Guid.Empty) + _ActualSelection++; + if (_ActualSelection >= _Tiles.Count || _Tiles[_ActualSelection].ProfileID == Guid.Empty) + _ActualSelection = _Tiles.FindLastIndex(t => t.ProfileID != Guid.Empty); + } + } + break; + } + + if (_ActualSelection >= 0 && _ActualSelection < _Tiles.Count && _Tiles[_ActualSelection].ProfileID != Guid.Empty) + { + SelectedID = _Tiles[_ActualSelection].ProfileID; + } + else + { + SelectedID = Guid.Empty; + } + } public void HandleMouse(SMouseEvent mevent) {