using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using Tango.Core.Helpers; using Tango.SharedUI.Shapes; namespace Tango.SharedUI.Controls { /// /// Interaction logic for HiveControl.xaml /// public partial class HiveControl : UserControl { public event EventHandler HexagonSelected; public event EventHandler HiveGenerated; public ObservableCollection Hexagons { get { return (ObservableCollection)GetValue(HexagonsProperty); } set { SetValue(HexagonsProperty, value); } } public static readonly DependencyProperty HexagonsProperty = DependencyProperty.Register("Hexagons", typeof(ObservableCollection), typeof(HiveControl), new PropertyMetadata(null)); public ObservableCollection SelectedHexagons { get { return (ObservableCollection)GetValue(SelectedHexagonsProperty); } set { SetValue(SelectedHexagonsProperty, value); } } public static readonly DependencyProperty SelectedHexagonsProperty = DependencyProperty.Register("SelectedHexagons", typeof(ObservableCollection), typeof(HiveControl), new PropertyMetadata(null)); public int MaxSelections { get { return (int)GetValue(MaxSelectionsProperty); } set { SetValue(MaxSelectionsProperty, value); } } public static readonly DependencyProperty MaxSelectionsProperty = DependencyProperty.Register("MaxSelections", typeof(int), typeof(HiveControl), new PropertyMetadata(3)); public bool DisplayGridPosition { get { return (bool)GetValue(DisplayGridPositionProperty); } set { SetValue(DisplayGridPositionProperty, value); } } public static readonly DependencyProperty DisplayGridPositionProperty = DependencyProperty.Register("DisplayGridPosition", typeof(bool), typeof(HiveControl), new PropertyMetadata(false)); public HexagonControl CenterHexagon { get { return (HexagonControl)GetValue(CenterHexagonProperty); } set { SetValue(CenterHexagonProperty, value); } } public static readonly DependencyProperty CenterHexagonProperty = DependencyProperty.Register("CenterHexagon", typeof(HexagonControl), typeof(HiveControl), new PropertyMetadata(null)); public int HiveWidth { get { return (int)GetValue(HiveWidthProperty); } set { SetValue(HiveWidthProperty, value); } } public static readonly DependencyProperty HiveWidthProperty = DependencyProperty.Register("HiveWidth", typeof(int), typeof(HiveControl), new PropertyMetadata(5)); public int HiveHeight { get { return (int)GetValue(HiveHeightProperty); } set { SetValue(HiveHeightProperty, value); } } public static readonly DependencyProperty HiveHeightProperty = DependencyProperty.Register("HiveHeight", typeof(int), typeof(HiveControl), new PropertyMetadata(5)); public HiveControl() { Hexagons = new ObservableCollection(); SelectedHexagons = new ObservableCollection(); InitializeComponent(); HiveHeight = 5; HiveWidth = 5; this.Loaded += HiveControl_Loaded; } private void HiveControl_Loaded(object sender, RoutedEventArgs e) { GenerateHive(); HiveGenerated?.Invoke(this,new EventArgs()); } private void GenerateHive() { Hexagons.Clear(); SelectedHexagons.Clear(); canvas.Children.Clear(); double width = ActualWidth; double height = ActualHeight; double hexHeight = height / (double)HiveHeight; int gap = (int)((Math.Round(HiveHeight / 2d, MidpointRounding.AwayFromZero)) / 2d); for (int column = 0; column < HiveWidth / 2; column++) { for (int row = gap; row < HiveHeight - (gap % 2 != 0 ? gap : gap + 1); row++) { AddHexagon(hexHeight, row, column); } gap--; } int centerColumn = (int)Math.Round(HiveHeight / 2d, MidpointRounding.ToEven); for (int row = 0; row < HiveHeight; row++) { AddHexagon(hexHeight, row, centerColumn); } gap = 0; for (int column = centerColumn + 1; column < HiveWidth; column++) { for (int row = gap; row < HiveHeight - (gap % 2 != 0 ? gap : gap + 1); row++) { AddHexagon(hexHeight, row, column); } gap++; } Width = Hexagons.Max(x => x.Points.Max(y => y.X)); CenterHexagon = GetHexagon((int)Math.Round(HiveWidth / 2d, MidpointRounding.ToEven), (int)Math.Round(HiveHeight / 2d, MidpointRounding.ToEven)); } private void AddHexagon(double hexHeight, int row, int col) { Point[] points = HexToPoints(hexHeight, row, col); HexagonControl hexagon = new HexagonControl(points, row, col); hexagon.HorizontalAlignment = HorizontalAlignment.Center; hexagon.VerticalAlignment = VerticalAlignment.Center; hexagon.Stroke = Brushes.Black; hexagon.StrokeThickness = 1; hexagon.Fill = new SolidColorBrush(ColorHelper.GetRandomGrayscaleColor()); canvas.Children.Add(hexagon); Hexagons.Add(hexagon); hexagon.Bind(HexagonControl.DisplayGridPositionProperty, this, DisplayGridPositionProperty, BindingMode.OneWay); hexagon.MouseEnter += Hexagon_MouseEnter; hexagon.MouseUp += Hexagon_MouseUp; } private void Hexagon_MouseUp(object sender, MouseButtonEventArgs e) { HexagonControl hexagon = sender as HexagonControl; ToggleHexagonSelection(hexagon); } public void SelectHexagon(HexagonControl hexagon) { SelectedHexagons.Clear(); SelectedHexagons.Add(hexagon); Hexagons.ToList().ForEach(x => x.IsSelected = false); hexagon.IsSelected = true; HexagonSelected?.Invoke(this, hexagon); } private void ToggleHexagonSelection(HexagonControl hexagon) { bool selected = !hexagon.IsSelected; if (MaxSelections > Hexagons.Where(x => x.IsSelected).Count()) { hexagon.IsSelected = selected; } else { if (selected) { SelectedHexagons.First().IsSelected = false; SelectedHexagons.Remove(SelectedHexagons.First()); hexagon.IsSelected = true; } else { hexagon.IsSelected = false; } } if (selected) { SelectedHexagons.Add(hexagon); HexagonSelected?.Invoke(this, hexagon); } else { SelectedHexagons.Remove(hexagon); } } private void Hexagon_MouseEnter(object sender, MouseEventArgs e) { Canvas.SetZIndex(sender as FrameworkElement, canvas.Children.OfType().Where(x => !x.IsSelected).Max(x => Canvas.GetZIndex(x)) + 1); foreach (var item in canvas.Children.OfType().Where(x => x.IsSelected)) { Canvas.SetZIndex(item, canvas.Children.OfType().Max(x => Canvas.GetZIndex(x)) + 1); } } private Point[] HexToPoints(double height, float row, float col) { // Start with the leftmost corner of the upper left hexagon. double width = HexWidth(height); double y = height / 2; double x = 0; // Move down the required number of rows. y += row * height; // If the column is odd, move down half a hex more. if (col % 2 == 1) y += height / 2; // Move over for the column number. x += col * (width * 0.75f); // Generate the points. return new Point[] { new Point(x, y), new Point(x + width * 0.25f, y - height / 2), new Point(x + width * 0.75f, y - height / 2), new Point(x + width, y), new Point(x + width * 0.75f, y + height / 2), new Point(x + width * 0.25f, y + height / 2), }; } private double HexWidth(double height) { return (double)(4 * (height / 2 / Math.Sqrt(3))); } public HexagonControl GetHexagon(int row, int column) { return Hexagons.Where(x => x.Row == row && x.Column == column).FirstOrDefault(); } } }