// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 using System; using System.Drawing; namespace ClassicalSharp.Gui.Widgets { public abstract class PlayerListWidget : Widget { protected readonly Font font; public PlayerListWidget(Game game, Font font) : base(game) { HorizontalAnchor = Anchor.Centre; VerticalAnchor = Anchor.Centre; this.font = font; } protected int columnPadding = 5; protected int elementOffset = 0; protected const int boundsSize = 10; protected const int namesPerColumn = 20; protected int namesCount = 0; protected Texture[] textures; protected int columns; protected int xMin, xMax, yHeight; protected static FastColour tableCol = new FastColour(50, 50, 50, 205); public override void Init() { CreateInitialPlayerInfo(); SortPlayerInfo(); } public abstract string GetNameUnder(int mouseX, int mouseY); public override void Render(double delta) { gfx.Texturing = false; gfx.Draw2DQuad(X, Y, Width, Height, tableCol); gfx.Texturing = true; for (int i = 0; i < namesCount; i++) { Texture texture = textures[i]; if (texture.IsValid) texture.Render(gfx); } } public override void Dispose() { for (int i = 0; i < namesCount; i++) { Texture tex = textures[i]; gfx.DeleteTexture(ref tex); textures[i] = tex; } } protected void UpdateTableDimensions() { int width = xMax - xMin; X = xMin - boundsSize; Y = game.Height / 2 - yHeight / 2 - boundsSize; Width = width + boundsSize * 2; Height = yHeight + boundsSize * 2; } protected void CalcMaxColumnHeight() { yHeight = 0; for (int col = 0; col < columns; col++) { yHeight = Math.Max(GetColumnHeight(col), yHeight); } } protected int GetColumnWidth(int column) { int i = column * namesPerColumn; int maxWidth = 0; int maxIndex = Math.Min(namesCount, i + namesPerColumn); for (; i < maxIndex; i++) maxWidth = Math.Max(maxWidth, textures[i].Width); return maxWidth + columnPadding + elementOffset; } protected int GetColumnHeight(int column) { int i = column * namesPerColumn; int total = 0; int maxIndex = Math.Min(namesCount, i + namesPerColumn); for (; i < maxIndex; i++) total += textures[i].Height + 1; return total; } protected void SetColumnPos(int column, int x, int y) { int i = column * namesPerColumn; int maxIndex = Math.Min(namesCount, i + namesPerColumn); for (; i < maxIndex; i++) { Texture tex = textures[i]; tex.X1 = x; tex.Y1 = y; y += tex.Height + 1; if (ShouldOffset(i)) tex.X1 += elementOffset; textures[i] = tex; } } protected virtual bool ShouldOffset(int i) { return true; } public void RecalcYOffset() { YOffset = -Math.Max(0, game.Height / 4 - Height / 2); } public override void CalculatePosition() { int oldX = X, oldY = Y; base.CalculatePosition(); for (int i = 0; i < namesCount; i++) { textures[i].X1 += X - oldX; textures[i].Y1 += Y - oldY; } } protected abstract void CreateInitialPlayerInfo(); protected abstract void SortInfoList(); protected void RemoveInfoAt(T[] info, int i) { Texture tex = textures[i]; gfx.DeleteTexture(ref tex); RemoveItemAt(info, i); RemoveItemAt(textures, i); namesCount--; SortPlayerInfo(); } protected void RemoveItemAt(T[] array, int index) { for (int i = index; i < namesCount - 1; i++) { array[i] = array[i + 1]; } array[namesCount - 1] = default(T); } protected void SortPlayerInfo() { columns = Utils.CeilDiv(namesCount, namesPerColumn); SortInfoList(); columns = Utils.CeilDiv(namesCount, namesPerColumn); CalcMaxColumnHeight(); int y = game.Height / 2 - yHeight / 2; int midCol = columns / 2; int centreX = game.Width / 2; int offset = 0; if (columns % 2 != 0) { // For an odd number of columns, the middle column is centred. offset = Utils.CeilDiv(GetColumnWidth(midCol), 2); } xMin = centreX - offset; for (int col = midCol - 1; col >= 0; col--) { xMin -= GetColumnWidth(col); SetColumnPos(col, xMin, y); } xMax = centreX - offset; for (int col = midCol; col < columns; col++) { SetColumnPos(col, xMax, y); xMax += GetColumnWidth(col); } OnSort(); UpdateTableDimensions(); RecalcYOffset(); CalculatePosition(); } protected virtual void OnSort() { } } }