#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 . #endregion using System; using System.Collections.Generic; using System.Linq; using System.Xml.Serialization; using VocaluxeLib.Draw; namespace VocaluxeLib.Menu { [XmlType("NameSelection")] public struct SThemeNameSelection { [XmlAttribute(AttributeName = "Name")] public string Name; public SRectF Rect; public string SkinEmptyTile; public SThemeColor ColorEmptyTile; public string SkinTileSelected; public SThemeNameSelectionTiles Tiles; } public struct SThemeNameSelectionTiles { public int W; public int H; public int NumW; public int NumH; public float SpaceW; public float SpaceH; public SThemeNameSelectionName Name; } public struct SThemeNameSelectionName { public float Space; [XmlElement("H")] public float Height; public string Font; public EStyle Style; public SThemeColor Color; } public class CNameSelection : CMenuElementBase, IMenuElement, IThemeable { private class CTile { public Guid ProfileId; public readonly CStatic Avatar; public readonly CText Name; public CTile(CStatic av, CText tex, Guid pId) { Avatar = av; Name = tex; ProfileId = pId; } } private readonly int _PartyModeId; private SThemeNameSelection _Theme; public string GetThemeName() { return _Theme.Name; } public bool ThemeLoaded { get; private set; } private readonly List _Tiles; private CTextureRef _TextureTileSelected; public CTextureRef TextureEmptyTile { get; private set; } private SColorF _ColorEmptyTile; private SColorF _ColorNameTile; public int Offset; private int _ActualSelection = -1; public Guid SelectedId = Guid.Empty; private int _Player = -1; private readonly List _VisibleProfiles; private readonly List _UsedProfiles; private readonly HashSet _InactiveProfiles = new HashSet(); public bool ShowInactive; private CStatic _PlayerSelector; private SRectF _Rect; public override SRectF Rect { get { return _Rect; } } public bool Selectable { get { return Visible; } } public CNameSelection(int partyModeId) { _PartyModeId = partyModeId; _Theme = new SThemeNameSelection { Tiles = new SThemeNameSelectionTiles { Name = new SThemeNameSelectionName() } }; _Tiles = new List(); _VisibleProfiles = new List(); _UsedProfiles = new List(); } public CNameSelection(SThemeNameSelection theme, int partyModeId) { _PartyModeId = partyModeId; _Theme = theme; _Tiles = new List(); _VisibleProfiles = new List(); _UsedProfiles = new List(); ThemeLoaded = true; } public void Init() { _UsedProfiles.Clear(); _PrepareTiles(); _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() { var i = 0; foreach (var tile in _Tiles) { tile.Avatar.Draw(); tile.Name.Draw(); if (_PlayerSelector.Visible) { //Update PlayerSelector-Coords if (_Player > -1 && _ActualSelection == i) { _PlayerSelector.X = tile.Avatar.Rect.X - 3; _PlayerSelector.Y = tile.Avatar.Rect.Y - 3; } } i++; } if (_PlayerSelector.Visible) { //Draw PlayerSelector _PlayerSelector.Draw(); } } public void HandleInput(SKeyEvent kevent) { if (_Tiles.Count == 0 || _VisibleProfiles.Count == 0) { _ActualSelection = -1; SelectedId = Guid.Empty; return; } if (_ActualSelection < 0 || _ActualSelection >= _Tiles.Count || _Tiles[_ActualSelection].ProfileId == Guid.Empty) { _ActualSelection = _Tiles.FindIndex(t => t.ProfileId != Guid.Empty); if (_ActualSelection < 0) { SelectedId = Guid.Empty; return; } } switch (kevent.Key) { case Keys.Right: if (_ActualSelection + 1 < _Tiles.Count) { if (_Tiles[_ActualSelection + 1].ProfileId != Guid.Empty) { _ActualSelection++; } } else { var oldOffset = Offset; UpdateList(Offset + 1); if (oldOffset != Offset) { _ActualSelection = Math.Max(0, _ActualSelection - (_Theme.Tiles.NumW - 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.Up: if (_ActualSelection - _Theme.Tiles.NumW >= 0) { _ActualSelection -= _Theme.Tiles.NumW; } else if (Offset > 0) { var 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; case Keys.Down: if (_ActualSelection + _Theme.Tiles.NumW < _Tiles.Count && _Tiles[_ActualSelection + _Theme.Tiles.NumW].ProfileId != Guid.Empty) { _ActualSelection += _Theme.Tiles.NumW; } else { var oldOffset = Offset; var 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) { for (var i = 0; i < _Tiles.Count; i++) { if (CHelper.IsInBounds(_Tiles[i].Avatar.Rect, mevent) && _Tiles[i].ProfileId != Guid.Empty) { _ActualSelection = i; if (Offset * _Theme.Tiles.NumW + _ActualSelection < _VisibleProfiles.Count) { SelectedId = _VisibleProfiles.ElementAt(Offset * _Theme.Tiles.NumW + _ActualSelection); } else { SelectedId = Guid.Empty; } } } } public void FastSelection(bool active, int player) { //Overwrite player-selection; Same profile, but other player if (active && SelectedId != Guid.Empty) { _Player = player; _PlayerSelector.Color = CBase.Themes.GetPlayerColor(player); } //Normal activation else if (active) { if (_VisibleProfiles.Count > 0) { SelectedId = _VisibleProfiles.ElementAt(0); _ActualSelection = 0; } else { SelectedId = Guid.Empty; _ActualSelection = -1; } _Player = player; _PlayerSelector.Color = CBase.Themes.GetPlayerColor(player); _PlayerSelector.Visible = true; } //Deactivate else { SelectedId = Guid.Empty; _ActualSelection = -1; _Player = -1; _PlayerSelector.Visible = false; } } public void UpdateList() { _UpdateVisibleProfiles(); if (_Theme.Tiles.NumW * (Offset + 1) - _VisibleProfiles.Count >= _Theme.Tiles.NumW * Offset) { UpdateList(Offset - 1); } else { UpdateList(Offset); } } public void UpdateList(int offset) { offset = offset.Clamp(0, _GetMaxOffset()); for (var i = 0; i < _Tiles.Count; i++) { 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, 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); } else { _Tiles[i].Avatar.Texture = TextureEmptyTile; _Tiles[i].Avatar.Color = _ColorEmptyTile; _Tiles[i].Name.Alpha = 1f; _Tiles[i].Name.Text = ""; _Tiles[i].ProfileId = Guid.Empty; } } Offset = offset; } public bool IsOverTile(SMouseEvent mevent) { var isOver = false; foreach (var tile in _Tiles) { if (CHelper.IsInBounds(tile.Avatar.Rect, mevent)) { isOver = true; } } return isOver; } public Guid TilePlayerId(SMouseEvent mevent) { foreach (var tile in _Tiles) { if (CHelper.IsInBounds(tile.Avatar.Rect, mevent)) { return tile.ProfileId; } } return Guid.Empty; } public CStatic TilePlayerAvatar(SMouseEvent mevent) { foreach (var tile in _Tiles) { if (CHelper.IsInBounds(tile.Avatar.Rect, mevent)) { return tile.Avatar; } } return new CStatic(_PartyModeId); } public void UnloadSkin() { } public void LoadSkin() { TextureEmptyTile = CBase.Themes.GetSkinTexture(_Theme.SkinEmptyTile, _PartyModeId); _TextureTileSelected = CBase.Themes.GetSkinTexture(_Theme.SkinTileSelected, _PartyModeId); _Theme.ColorEmptyTile.Get(_PartyModeId, out _ColorEmptyTile); _Theme.Tiles.Name.Color.Get(_PartyModeId, out _ColorNameTile); MaxRect = _Theme.Rect; } public void ReloadSkin() { UnloadSkin(); LoadSkin(); _PrepareTiles(); } public void UseProfile(Guid id) { if (id != Guid.Empty) { if (!_UsedProfiles.Contains(id) && CBase.Profiles.IsProfileIdValid(id) && !CBase.Profiles.IsGuest(id)) { _UsedProfiles.Add(id); UpdateList(); } } } public void RemoveUsedProfile(Guid id) { if (id != Guid.Empty) { _UsedProfiles.Remove(id); UpdateList(); } } public Guid GetRandomUnusedProfile() { var unusedProfiles = _VisibleProfiles.Where(profileId => !_UsedProfiles.Contains(profileId)).ToList(); if (unusedProfiles.Count == 0) { return Guid.Empty; } return unusedProfiles[CBase.Game.GetRandom(unusedProfiles.Count)]; } private void _PrepareTiles() { _Tiles.Clear(); for (var i = 0; i < _Theme.Tiles.NumH; i++) { for (var j = 0; j < _Theme.Tiles.NumW; j++) { var rect = new SRectF(MaxRect.X + j * (_Theme.Tiles.W + _Theme.Tiles.SpaceW), MaxRect.Y + i * (_Theme.Tiles.H + _Theme.Tiles.SpaceH), _Theme.Tiles.W, _Theme.Tiles.H, MaxRect.Z); var tileStatic = new CStatic(_PartyModeId, TextureEmptyTile, _ColorEmptyTile, rect) { Aspect = EAspect.Crop }; var tileText = new CText(rect.X + rect.W / 2, rect.Y + rect.H + _Theme.Tiles.Name.Space, rect.Z, _Theme.Tiles.Name.Height, rect.W, EAlignment.Center, _Theme.Tiles.Name.Style, _Theme.Tiles.Name.Font, _ColorNameTile, ""); _Tiles.Add(new CTile(tileStatic, tileText, Guid.Empty)); } } _Rect.X = MaxRect.X; _Rect.Y = MaxRect.Y; _Rect.Right = _Tiles[_Tiles.Count - 1].Avatar.Rect.Right; _Rect.Bottom = _Tiles[_Tiles.Count - 1].Name.Rect.Bottom; _Rect.Z = MaxRect.Z; } 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) { visible = false; } } if (visible) { _VisibleProfiles.Add(profile.Id); } } } private int _GetMaxOffset() { var maxOffset = (int)Math.Ceiling((decimal)(_VisibleProfiles.Count - _Tiles.Count) / _Theme.Tiles.NumW); if (maxOffset < 0) { return 0; } return maxOffset; } public object GetTheme() { return _Theme; } #region ThemeEdit public void MoveElement(int stepX, int stepY) { X += stepX; Y += stepY; _Theme.Rect.X += stepX; _Theme.Rect.Y += stepY; } public void ResizeElement(int stepW, int stepH) { W += stepW; if (W <= 0) { W = 1; } H += stepH; if (H <= 0) { H = 1; } _Theme.Rect.W = W; _Theme.Rect.H = H; } #endregion ThemeEdit } }