944 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			944 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using FizzyLauncher.Models;
 | 
						|
using RyzStudio.Windows.Forms;
 | 
						|
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Diagnostics;
 | 
						|
using System.Drawing;
 | 
						|
using System.IO;
 | 
						|
using System.Linq;
 | 
						|
using System.Threading;
 | 
						|
using System.Threading.Tasks;
 | 
						|
using System.Windows.Forms;
 | 
						|
using AppResource = BookmarkManager.AppResource;
 | 
						|
 | 
						|
namespace FizzyLauncher.Windows.Forms
 | 
						|
{
 | 
						|
    public partial class TilePanelLayout : TUserControl
 | 
						|
    {
 | 
						|
        public static int CalcWidth(int tileCount) => (tileCount * tileSize) + ((tileCount - 1) * margin);
 | 
						|
 | 
						|
 | 
						|
        public class Item
 | 
						|
        {
 | 
						|
            public TilePanel Tile { get; set; }
 | 
						|
            public Point Coord { get; set; } = new Point(0, 0);
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        protected const int tileSize = 70;
 | 
						|
        protected const int margin = 3;
 | 
						|
        protected const int labelHeight = 20;
 | 
						|
        protected const int collapseIncrement = 6;
 | 
						|
        protected const int expandIncrement = 8;
 | 
						|
 | 
						|
        protected TileGroupModel groupModel = null;
 | 
						|
        protected List<Item> items = new List<Item>();
 | 
						|
 | 
						|
        protected int collapseHeight = 0;
 | 
						|
        protected int expandedHeight = 0;
 | 
						|
 | 
						|
        protected bool isAnimating = false;
 | 
						|
        protected bool isChecked = true;
 | 
						|
        protected Point lastMousePosition = new Point();
 | 
						|
        protected Point gridSize = new Point();
 | 
						|
 | 
						|
 | 
						|
        public TilePanelLayout(TileGroupModel model) : base()
 | 
						|
        {
 | 
						|
            InitializeComponent();
 | 
						|
 | 
						|
            this.AllowDrop = true;
 | 
						|
            this.BackColor = Color.Transparent;
 | 
						|
 | 
						|
            this.LoadModel(model);
 | 
						|
 | 
						|
            label1.Location = new Point(0, 4);
 | 
						|
            label1.Margin = new Padding(0);
 | 
						|
            label1.Padding = new Padding(0);
 | 
						|
        }
 | 
						|
 | 
						|
        protected override void OnDragDrop(DragEventArgs e)
 | 
						|
        {
 | 
						|
            string[] fileList = e.Data.GetData(DataFormats.FileDrop) as string[];
 | 
						|
 | 
						|
            this.DropFileList(fileList);
 | 
						|
        }
 | 
						|
 | 
						|
        protected override void OnDragOver(DragEventArgs e)
 | 
						|
        {
 | 
						|
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
 | 
						|
            {
 | 
						|
                e.Effect = DragDropEffects.Link;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                e.Effect = DragDropEffects.None;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        protected override void OnLoad(EventArgs e)
 | 
						|
        {
 | 
						|
            base.OnLoad(e);
 | 
						|
 | 
						|
            this.Margin = new Padding(0);
 | 
						|
            this.Padding = new Padding(0, 0, 0, 10);
 | 
						|
        }
 | 
						|
 | 
						|
        protected override async void OnResize(EventArgs e)
 | 
						|
        {
 | 
						|
            base.OnResize(e);
 | 
						|
 | 
						|
            await this.InvalidateContainer();
 | 
						|
        }
 | 
						|
 | 
						|
        protected override void OnMouseClick(MouseEventArgs e)
 | 
						|
        {
 | 
						|
            base.OnMouseClick(e);
 | 
						|
 | 
						|
            lastMousePosition = e.Location;
 | 
						|
 | 
						|
            bool isLabel = ((e.Location.X >= 0) && (e.Location.X <= this.Width) && (e.Location.Y >= 0) && (e.Location.Y <= 20));
 | 
						|
 | 
						|
            if (e.Button == MouseButtons.Left)
 | 
						|
            {
 | 
						|
                // do nothing
 | 
						|
            }
 | 
						|
            else if (e.Button == MouseButtons.Right)
 | 
						|
            {
 | 
						|
                if (isLabel)
 | 
						|
                {
 | 
						|
                    contextMenuStrip2.Show(this, e.Location);
 | 
						|
                }
 | 
						|
                else
 | 
						|
                {
 | 
						|
                    contextMenuStrip1.Show(this, e.Location);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        protected override void OnMouseDoubleClick(MouseEventArgs e) => base.OnMouseClick(e);
 | 
						|
 | 
						|
        public Point GridSize
 | 
						|
        {
 | 
						|
            get => gridSize;
 | 
						|
        }
 | 
						|
 | 
						|
        public bool EnableAnimation
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                MainForm mainForm = this.MainForm;
 | 
						|
                if (mainForm == null)
 | 
						|
                {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
 | 
						|
                if (mainForm.CurrentSession == null)
 | 
						|
                {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
 | 
						|
                return mainForm.CurrentSession.EnableAnimation;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public int CollapseHeight => labelHeight + collapseHeight;
 | 
						|
 | 
						|
        public int ExpandedHeight => expandedHeight + this.Padding.Bottom;
 | 
						|
 | 
						|
        public void DropFileList(string[] fileList)
 | 
						|
        {
 | 
						|
            if (fileList == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (fileList.Length <= 0)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (string.IsNullOrWhiteSpace(fileList[0]))
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            TileModel model = new TileModel()
 | 
						|
            {
 | 
						|
                ProcessFilename = fileList[0],
 | 
						|
                Title = Path.GetFileName(fileList[0])
 | 
						|
            };
 | 
						|
 | 
						|
            // exe
 | 
						|
            if (Path.GetExtension(fileList[0]).Equals(".exe", StringComparison.CurrentCultureIgnoreCase))
 | 
						|
            {
 | 
						|
                if (File.Exists(fileList[0]))
 | 
						|
                {
 | 
						|
                    try
 | 
						|
                    {
 | 
						|
                        FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(fileList[0]);
 | 
						|
                        if (fvi != null)
 | 
						|
                        {
 | 
						|
                            model.Title = fvi.ProductName;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    catch
 | 
						|
                    {
 | 
						|
                        // do nothing
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if (string.IsNullOrWhiteSpace(model.Title))
 | 
						|
                {
 | 
						|
                    model.Title = Path.GetFileNameWithoutExtension(fileList[0]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            this.AddTile(model);
 | 
						|
        }
 | 
						|
 | 
						|
        public TileGroupModel Model
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                TileGroupModel rs = new TileGroupModel()
 | 
						|
                {
 | 
						|
                    Title = groupModel.Title,
 | 
						|
                    GridSize = new Size(this.GridSize.X, this.GridSize.Y),
 | 
						|
                    IsExpanded = isChecked,
 | 
						|
                    IsExclusive = groupModel.IsExclusive,
 | 
						|
                    Items = this.Tiles
 | 
						|
                };
 | 
						|
 | 
						|
                return rs;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public FlowLayoutPanel FlowLayoutPanel
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                Control parentControl = this.Parent;
 | 
						|
                while (true)
 | 
						|
                {
 | 
						|
                    if (parentControl == null)
 | 
						|
                    {
 | 
						|
                        return null;
 | 
						|
                    }
 | 
						|
 | 
						|
                    if (parentControl.GetType() == typeof(FlowLayoutPanel))
 | 
						|
                    {
 | 
						|
                        return parentControl as FlowLayoutPanel;
 | 
						|
                    }
 | 
						|
 | 
						|
                    parentControl = parentControl.Parent;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public MainForm MainForm
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                Control parentControl = this.FlowLayoutPanel;
 | 
						|
                while (true)
 | 
						|
                {
 | 
						|
                    if (parentControl == null)
 | 
						|
                    {
 | 
						|
                        return null;
 | 
						|
                    }
 | 
						|
 | 
						|
                    if (parentControl.GetType() == typeof(MainForm))
 | 
						|
                    {
 | 
						|
                        return parentControl as MainForm;
 | 
						|
                    }
 | 
						|
 | 
						|
                    parentControl = parentControl.Parent;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public List<TileModel> Tiles
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                List<TileModel> rs = new List<TileModel>();
 | 
						|
                foreach (Item item in items)
 | 
						|
                {
 | 
						|
                    TileModel model = item.Tile.ModelInfo;
 | 
						|
                    model.Position = item.Coord;
 | 
						|
 | 
						|
                    rs.Add(model);
 | 
						|
                }
 | 
						|
 | 
						|
                return rs;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public int TileSize => (tileSize + margin);
 | 
						|
 | 
						|
        public void AddTile(TileModel tile)
 | 
						|
        {
 | 
						|
            Point gridSize = this.GridSize;
 | 
						|
 | 
						|
            if (items.Count >= (gridSize.X * gridSize.Y))
 | 
						|
            {
 | 
						|
                this.SetGridSize(gridSize.X, (gridSize.Y + 1));
 | 
						|
            }
 | 
						|
 | 
						|
            Point? newCoord = tile.Position;
 | 
						|
            if ((newCoord == null) || hasTile(tile.Position))
 | 
						|
            {
 | 
						|
                newCoord = findLastFreeCoord();
 | 
						|
            }
 | 
						|
 | 
						|
            if (newCoord == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            tile.Position = newCoord.Value;
 | 
						|
 | 
						|
            TilePanel panel = new TilePanel();
 | 
						|
            panel.LoadInfo(tile);
 | 
						|
            panel.Location = convertCoordToLocation(tile.Position);
 | 
						|
 | 
						|
            items.Add(new Item()
 | 
						|
            {
 | 
						|
                Tile = panel,
 | 
						|
                Coord = tile.Position
 | 
						|
            });
 | 
						|
 | 
						|
            this.Controls.Add(panel);
 | 
						|
        }
 | 
						|
 | 
						|
        public void Clear()
 | 
						|
        {
 | 
						|
            this.Controls.Clear();
 | 
						|
        }
 | 
						|
 | 
						|
        public async Task Collapse()
 | 
						|
        {
 | 
						|
            await Task.Run(() =>
 | 
						|
            {
 | 
						|
                if (isAnimating) return;
 | 
						|
 | 
						|
                isAnimating = true;
 | 
						|
                isChecked = false;
 | 
						|
 | 
						|
                if (this.EnableAnimation)
 | 
						|
                {
 | 
						|
                    while (this.Height > this.CollapseHeight)
 | 
						|
                    {
 | 
						|
                        ThreadControl.SetHeight(this, (this.Height - collapseIncrement));
 | 
						|
 | 
						|
                        Thread.Sleep(10);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                ThreadControl.SetHeight(this, this.CollapseHeight);
 | 
						|
 | 
						|
                isAnimating = false;
 | 
						|
 | 
						|
                this.Invalidate(this.DisplayRectangle, false);
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
        public async Task Expand()
 | 
						|
        {
 | 
						|
            await Task.Run(() =>
 | 
						|
            {
 | 
						|
                if (isAnimating) return;
 | 
						|
 | 
						|
                isAnimating = true;
 | 
						|
                isChecked = true;
 | 
						|
 | 
						|
                if (this.EnableAnimation)
 | 
						|
                {
 | 
						|
                    while (this.Height < this.ExpandedHeight)
 | 
						|
                    {
 | 
						|
                        ThreadControl.SetHeight(this, (this.Height + expandIncrement));
 | 
						|
                        Thread.Sleep(10);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                ThreadControl.SetHeight(this, this.ExpandedHeight);
 | 
						|
 | 
						|
                isAnimating = false;
 | 
						|
 | 
						|
                this.Invalidate(this.DisplayRectangle, false);
 | 
						|
            });
 | 
						|
        }
 | 
						|
 | 
						|
        public Point GetTilePosition(int posX, int posY)
 | 
						|
        {
 | 
						|
            int x = (int)Math.Round(decimal.Divide(posX, this.TileSize));
 | 
						|
            int y = (int)Math.Round(decimal.Divide((posY - labelHeight), this.TileSize));
 | 
						|
 | 
						|
            if (x < 0) x = 0;
 | 
						|
            if (y < 0) y = 0;
 | 
						|
 | 
						|
            return new Point((x * this.TileSize), ((y * this.TileSize) + labelHeight));
 | 
						|
        }
 | 
						|
 | 
						|
        public async Task InvalidateContainer()
 | 
						|
        {
 | 
						|
            if (isAnimating)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (isChecked)
 | 
						|
            {
 | 
						|
                await this.Expand();
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                await this.Collapse();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public void AddGroup()
 | 
						|
        {
 | 
						|
            if (this.FlowLayoutPanel == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.FlowLayoutPanel.Controls.Add(new TilePanelLayout(new TileGroupModel()
 | 
						|
            {
 | 
						|
                Title = "New Group",
 | 
						|
                GridSize = new Size(8, 1)
 | 
						|
            }));
 | 
						|
        }
 | 
						|
 | 
						|
        public void AddRow() => this.SetGridSize(gridSize.X, (gridSize.Y + 1));
 | 
						|
 | 
						|
        public void EditGroup() => EditGroupForm.ShowDialog(this);
 | 
						|
 | 
						|
        public void LoadModel(TileGroupModel model)
 | 
						|
        {
 | 
						|
            groupModel = model;
 | 
						|
 | 
						|
            isChecked = groupModel.IsExpanded;
 | 
						|
 | 
						|
            label1.Text = "        " + groupModel?.Title;
 | 
						|
            label1.Image = (isChecked ? AppResource.toggle_right_ea_16 : AppResource.toggle_left_ea_16);
 | 
						|
 | 
						|
            this.SetGridSize(groupModel.GridSize.Width, groupModel.GridSize.Height);
 | 
						|
            this.LoadTiles(model.Items);
 | 
						|
            this.SetGridSize(groupModel.GridSize.Width, groupModel.GridSize.Height);
 | 
						|
 | 
						|
            this.Invalidate();
 | 
						|
        }
 | 
						|
 | 
						|
        public void UpdateModel(TileGroupModel model)
 | 
						|
        {
 | 
						|
            groupModel = model;
 | 
						|
            isChecked = groupModel.IsExpanded;
 | 
						|
 | 
						|
            label1.Text = "        " + groupModel?.Title;
 | 
						|
 | 
						|
            this.Invalidate();
 | 
						|
        }
 | 
						|
 | 
						|
        public void LoadTiles(List<TileModel> tiles)
 | 
						|
        {
 | 
						|
            if (tiles == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (tiles.Count() <= 0)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            foreach (TileModel item in tiles)
 | 
						|
            {
 | 
						|
                // resolve final grid position
 | 
						|
                Point? confirmedPosition = resolveCoord(item.Position);
 | 
						|
                if (confirmedPosition == null)
 | 
						|
                {
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
 | 
						|
                // place control
 | 
						|
                TilePanel panel = new TilePanel();
 | 
						|
                panel.LoadInfo(item);
 | 
						|
                panel.Location = convertCoordToLocation(confirmedPosition.Value);
 | 
						|
 | 
						|
                items.Add(new Item()
 | 
						|
                {
 | 
						|
                    Tile = panel,
 | 
						|
                    Coord = confirmedPosition.Value
 | 
						|
                });
 | 
						|
 | 
						|
                this.Controls.Add(panel);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public void MoveTile(TilePanel panel, int posX, int posY)
 | 
						|
        {
 | 
						|
            Item item = items.Where(x => x.Tile.Equals(panel)).FirstOrDefault();
 | 
						|
            if (item == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            Point newPosition = convertLocationToCoord_Nearest(posX, posY);
 | 
						|
            if (!isTileInBounds(newPosition))
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (hasTile(newPosition))
 | 
						|
            {
 | 
						|
                Item swapItem = items.Where(x => x.Coord.Equals(newPosition)).FirstOrDefault();
 | 
						|
                if (swapItem != null)
 | 
						|
                {
 | 
						|
                    swapItem.Coord = item.Coord;
 | 
						|
                    swapItem.Tile.Location = convertCoordToLocation(item.Coord);
 | 
						|
                }
 | 
						|
 | 
						|
                item.Coord = newPosition;
 | 
						|
                panel.Location = convertCoordToLocation(newPosition);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                item.Coord = newPosition;
 | 
						|
                panel.Location = convertCoordToLocation(newPosition);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        public void MoveTop()
 | 
						|
        {
 | 
						|
            if (this.FlowLayoutPanel == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.FlowLayoutPanel.Controls.SetChildIndex(this, 0);
 | 
						|
        }
 | 
						|
 | 
						|
        public void MoveUp()
 | 
						|
        {
 | 
						|
            if (this.FlowLayoutPanel == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            int pos = this.FlowLayoutPanel.Controls.GetChildIndex(this);
 | 
						|
            if (pos <= 0)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.FlowLayoutPanel.Controls.SetChildIndex(this, (pos - 1));
 | 
						|
        }
 | 
						|
 | 
						|
        public void MoveDown()
 | 
						|
        {
 | 
						|
            if (this.FlowLayoutPanel == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            int pos = this.FlowLayoutPanel.Controls.GetChildIndex(this);
 | 
						|
            if (pos >= (this.FlowLayoutPanel.Controls.Count - 1))
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.FlowLayoutPanel.Controls.SetChildIndex(this, (pos + 1));
 | 
						|
        }
 | 
						|
 | 
						|
        public void MoveBottom()
 | 
						|
        {
 | 
						|
            if (this.FlowLayoutPanel == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.FlowLayoutPanel.Controls.SetChildIndex(this, (this.FlowLayoutPanel.Controls.Count - 1));
 | 
						|
        }
 | 
						|
 | 
						|
        public void Remove()
 | 
						|
        {
 | 
						|
            if (this.FlowLayoutPanel == null)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.FlowLayoutPanel.Controls.Remove(this);
 | 
						|
        }
 | 
						|
 | 
						|
        public void Remove(TilePanel panel)
 | 
						|
        {
 | 
						|
            Item m = items.Where(x => x.Tile.Equals(panel)).FirstOrDefault();
 | 
						|
            if (m != null)
 | 
						|
            {
 | 
						|
                items.Remove(m);
 | 
						|
            }
 | 
						|
 | 
						|
            this.Controls.Remove(panel);
 | 
						|
        }
 | 
						|
 | 
						|
        public void SetGridSize(int width, int height)
 | 
						|
        {
 | 
						|
            gridSize = new Point(width, height);
 | 
						|
 | 
						|
            groupModel.GridSize = new Size(groupModel.GridSize.Width, height);
 | 
						|
 | 
						|
            expandedHeight = (this.TileSize * height) + labelHeight;
 | 
						|
 | 
						|
            int w = CalcWidth(gridSize.X);
 | 
						|
 | 
						|
            this.Size = new Size(w, (isChecked ? this.ExpandedHeight : this.CollapseHeight));
 | 
						|
        }
 | 
						|
 | 
						|
        protected Point convertCoordToLocation(Point position) => new Point((position.X * this.TileSize), ((position.Y * this.TileSize) + labelHeight));
 | 
						|
 | 
						|
        protected Point convertLocationToCoord(int posX, int posY)
 | 
						|
        {
 | 
						|
            int x = (int)Math.Ceiling(decimal.Divide(posX, this.TileSize));
 | 
						|
            int y = (int)Math.Ceiling(decimal.Divide((posY - labelHeight), this.TileSize));
 | 
						|
 | 
						|
            x--;
 | 
						|
            y--;
 | 
						|
 | 
						|
            if (x < 0) x = 0;
 | 
						|
            if (y < 0) y = 0;
 | 
						|
 | 
						|
            return new Point(x, y);
 | 
						|
        }
 | 
						|
 | 
						|
        protected Point convertLocationToCoord_Nearest(int posX, int posY)
 | 
						|
        {
 | 
						|
            int x = (int)Math.Round(decimal.Divide(posX, this.TileSize));
 | 
						|
            int y = (int)Math.Round(decimal.Divide((posY - labelHeight), this.TileSize));
 | 
						|
 | 
						|
            if (x < 0) x = 0;
 | 
						|
            if (y < 0) y = 0;
 | 
						|
 | 
						|
            return new Point(x, y);
 | 
						|
        }
 | 
						|
 | 
						|
        protected Point? findFirstFreeCoord()
 | 
						|
        {
 | 
						|
            Point gridSize = this.GridSize;
 | 
						|
 | 
						|
            for (int y = 0; y < gridSize.Y; y++)
 | 
						|
            {
 | 
						|
                for (int x = 0; x < gridSize.X; x++)
 | 
						|
                {
 | 
						|
                    if (hasTile(new Point(x, y)))
 | 
						|
                    {
 | 
						|
                        continue;
 | 
						|
                    }
 | 
						|
 | 
						|
                    return new Point(x, y);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
 | 
						|
        protected Point? findLastFreeCoord()
 | 
						|
        {
 | 
						|
            Point gridSize = this.GridSize;
 | 
						|
 | 
						|
            // none available
 | 
						|
            if (items.Count >= (gridSize.X * gridSize.Y))
 | 
						|
            {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
 | 
						|
            if (items.Count <= 0)
 | 
						|
            {
 | 
						|
                return findFirstFreeCoord();
 | 
						|
            }
 | 
						|
 | 
						|
            // only one available
 | 
						|
            if (items.Count >= ((gridSize.X * gridSize.Y) - 1))
 | 
						|
            {
 | 
						|
                return findFirstFreeCoord();
 | 
						|
            }
 | 
						|
 | 
						|
            Point? rv = null;
 | 
						|
 | 
						|
            for (int y = (gridSize.Y - 1); y >= 0; y--)
 | 
						|
            {
 | 
						|
                for (int x = (gridSize.X - 1); x >= 0; x--)
 | 
						|
                {
 | 
						|
                    if (hasTile(new Point(x, y)))
 | 
						|
                    {
 | 
						|
                        if (rv.HasValue)
 | 
						|
                        {
 | 
						|
                            return rv;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                    {
 | 
						|
                        rv = new Point(x, y);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return null;
 | 
						|
        }
 | 
						|
 | 
						|
        protected bool hasTile(Point position)
 | 
						|
        {
 | 
						|
            if (items == null)
 | 
						|
            {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
            if (items.Count <= 0)
 | 
						|
            {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
            return (items.Count(x => x.Coord.Equals(position)) > 0);
 | 
						|
        }
 | 
						|
 | 
						|
        protected bool isTileInBounds(Point position)
 | 
						|
        {
 | 
						|
            Point gridSize = this.GridSize;
 | 
						|
 | 
						|
            if (position.X >= gridSize.X)
 | 
						|
            {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
            if (position.Y >= gridSize.Y)
 | 
						|
            {
 | 
						|
                return false;
 | 
						|
            }
 | 
						|
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
 | 
						|
        protected Point? resolveCoord(Point coord)
 | 
						|
        {
 | 
						|
            if (!isTileInBounds(coord))
 | 
						|
            {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
 | 
						|
            if (!hasTile(coord))
 | 
						|
            {
 | 
						|
                return coord;
 | 
						|
            }
 | 
						|
 | 
						|
            return resolveNextCoord(coord);
 | 
						|
        }
 | 
						|
 | 
						|
        protected Point? resolveNextCoord(Point coord)
 | 
						|
        {
 | 
						|
            Point gridSize = this.GridSize;
 | 
						|
            Point newCoord = coord;
 | 
						|
 | 
						|
            while (true)
 | 
						|
            {
 | 
						|
                newCoord.X++;
 | 
						|
 | 
						|
                if (newCoord.X >= gridSize.X)
 | 
						|
                {
 | 
						|
                    newCoord.Y++;
 | 
						|
                    newCoord.X = 0;
 | 
						|
                }
 | 
						|
 | 
						|
                if (!isTileInBounds(newCoord))
 | 
						|
                {
 | 
						|
                    return null;
 | 
						|
                }
 | 
						|
 | 
						|
                if (hasTile(newCoord))
 | 
						|
                {
 | 
						|
                    continue;
 | 
						|
                }
 | 
						|
 | 
						|
                return newCoord;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        private async void label1_MouseClick(object sender, MouseEventArgs e)
 | 
						|
        {
 | 
						|
            if (isAnimating) return;
 | 
						|
 | 
						|
            if (e.Button == MouseButtons.Left)
 | 
						|
            {
 | 
						|
                isChecked = !isChecked;
 | 
						|
 | 
						|
                label1.Image = (isChecked ? AppResource.toggle_right_ea_16 : AppResource.toggle_left_ea_16);
 | 
						|
 | 
						|
                this.Invalidate();
 | 
						|
 | 
						|
                await this.InvalidateContainer();
 | 
						|
 | 
						|
                // exclusivity
 | 
						|
                if (isChecked)
 | 
						|
                {
 | 
						|
                    if (this.Model.IsExclusive)
 | 
						|
                    {
 | 
						|
                        if (this.FlowLayoutPanel != null)
 | 
						|
                        {
 | 
						|
                            foreach (TilePanelLayout item in this.FlowLayoutPanel.Controls.OfType<TilePanelLayout>())
 | 
						|
                            {
 | 
						|
                                if (item.Equals(this))
 | 
						|
                                {
 | 
						|
                                    continue;
 | 
						|
                                }
 | 
						|
 | 
						|
                                await item.Collapse();
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                label1.Image = (isChecked ? AppResource.toggle_right_ea_16 : AppResource.toggle_left_ea_16);
 | 
						|
            }
 | 
						|
            else if (e.Button == MouseButtons.Right)
 | 
						|
            {
 | 
						|
                contextMenuStrip2.Show(this, e.Location);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        #region tile context menu
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Add tile
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void addTileMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            Point coord = convertLocationToCoord(lastMousePosition.X, lastMousePosition.Y);
 | 
						|
 | 
						|
            EditTileForm.ShowAddDialog(this, coord);
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Add folder
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void addListTileMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            Point coord = convertLocationToCoord(lastMousePosition.X, lastMousePosition.Y);
 | 
						|
 | 
						|
            EditTileFolderForm.ShowAddDialog(this, coord);
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
        #region group context menu
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Add group
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void addGroupMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.AddGroup();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Edit group
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void editGroupMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.EditGroup();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Add row
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void toolStripMenuItem5_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.AddRow();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Remove row
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void removeRowToolStripMenuItem_Click_1(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            if (gridSize.Y <= 1)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            bool rs = items.Exists(x => x.Coord.Y.Equals(gridSize.Y - 1));
 | 
						|
            if (rs)
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            this.SetGridSize(gridSize.X, (gridSize.Y - 1));
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Move to top
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void moveTopMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.MoveTop();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Move up
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void moveUpMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.MoveUp();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Move down
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void moveDownMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.MoveDown();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Move to bottom
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void moveBottomMenuItem_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.MoveBottom();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Remove group
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="sender"></param>
 | 
						|
        /// <param name="e"></param>
 | 
						|
        private void removeGroupMenuItem3_Click(object sender, EventArgs e)
 | 
						|
        {
 | 
						|
            this.Remove();
 | 
						|
        }
 | 
						|
 | 
						|
        #endregion
 | 
						|
 | 
						|
    }
 | 
						|
}
 |