using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using System.Windows.Forms; using RyzStudio.Windows.Forms; namespace RyzStudio.Windows.TileForms { public class TileContainer : RyzStudio.Windows.Forms.TTogglePanel { public TileContainer() { this.AllowDrop = true; this.ForeColor = Color.FromArgb(31, 31, 31); this.HeaderPadding = new Padding(10, 0, 0, 0); } private const int PADDING_BOTTOM = 10; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public Size TileSize { get; set; } = new Size(70, 70); [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public int TileMargin { get; set; } = 3; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public bool AutoSizeHeight { get; set; } = false; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] public List> TileCollection { get; set; } = new List>(); public int ColumnCount { get { if (this.TileCollection.Count <= 0) { return 1; } return (this.TileCollection?.Max(x => x.Item2.X) ?? 0) + 1; } } public int RowCount { get { if (this.TileCollection.Count <= 0) { return 1; } return (this.TileCollection?.Max(x => x.Item2.Y) ?? 0) + 1; } } public Size HotRectangle { get => new Size((this.ContentRectangle.Width - SystemInformation.VerticalScrollBarWidth), this.ContentRectangle.Height); } public Size GridSize { get { var tileWidth = TileSize.Width + TileMargin; var tileHeight = TileSize.Height + TileMargin; var columns = (int)Math.Floor(decimal.Divide(this.HotRectangle.Width, tileWidth)); var rows = (int)Math.Floor(decimal.Divide(this.HotRectangle.Height, tileHeight)); return new Size(columns, rows); } } protected override void OnControlAdded(ControlEventArgs e) { base.OnControlAdded(e); if (e.Control == null) { return; } if (!(e.Control is Tile)) { return; } var newTile = (Tile)e.Control; newTile.OnMoved += (object sender, EventArgs e) => { var control = (System.Windows.Forms.Control)sender; var coord = this.GetCoord(control); coord = this.ValidateCoord(coord); MoveTile(control, coord); }; var coord = GetCoord(e.Control); MoveTile(e.Control, coord); } protected override void OnControlRemoved(ControlEventArgs e) { base.OnControlRemoved(e); var n = this.TileCollection.FindIndex(x => x.Item1 == e.Control); this.TileCollection.RemoveAt(n); } public void Add(Control control, int x, int y) { var pos = GetLocation(new Point(x, y)); control.Location = pos; UIControl.Invoke(this, (x) => this.Controls.Add(control)); } public void AddRow() { var gridSize = this.GridSize; this.AutoSize(gridSize.Width, (gridSize.Height + 1)); } public void RemoveRow() { var gridSize = this.GridSize; var minGridSize = this.GetMinGridSize(); var y = Math.Max((gridSize.Height - 1), minGridSize.Height); this.AutoSize(gridSize.Width, y); } public new void AutoSize(int x, int y) { var tileWidth = TileSize.Width + TileMargin; var tileHeight = TileSize.Height + TileMargin; var w = (tileWidth * x) + this.ContentRectangle.Left + SystemInformation.VerticalScrollBarWidth; var h = (tileHeight * y) + this.ContentRectangle.Top; h += PADDING_BOTTOM; this.ExpandedHeight = h; UIControl.Invoke(this, (x) => this.Size = new Size(w, h)); this.IsOpen = this.IsOpen; } public void Clear() { if (this.TileCollection == null) { this.TileCollection = new List>(); } this.Controls.Clear(); this.TileCollection.Clear(); } public Point GetCoord(System.Windows.Forms.Control control) { var tileWidth = TileSize.Width + TileMargin; var tileHeight = TileSize.Height + TileMargin; var x = control.Left - this.ContentRectangle.Left; var y = control.Top - this.ContentRectangle.Top; var colX = (int)Math.Floor(decimal.Divide(x, tileWidth)); var colY = (int)Math.Floor(decimal.Divide(y, tileHeight)); colX = Math.Max(colX, 0); colY = Math.Max(colY, 0); return new Point(colX, colY); } public Size GetMinGridSize() { var x = Math.Max(this.ColumnCount, 1); var y = Math.Max(this.RowCount, 1); return new Size(x, y); } public Point GetNextCoord() { var y = Math.Max(this.RowCount, 1) - 1; var x = -1; if (this.TileCollection.Count > 0) { x = (this.TileCollection?.Where(x => x.Item2.Y == y)?.Max(x => x.Item2.X) ?? 0); } return GetNextCoord(new Point(x, y)); } public Point GetNextCoord(Point coord) { var gridSize = this.GridSize; var x = (coord.X + 1); var y = coord.Y; if (x >= gridSize.Width) { x = 0; y++; } return new Point(x, y); } public new void Invalidate() { base.Invalidate(); if (this.TileCollection == null) { this.TileCollection = new List>(); } this.TileCollection.Clear(); foreach (var item in this.Controls) { var control = (System.Windows.Forms.Control)item; var coord = GetCoord(control); MoveTile(control, coord); } } public void MoveTile(System.Windows.Forms.Control control, Point newCoord) { var n = this.TileCollection.FindIndex(x => x.Item1 == control); if (n < 0) { // Add to collection this.TileCollection.Add(new Tuple(control, newCoord)); n = this.TileCollection.FindIndex(x => x.Item1 == control); } this.TileCollection[n] = new Tuple(control, newCoord); var newLocation = GetLocation(newCoord); control.Location = new Point(newLocation.X, newLocation.Y); // Auto-resize for height if (this.AutoSizeHeight) { var gridSize = this.GridSize; var newHeight = (this.TileCollection?.Max(x => x.Item2.Y) ?? 0) + 1; this.AutoSize(gridSize.Width, Math.Max(gridSize.Height, newHeight)); } // Handle displaced tile var duplicateTile = this.TileCollection.Where(x => ((x.Item1 != control) && (x.Item2 == newCoord))).FirstOrDefault(); if (duplicateTile != null) { var nextCoord = GetNextCoord(newCoord); MoveTile(duplicateTile.Item1, nextCoord); } } public Point ValidateCoord(Point coord) { var gridSize = this.GridSize; var x = coord.X; var y = coord.Y; if (x >= gridSize.Width) { x = 0; y++; } return new Point(x, y); } protected Point GetLocation(Point coord) { var tileWidth = TileSize.Width + TileMargin; var tileHeight = TileSize.Height + TileMargin; var posX = (coord.X * tileWidth) + this.ContentRectangle.Left; var posY = (coord.Y * tileHeight) + this.ContentRectangle.Top; return new Point(posX, posY); } } }