private static void AddColorHexagon(int i, Palette palette, Canvas container, PaletteSelector owner, List <PaletteColorInfo> infos, Func <Color, Color> colourBlindnessFunction) { AnimatableTransform transform = new AnimatableTransform(new Matrix(1, 0, 0, 1, 0, 0)); PaletteColorInfo info = new PaletteColorInfo() { Index = i, OriginalIndex = i, Transform = transform }; infos.Insert(i, info); double centerX = (1.5 + 2.5 * i) * HexagonRadius + 6.93; double centerY = HexagonRadius * Math.Cos(Math.PI / 6) * (i % 2 == 0 ? 1 : 2); PathGeometry leftHexagon = GetHexagonPath(new Point(centerX - 0.5 * HexagonRadius, centerY), HexagonRadius); PathGeometry centerHexagon = GetHexagonPath(new Point(centerX, centerY), HexagonRadius); PathGeometry rightHexagon = GetHexagonPath(new Point(centerX + 0.5 * HexagonRadius, centerY), HexagonRadius); Color color = palette.Colors[i % palette.Colors.Count]; Color lighterColor = ColorPicker.GetLighterColor(color); Color darkerColor = ColorPicker.GetDarkerColor(color); Avalonia.Controls.Shapes.Path leftPath = new Avalonia.Controls.Shapes.Path() { Data = leftHexagon, Fill = new ColorVisualBrush(colourBlindnessFunction(lighterColor)), Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Hand) }; Avalonia.Controls.Shapes.Path rightPath = new Avalonia.Controls.Shapes.Path() { Data = rightHexagon, Fill = new ColorVisualBrush(colourBlindnessFunction(darkerColor)), Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Hand) }; Avalonia.Controls.Shapes.Path centerPath = new Avalonia.Controls.Shapes.Path() { Data = centerHexagon, Fill = new ColorVisualBrush(colourBlindnessFunction(color)), Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Hand) }; if (!ColorPicker.TransitionsDisabled) { leftPath.Transitions = new Transitions { new ThicknessTransition() { Property = Avalonia.Controls.Shapes.Path.MarginProperty, Duration = new TimeSpan(0, 0, 0, 0, 100) } }; rightPath.Transitions = new Transitions { new ThicknessTransition() { Property = Avalonia.Controls.Shapes.Path.MarginProperty, Duration = new TimeSpan(0, 0, 0, 0, 100) } }; } leftPath.Classes.Add("HexagonLeftPalette"); rightPath.Classes.Add("HexagonRightPalette"); centerPath.Classes.Add("HexagonCenter"); rightPath.PointerEnter += (s, e) => { rightPath.ZIndex = 10; centerPath.ZIndex = 10; }; rightPath.PointerLeave += async(s, e) => { await Task.Delay(100); rightPath.ZIndex = 0; centerPath.ZIndex = 0; }; leftPath.PointerPressed += (s, e) => { owner.ColorSelected?.Invoke(owner, new ColorSelectedEventArgs(lighterColor)); }; rightPath.PointerPressed += (s, e) => { owner.ColorSelected?.Invoke(owner, new ColorSelectedEventArgs(darkerColor)); }; centerPath.PointerPressed += (s, e) => { owner.ColorSelected?.Invoke(owner, new ColorSelectedEventArgs(color)); }; Point p1, p2, p3, p4; if (i % 2 == 0) { p1 = new Point(centerX + HexagonRadius * Math.Cos(Math.PI * 2 / 3) - HexagonRadius * 0.5, centerY + HexagonRadius * Math.Sin(Math.PI * 2 / 3)); p2 = new Point(centerX + HexagonRadius * Math.Cos(Math.PI * 1 / 3) + HexagonRadius * 0.5, centerY + HexagonRadius * Math.Sin(Math.PI * 1 / 3)); p3 = p2 + new Point(-Math.Cos(Math.PI / 3), Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; p4 = p1 + new Point(Math.Cos(Math.PI / 3), Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; } else { p1 = new Point(centerX + HexagonRadius * Math.Cos(Math.PI * 4 / 3) - HexagonRadius * 0.5, centerY + HexagonRadius * Math.Sin(Math.PI * 4 / 3)); p2 = new Point(centerX + HexagonRadius * Math.Cos(Math.PI * 5 / 3) + HexagonRadius * 0.5, centerY + HexagonRadius * Math.Sin(Math.PI * 5 / 3)); p3 = p2 + new Point(-Math.Cos(Math.PI / 3), -Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; p4 = p1 + new Point(Math.Cos(Math.PI / 3), -Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; } AnimatablePath4Points deleteBG = new AnimatablePath4Points(p1, p2, p2, p1); AnimatableColorBrush bgFill = new AnimatableColorBrush(Color.FromRgb(180, 180, 180), col => deleteBG.Path.Fill = new SolidColorBrush(col)); deleteBG.Path.Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Hand); PathGeometry deleteGeometry = new PathGeometry(); PathFigure seg1 = new PathFigure() { StartPoint = new Point(centerX - HexagonRadius * 0.15, centerY - HexagonRadius * 0.15), IsClosed = false }; seg1.Segments.Add(new LineSegment() { Point = seg1.StartPoint + new Point(HexagonRadius * 0.3, HexagonRadius * 0.3) }); PathFigure seg2 = new PathFigure() { StartPoint = new Point(centerX + HexagonRadius * 0.15, centerY - HexagonRadius * 0.15), IsClosed = false }; seg2.Segments.Add(new LineSegment() { Point = seg2.StartPoint + new Point(-HexagonRadius * 0.3, HexagonRadius * 0.3) }); deleteGeometry.Figures.Add(seg1); deleteGeometry.Figures.Add(seg2); RelativePoint renderTransformOrigin = new RelativePoint(centerX, centerY, RelativeUnit.Absolute); leftPath.RenderTransform = transform.MatrixTransform; leftPath.RenderTransformOrigin = renderTransformOrigin; rightPath.RenderTransform = transform.MatrixTransform; rightPath.RenderTransformOrigin = renderTransformOrigin; centerPath.RenderTransform = transform.MatrixTransform; centerPath.RenderTransformOrigin = renderTransformOrigin; deleteBG.Path.RenderTransform = transform.MatrixTransform; deleteBG.Path.RenderTransformOrigin = renderTransformOrigin; AnimatableTransform fgTransform = new AnimatableTransform(new Matrix(1, 0, 0, 1, 0, (info.Index % 2 == 0 ? 1 : -1) * HexagonRadius * Math.Sin(Math.PI / 3) * 0.7)); TransformGroup fgTransforms = new TransformGroup(); fgTransforms.Children.Add(transform.MatrixTransform); fgTransforms.Children.Add(fgTransform.MatrixTransform); Avalonia.Controls.Shapes.Path deleteFG = new Avalonia.Controls.Shapes.Path() { Data = deleteGeometry, StrokeThickness = HexagonRadius * 0.1, IsHitTestVisible = false, RenderTransform = fgTransforms, RenderTransformOrigin = renderTransformOrigin }; info.DeleteBGPath = deleteBG; info.DeleteFBTransform = fgTransform; AnimatableColorBrush fgStroke = new AnimatableColorBrush(Color.FromRgb(255, 255, 255), col => deleteFG.Stroke = new SolidColorBrush(col)); deleteBG.Path.PointerEnter += (s, e) => { bgFill.Update(Color.FromRgb(240, 240, 240), false); fgStroke.Update(Color.FromRgb(128, 128, 128), false); }; deleteBG.Path.PointerLeave += (s, e) => { bgFill.Update(Color.FromRgb(180, 180, 180), false); fgStroke.Update(Colors.White, false); }; container.Children.Add(deleteBG.Path); container.Children.Add(deleteFG); bool deleteVisible = false; centerPath.PointerEnter += async(s, e) => { if (!deleteVisible) { double _centerX = (1.5 + 2.5 * info.OriginalIndex) * HexagonRadius + 6.93; double _centerY = HexagonRadius * Math.Cos(Math.PI / 6) * (info.OriginalIndex % 2 == 0 ? 1 : 2); Point _p1, _p2, _p3, _p4; if (info.Index % 2 == 0) { _p1 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 2 / 3) - HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 2 / 3)); _p2 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 1 / 3) + HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 1 / 3)); _p3 = _p2 + new Point(-Math.Cos(Math.PI / 3), Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; _p4 = _p1 + new Point(Math.Cos(Math.PI / 3), Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; } else { _p1 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 4 / 3) - HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 4 / 3)); _p2 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 5 / 3) + HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 5 / 3)); _p3 = _p2 + new Point(-Math.Cos(Math.PI / 3), -Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; _p4 = _p1 + new Point(Math.Cos(Math.PI / 3), -Math.Sin(Math.PI / 3)) * HexagonRadius * 0.6; } deleteVisible = true; deleteBG.Points = new PointCollection4(_p1, _p2, _p3, _p4); fgTransform.Matrix = new Matrix(1, 0, 0, 1, 0, (info.Index % 2 == 0 ? 1 : -1) * HexagonRadius * Math.Sin(Math.PI / 3) * 1.3); await Task.Delay(100); deleteBG.Path.ZIndex = 11; deleteFG.ZIndex = 11; await Task.Delay(1000); deleteBG.Path.ZIndex = 0; deleteFG.ZIndex = 0; fgTransform.Matrix = new Matrix(1, 0, 0, 1, 0, (info.Index % 2 == 0 ? 1 : -1) * HexagonRadius * Math.Sin(Math.PI / 3) * 0.7); deleteBG.Points = new PointCollection4(_p1, _p2, _p2, _p1); deleteVisible = false; } }; container.Children.Add(leftPath); container.Children.Add(rightPath); container.Children.Add(centerPath); deleteBG.Path.PointerPressed += async(s, e) => { transform.Matrix = new Matrix(0, 0, 0, 0, transform.Matrix.M31, transform.Matrix.M32); for (int j = info.Index + 1; j < infos.Count; j++) { infos[j].Transform.Matrix = new Matrix(1, 0, 0, 1, infos[j].Transform.Matrix.M31 - HexagonRadius * 2.5, infos[j].Transform.Matrix.M32 + HexagonRadius * Math.Sin(Math.PI / 3) * (j % 2 == 0 ? 1 : -1)); infos[j].Index--; if (infos[j].DeleteBGPath != null) { double _centerX = (1.5 + 2.5 * infos[j].OriginalIndex) * HexagonRadius + 6.93; double _centerY = HexagonRadius * Math.Cos(Math.PI / 6) * (infos[j].OriginalIndex % 2 == 0 ? 1 : 2); Point _p1, _p2; if (infos[j].Index % 2 == 0) { _p1 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 2 / 3) - HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 2 / 3)); _p2 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 1 / 3) + HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 1 / 3)); } else { _p1 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 4 / 3) - HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 4 / 3)); _p2 = new Point(_centerX + HexagonRadius * Math.Cos(Math.PI * 5 / 3) + HexagonRadius * 0.5, _centerY + HexagonRadius * Math.Sin(Math.PI * 5 / 3)); } infos[j].DeleteBGPath.Points = new PointCollection4(_p1, _p2, _p2, _p1); infos[j].DeleteFBTransform.Matrix = new Matrix(1, 0, 0, 1, 0, -infos[j].DeleteFBTransform.Matrix.M32); } } await Task.Delay(100); container.Width -= HexagonRadius * 2.5; infos.RemoveAt(info.Index); palette.Colors.RemoveAt(info.Index); container.Children.Remove(leftPath); container.Children.Remove(rightPath); container.Children.Remove(centerPath); container.Children.Remove(deleteBG.Path); container.Children.Remove(deleteFG); }; }
private Canvas BuildPaletteCanvas(Palette palette) { int n = palette.Colors.Count + 1; Canvas tbr = new Canvas() { Height = HexagonRadius * Math.Cos(Math.PI / 6) * 3, Width = HexagonRadius * (3 + 2.5 * (n - 1)) + 13.86, Margin = new Thickness(0, 0, 0, 5) }; if (!ColorPicker.TransitionsDisabled) { tbr.Transitions = new Transitions { new DoubleTransition() { Property = Canvas.WidthProperty, Duration = new TimeSpan(0, 0, 0, 0, 100) } }; } List <PaletteColorInfo> infos = new List <PaletteColorInfo>(); for (int i = 0; i < n - 1; i++) { AddColorHexagon(i, palette, tbr, this, infos, this.ColourBlindnessFunction); } { int i = n - 1; double centerX = (1.5 + 2.5 * i) * HexagonRadius + 6.93; double centerY = HexagonRadius * Math.Cos(Math.PI / 6) * (i % 2 == 0 ? 1 : 2); PathGeometry leftHexagon = GetHexagonPath(new Point(centerX - 0.5 * HexagonRadius, centerY), HexagonRadius); PathGeometry centerHexagon = GetHexagonPath(new Point(centerX, centerY), HexagonRadius); PathGeometry rightHexagon = GetHexagonPath(new Point(centerX + 0.5 * HexagonRadius, centerY), HexagonRadius); Avalonia.Controls.Shapes.Path leftPath = new Avalonia.Controls.Shapes.Path() { Data = leftHexagon, ZIndex = 2 }; Avalonia.Controls.Shapes.Path rightPath = new Avalonia.Controls.Shapes.Path() { Data = rightHexagon, ZIndex = 2 }; Avalonia.Controls.Shapes.Path centerPath = new Avalonia.Controls.Shapes.Path() { Data = centerHexagon, Cursor = new Avalonia.Input.Cursor(Avalonia.Input.StandardCursorType.Hand), ZIndex = 2 }; AnimatableColorBrush leftFill = new AnimatableColorBrush(Color.FromRgb(240, 240, 240), col => leftPath.Fill = new SolidColorBrush(col)); AnimatableColorBrush rightFill = new AnimatableColorBrush(Color.FromRgb(240, 240, 240), col => rightPath.Fill = new SolidColorBrush(col)); AnimatableColorBrush centerFill = new AnimatableColorBrush(Color.FromRgb(200, 200, 200), col => centerPath.Fill = new SolidColorBrush(col)); tbr.Children.Add(leftPath); tbr.Children.Add(rightPath); tbr.Children.Add(centerPath); PathGeometry plusGeometry = new PathGeometry(); PathFigure verticalPlusFigure = new PathFigure() { StartPoint = new Point(centerX, centerY - HexagonRadius * 0.5), IsClosed = false }; verticalPlusFigure.Segments.Add(new LineSegment() { Point = new Point(centerX, centerY + HexagonRadius * 0.5) }); PathFigure horizontalPlusFigure = new PathFigure() { StartPoint = new Point(centerX - HexagonRadius * 0.5, centerY), IsClosed = false }; horizontalPlusFigure.Segments.Add(new LineSegment() { Point = new Point(centerX + HexagonRadius * 0.5, centerY) }); plusGeometry.Figures.Add(verticalPlusFigure); plusGeometry.Figures.Add(horizontalPlusFigure); Avalonia.Controls.Shapes.Path plusPath = new Avalonia.Controls.Shapes.Path() { Data = plusGeometry, StrokeThickness = HexagonRadius * 0.2, IsHitTestVisible = false, ZIndex = 2 }; AnimatableColorBrush plusStroke = new AnimatableColorBrush(Colors.White, col => plusPath.Stroke = new SolidColorBrush(col)); tbr.Children.Add(plusPath); AnimatableTransform transform = new AnimatableTransform(new Matrix(1, 0, 0, 1, 0, 0)); leftPath.RenderTransform = transform.MatrixTransform; rightPath.RenderTransform = transform.MatrixTransform; centerPath.RenderTransform = transform.MatrixTransform; plusPath.RenderTransform = transform.MatrixTransform; bool disabled = false; centerPath.PointerEnter += (s, e) => { if (!disabled) { leftFill.Update(Color.FromRgb(180, 180, 180), false); rightFill.Update(Color.FromRgb(180, 180, 180), false); centerFill.Update(Color.FromRgb(240, 240, 240), false); plusStroke.Update(Color.FromRgb(180, 180, 180), false); } }; centerPath.PointerLeave += (s, e) => { if (!disabled) { leftFill.Update(Color.FromRgb(240, 240, 240), false); rightFill.Update(Color.FromRgb(240, 240, 240), false); centerFill.Update(Color.FromRgb(200, 200, 200), false); plusStroke.Update(Colors.White, false); } }; centerPath.PointerPressed += async(s, e) => { disabled = true; Color col = this.Owner.Color; leftFill.Update(ColorPicker.GetLighterColor(col), false); rightFill.Update(ColorPicker.GetDarkerColor(col), false); centerFill.Update(col, false); plusStroke.Update(Color.FromArgb(0, 255, 255, 255), false); await Task.Delay(100); leftPath.ZIndex = -1; centerPath.ZIndex = -1; rightPath.ZIndex = -1; plusPath.ZIndex = -1; palette.Colors.Add(col); AddColorHexagon(palette.Colors.Count - 1, palette, tbr, this, infos, this.ColourBlindnessFunction); leftFill.Update(Color.FromRgb(240, 240, 240), false); rightFill.Update(Color.FromRgb(240, 240, 240), false); centerFill.Update(Color.FromRgb(200, 200, 200), false); plusStroke.Update(Colors.White, false); tbr.Width += HexagonRadius * 2.5; double deltaX = HexagonRadius * 2.5; double deltaY = HexagonRadius * Math.Sin(Math.PI / 3) * (palette.Colors.Count % 2 == 0 ? -1 : 1); transform.Matrix = new Matrix(1, 0, 0, 1, transform.Matrix.M31 + deltaX, transform.Matrix.M32 + deltaY); await Task.Delay(100); leftPath.ZIndex = 2; centerPath.ZIndex = 2; rightPath.ZIndex = 2; plusPath.ZIndex = 2; disabled = false; }; infos.Add(new PaletteColorInfo() { Index = -1, Transform = transform }); } return(tbr); }