2017-02-26 19:23:31 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
using System.Drawing.Drawing2D;
|
|
|
|
|
using System.Drawing.IconLib;
|
|
|
|
|
using System.Drawing.Imaging;
|
|
|
|
|
using System.Linq;
|
2020-04-23 08:16:16 +00:00
|
|
|
|
using HeliosPlus.Shared.Topology;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
|
2020-04-23 08:16:16 +00:00
|
|
|
|
namespace HeliosPlus.Shared
|
2017-02-26 19:23:31 +00:00
|
|
|
|
{
|
|
|
|
|
public class ProfileIcon
|
|
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
|
|
|
|
|
|
private Profile _profile;
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
public ProfileIcon(Profile profile, int paddingX = 100, int paddingY = 100)
|
|
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
|
_profile = profile;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
PaddingX = paddingX;
|
|
|
|
|
PaddingY = paddingY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int PaddingX { get; }
|
|
|
|
|
public int PaddingY { get; }
|
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
|
//public Profile Profile { get; }
|
2017-02-26 19:23:31 +00:00
|
|
|
|
|
2018-10-20 00:08:30 +00:00
|
|
|
|
// ReSharper disable once TooManyArguments
|
2017-02-26 19:23:31 +00:00
|
|
|
|
public static RectangleF CalculateViewSize(
|
2020-05-09 13:02:07 +00:00
|
|
|
|
ProfilePath[] paths,
|
2017-02-26 19:23:31 +00:00
|
|
|
|
bool withPadding = false,
|
|
|
|
|
int paddingX = 0,
|
|
|
|
|
int paddingY = 0)
|
|
|
|
|
{
|
|
|
|
|
var minX = 0;
|
|
|
|
|
var maxX = 0;
|
|
|
|
|
var minY = 0;
|
|
|
|
|
var maxY = 0;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
foreach (var path in paths)
|
|
|
|
|
{
|
|
|
|
|
var res = NormalizeResolution(path);
|
|
|
|
|
minX = Math.Min(minX, path.Position.X);
|
|
|
|
|
maxX = Math.Max(maxX, res.Width + path.Position.X);
|
|
|
|
|
minY = Math.Min(minY, path.Position.Y);
|
|
|
|
|
maxY = Math.Max(maxY, res.Height + path.Position.Y);
|
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
if (withPadding)
|
|
|
|
|
{
|
|
|
|
|
minX -= paddingX;
|
|
|
|
|
maxX += paddingX;
|
|
|
|
|
minY -= paddingY;
|
|
|
|
|
maxY += paddingY;
|
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
var size = new SizeF(Math.Abs(minX) + maxX, Math.Abs(minY) + maxY);
|
|
|
|
|
var rect = new RectangleF(new PointF(minX, minY), size);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return rect;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static Size NormalizeResolution(Size resolution, Rotation rotation)
|
|
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
|
if (rotation == Rotation.Rotate90 || rotation == Rotation.Rotate270)
|
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return new Size(resolution.Height, resolution.Width);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return resolution;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
|
public static Size NormalizeResolution(ProfilePath path)
|
2017-02-26 19:23:31 +00:00
|
|
|
|
{
|
|
|
|
|
var bigest = Size.Empty;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
foreach (var target in path.Targets)
|
|
|
|
|
{
|
|
|
|
|
var res = NormalizeResolution(path.Resolution, target.Rotation);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
|
|
|
|
if ((ulong) res.Width * (ulong) res.Height > (ulong) bigest.Width * (ulong) bigest.Height)
|
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
bigest = res;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return bigest.IsEmpty ? path.Resolution : bigest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Creates a rounded rectangle path
|
|
|
|
|
/// By @taffer
|
|
|
|
|
/// https://stackoverflow.com/questions/33853434/how-to-draw-a-rounded-rectangle-in-c-sharp
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static GraphicsPath RoundedRect(RectangleF bounds, float radius)
|
|
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
|
var diameter = radius * 2;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
var size = new SizeF(diameter, diameter);
|
|
|
|
|
var arc = new RectangleF(bounds.Location, size);
|
|
|
|
|
var path = new GraphicsPath();
|
|
|
|
|
|
|
|
|
|
if (radius < 0.01)
|
|
|
|
|
{
|
|
|
|
|
path.AddRectangle(bounds);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// top left arc
|
|
|
|
|
path.AddArc(arc, 180, 90);
|
|
|
|
|
|
|
|
|
|
// top right arc
|
|
|
|
|
arc.X = bounds.Right - diameter;
|
|
|
|
|
path.AddArc(arc, 270, 90);
|
|
|
|
|
|
|
|
|
|
// bottom right arc
|
|
|
|
|
arc.Y = bounds.Bottom - diameter;
|
|
|
|
|
path.AddArc(arc, 0, 90);
|
|
|
|
|
|
|
|
|
|
// bottom left arc
|
|
|
|
|
arc.X = bounds.Left;
|
|
|
|
|
path.AddArc(arc, 90, 90);
|
|
|
|
|
|
|
|
|
|
path.CloseFigure();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Bitmap ToBitmap(int width, int height, PixelFormat format = PixelFormat.Format32bppArgb)
|
|
|
|
|
{
|
|
|
|
|
var bitmap = new Bitmap(width, height, format);
|
|
|
|
|
bitmap.MakeTransparent();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
using (var g = Graphics.FromImage(bitmap))
|
|
|
|
|
{
|
|
|
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
DrawView(g, width, height);
|
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return bitmap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Bitmap ToBitmapOverly(Bitmap bitmap)
|
|
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
|
var viewSize = CalculateViewSize(_profile.Paths, true, PaddingX, PaddingY);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
var width = bitmap.Width * 0.7f;
|
|
|
|
|
var height = width / viewSize.Width * viewSize.Height;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
|
|
|
|
|
using (var g = Graphics.FromImage(bitmap))
|
|
|
|
|
{
|
|
|
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
g.TranslateTransform(bitmap.Width - width, bitmap.Height - height * 1.1f);
|
2017-02-26 19:23:31 +00:00
|
|
|
|
DrawView(g, width, height);
|
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return bitmap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MultiIcon ToIcon()
|
|
|
|
|
{
|
|
|
|
|
var iconSizes = new[]
|
|
|
|
|
{
|
|
|
|
|
new Size(256, 256),
|
|
|
|
|
new Size(64, 64),
|
|
|
|
|
new Size(48, 48),
|
|
|
|
|
new Size(32, 32),
|
|
|
|
|
new Size(24, 24),
|
|
|
|
|
new Size(16, 16)
|
|
|
|
|
};
|
|
|
|
|
var multiIcon = new MultiIcon();
|
|
|
|
|
var icon = multiIcon.Add("Icon1");
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
foreach (var size in iconSizes)
|
|
|
|
|
{
|
|
|
|
|
icon.Add(ToBitmap(size.Width, size.Height));
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
|
|
|
|
if (size.Width >= 256 && size.Height >= 256)
|
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
icon[icon.Count - 1].IconImageFormat = IconImageFormat.PNG;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
multiIcon.SelectedIndex = 0;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return multiIcon;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public MultiIcon ToIconOverly(string iconAddress)
|
|
|
|
|
{
|
|
|
|
|
var multiIcon = new MultiIcon();
|
|
|
|
|
var icon = multiIcon.Add("Icon1");
|
|
|
|
|
var mainIcon = new MultiIcon();
|
|
|
|
|
mainIcon.Load(iconAddress);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
foreach (var singleIcon in mainIcon[0].Where(image =>
|
2018-10-20 00:27:25 +00:00
|
|
|
|
image.PixelFormat == PixelFormat.Format16bppRgb565 ||
|
|
|
|
|
image.PixelFormat == PixelFormat.Format24bppRgb ||
|
|
|
|
|
image.PixelFormat == PixelFormat.Format32bppArgb)
|
2017-02-26 19:23:31 +00:00
|
|
|
|
.OrderByDescending(
|
|
|
|
|
image =>
|
|
|
|
|
image.PixelFormat == PixelFormat.Format16bppRgb565
|
|
|
|
|
? 1
|
2018-10-20 00:27:25 +00:00
|
|
|
|
: image.PixelFormat == PixelFormat.Format24bppRgb
|
|
|
|
|
? 2
|
|
|
|
|
: 3)
|
|
|
|
|
.ThenByDescending(image => image.Size.Width * image.Size.Height))
|
2017-02-26 19:23:31 +00:00
|
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
|
if (!icon.All(i => singleIcon.Size != i.Size || singleIcon.PixelFormat != i.PixelFormat))
|
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
continue;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
var bitmap = singleIcon.Icon.ToBitmap();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
if (bitmap.PixelFormat != singleIcon.PixelFormat)
|
|
|
|
|
{
|
|
|
|
|
var clone = new Bitmap(bitmap.Width, bitmap.Height, singleIcon.PixelFormat);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
using (var gr = Graphics.FromImage(clone))
|
|
|
|
|
{
|
|
|
|
|
gr.DrawImage(bitmap, new Rectangle(0, 0, clone.Width, clone.Height));
|
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
bitmap.Dispose();
|
|
|
|
|
bitmap = clone;
|
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
|
|
|
|
icon.Add(singleIcon.Size.Height * singleIcon.Size.Width < 24 * 24 ? bitmap : ToBitmapOverly(bitmap));
|
|
|
|
|
|
|
|
|
|
if (singleIcon.Size.Width >= 256 && singleIcon.Size.Height >= 256)
|
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
icon[icon.Count - 1].IconImageFormat = IconImageFormat.PNG;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
bitmap.Dispose();
|
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
if (icon.Count == 0)
|
2018-10-20 00:27:25 +00:00
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
throw new ArgumentException();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
multiIcon.SelectedIndex = 0;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
return multiIcon;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
|
private void DrawPath(Graphics g, ProfilePath path)
|
2017-02-26 19:23:31 +00:00
|
|
|
|
{
|
|
|
|
|
var res = NormalizeResolution(path);
|
|
|
|
|
var rect = new Rectangle(path.Position, res);
|
|
|
|
|
var rows = rect.Width < rect.Height ? path.Targets.Length : 1;
|
|
|
|
|
var cols = rect.Width >= rect.Height ? path.Targets.Length : 1;
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
for (var i = 0; i < path.Targets.Length; i++)
|
2018-10-20 00:27:25 +00:00
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
DrawTarget(g, path, path.Targets[i],
|
|
|
|
|
new Rectangle(
|
|
|
|
|
rect.X + PaddingX,
|
|
|
|
|
rect.Y + PaddingY,
|
2018-10-20 00:27:25 +00:00
|
|
|
|
rect.Width - 2 * PaddingX,
|
|
|
|
|
rect.Height - 2 * PaddingY),
|
2017-02-26 19:23:31 +00:00
|
|
|
|
rows > 1 ? i : 0, cols > 1 ? i : 0, rows, cols);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-10-20 00:08:30 +00:00
|
|
|
|
// ReSharper disable once TooManyArguments
|
2018-10-20 00:27:25 +00:00
|
|
|
|
private void DrawTarget(
|
|
|
|
|
Graphics g,
|
2020-05-09 13:02:07 +00:00
|
|
|
|
ProfilePath path,
|
|
|
|
|
ProfilePathTarget target,
|
2018-10-20 00:27:25 +00:00
|
|
|
|
Rectangle rect,
|
|
|
|
|
int row,
|
|
|
|
|
int col,
|
|
|
|
|
int rows,
|
2017-02-26 19:23:31 +00:00
|
|
|
|
int cols)
|
|
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
|
var targetSize = new Size(rect.Width / cols, rect.Height / rows);
|
|
|
|
|
var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y);
|
2017-02-26 19:23:31 +00:00
|
|
|
|
var targetRect = new Rectangle(targetPosition, targetSize);
|
|
|
|
|
|
|
|
|
|
if (target.SurroundTopology != null)
|
2018-10-20 00:27:25 +00:00
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 106, 185, 0)), targetRect);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
//else if (target.EyefinityTopology != null)
|
|
|
|
|
// g.FillRectangle(new SolidBrush(Color.FromArgb(255, 99, 0, 0)), targetRect);
|
|
|
|
|
else if (path.Targets.Length > 1)
|
2018-10-20 00:27:25 +00:00
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 255, 97, 27)), targetRect);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
else if (path.Position == Point.Empty)
|
2018-10-20 00:27:25 +00:00
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 0, 174, 241)), targetRect);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
else
|
2018-10-20 00:27:25 +00:00
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 155, 155, 155)), targetRect);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
g.DrawRectangle(new Pen(Color.FromArgb(125, 50, 50, 50), 2f), targetRect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void DrawView(Graphics g, float width, float height)
|
|
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
|
var viewSize = CalculateViewSize(_profile.Paths, true, PaddingX, PaddingY);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
var standPadding = height * 0.005f;
|
|
|
|
|
height -= standPadding * 8;
|
|
|
|
|
var factor = Math.Min((width - 2 * standPadding - 1) / viewSize.Width,
|
|
|
|
|
(height - 2 * standPadding - 1) / viewSize.Height);
|
2017-02-26 19:23:31 +00:00
|
|
|
|
g.ScaleTransform(factor, factor);
|
|
|
|
|
|
2018-10-20 00:27:25 +00:00
|
|
|
|
var xOffset = ((width - 1) / factor - viewSize.Width) / 2f;
|
|
|
|
|
var yOffset = ((height - 1) / factor - viewSize.Height) / 2f;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
g.TranslateTransform(-viewSize.X + xOffset, -viewSize.Y + yOffset);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
|
|
|
|
if (standPadding * 6 >= 1)
|
2017-02-26 19:23:31 +00:00
|
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
|
using (var boundRect = RoundedRect(viewSize, 2 * standPadding / factor))
|
2017-02-26 19:23:31 +00:00
|
|
|
|
{
|
|
|
|
|
g.FillPath(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), boundRect);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
g.DrawPath(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding / factor), boundRect);
|
2017-02-26 19:23:31 +00:00
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
|
using (
|
|
|
|
|
var boundRect =
|
|
|
|
|
RoundedRect(
|
2018-10-20 00:27:25 +00:00
|
|
|
|
new RectangleF(viewSize.Width * 0.375f + viewSize.X,
|
|
|
|
|
viewSize.Height + standPadding / factor,
|
|
|
|
|
viewSize.Width / 4, standPadding * 7 / factor), 2 * standPadding / factor))
|
2017-02-26 19:23:31 +00:00
|
|
|
|
{
|
|
|
|
|
g.FillPath(new SolidBrush(Color.FromArgb(250, 50, 50, 50)), boundRect);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
g.DrawPath(new Pen(Color.FromArgb(50, 255, 255, 255), 2 / factor), boundRect);
|
2017-02-26 19:23:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
g.FillRectangle(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), viewSize);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
g.DrawRectangle(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding / factor), viewSize.X, viewSize.Y,
|
2017-02-26 19:23:31 +00:00
|
|
|
|
viewSize.Width, viewSize.Height);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
|
foreach (var path in _profile.Paths)
|
2018-10-20 00:27:25 +00:00
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
|
DrawPath(g, path);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|