DisplayMagician/HeliosDisplayManagement.Shared/ProfileIcon.cs
2017-08-06 10:45:17 +04:30

279 lines
11 KiB
C#

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.IconLib;
using System.Drawing.Imaging;
using System.Linq;
using HeliosDisplayManagement.Shared.Topology;
namespace HeliosDisplayManagement.Shared
{
public class ProfileIcon
{
public ProfileIcon(Profile profile, int paddingX = 100, int paddingY = 100)
{
Profile = profile;
PaddingX = paddingX;
PaddingY = paddingY;
}
public int PaddingX { get; }
public int PaddingY { get; }
public Profile Profile { get; }
public static RectangleF CalculateViewSize(
Path[] paths,
bool withPadding = false,
int paddingX = 0,
int paddingY = 0)
{
var minX = 0;
var maxX = 0;
var minY = 0;
var maxY = 0;
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);
}
if (withPadding)
{
minX -= paddingX;
maxX += paddingX;
minY -= paddingY;
maxY += paddingY;
}
var size = new SizeF(Math.Abs(minX) + maxX, Math.Abs(minY) + maxY);
var rect = new RectangleF(new PointF(minX, minY), size);
return rect;
}
public static Size NormalizeResolution(Size resolution, Rotation rotation)
{
if ((rotation == Rotation.Rotate90) || (rotation == Rotation.Rotate270))
return new Size(resolution.Height, resolution.Width);
return resolution;
}
public static Size NormalizeResolution(Path path)
{
var bigest = Size.Empty;
foreach (var target in path.Targets)
{
var res = NormalizeResolution(path.Resolution, target.Rotation);
if ((ulong) res.Width*(ulong) res.Height > (ulong) bigest.Width*(ulong) bigest.Height)
bigest = res;
}
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)
{
var diameter = radius*2;
var size = new SizeF(diameter, diameter);
var arc = new RectangleF(bounds.Location, size);
var path = new GraphicsPath();
if (radius < 0.01)
{
path.AddRectangle(bounds);
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();
return path;
}
public Bitmap ToBitmap(int width, int height, PixelFormat format = PixelFormat.Format32bppArgb)
{
var bitmap = new Bitmap(width, height, format);
bitmap.MakeTransparent();
using (var g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = SmoothingMode.HighQuality;
DrawView(g, width, height);
}
return bitmap;
}
public Bitmap ToBitmapOverly(Bitmap bitmap)
{
var viewSize = CalculateViewSize(Profile.Paths, true, PaddingX, PaddingY);
var width = bitmap.Width*0.7f;
var height = width/viewSize.Width*viewSize.Height;
using (var g = Graphics.FromImage(bitmap))
{
g.SmoothingMode = SmoothingMode.HighQuality;
g.TranslateTransform(bitmap.Width - width, bitmap.Height - height*1.1f);
DrawView(g, width, height);
}
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");
foreach (var size in iconSizes)
{
icon.Add(ToBitmap(size.Width, size.Height));
if ((size.Width >= 256) && (size.Height >= 256))
icon[icon.Count - 1].IconImageFormat = IconImageFormat.PNG;
}
multiIcon.SelectedIndex = 0;
return multiIcon;
}
public MultiIcon ToIconOverly(string iconAddress)
{
var multiIcon = new MultiIcon();
var icon = multiIcon.Add("Icon1");
var mainIcon = new MultiIcon();
mainIcon.Load(iconAddress);
foreach (var singleIcon in mainIcon[0].Where(image =>
(image.PixelFormat == PixelFormat.Format16bppRgb565) ||
(image.PixelFormat == PixelFormat.Format24bppRgb) ||
(image.PixelFormat == PixelFormat.Format32bppArgb))
.OrderByDescending(
image =>
image.PixelFormat == PixelFormat.Format16bppRgb565
? 1
: image.PixelFormat == PixelFormat.Format24bppRgb ? 2 : 3)
.ThenByDescending(image => image.Size.Width*image.Size.Height))
{
if (!icon.All(i => (singleIcon.Size != i.Size) || (singleIcon.PixelFormat != i.PixelFormat)))
continue;
var bitmap = singleIcon.Icon.ToBitmap();
if (bitmap.PixelFormat != singleIcon.PixelFormat)
{
var clone = new Bitmap(bitmap.Width, bitmap.Height, singleIcon.PixelFormat);
using (var gr = Graphics.FromImage(clone))
{
gr.DrawImage(bitmap, new Rectangle(0, 0, clone.Width, clone.Height));
}
bitmap.Dispose();
bitmap = clone;
}
icon.Add(singleIcon.Size.Height*singleIcon.Size.Width < 24*24 ? bitmap : ToBitmapOverly(bitmap));
if ((singleIcon.Size.Width >= 256) && (singleIcon.Size.Height >= 256))
icon[icon.Count - 1].IconImageFormat = IconImageFormat.PNG;
bitmap.Dispose();
}
if (icon.Count == 0)
throw new ArgumentException();
multiIcon.SelectedIndex = 0;
return multiIcon;
}
private void DrawPath(Graphics g, Path path)
{
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;
for (var i = 0; i < path.Targets.Length; i++)
DrawTarget(g, path, path.Targets[i],
new Rectangle(
rect.X + PaddingX,
rect.Y + PaddingY,
rect.Width - 2*PaddingX,
rect.Height - 2*PaddingY),
rows > 1 ? i : 0, cols > 1 ? i : 0, rows, cols);
}
private void DrawTarget(Graphics g, Path path, PathTarget target, Rectangle rect, int row, int col, int rows,
int cols)
{
var targetSize = new Size(rect.Width/cols, rect.Height/rows);
var targetPosition = new Point(targetSize.Width*col + rect.X, targetSize.Height*row + rect.Y);
var targetRect = new Rectangle(targetPosition, targetSize);
if (target.SurroundTopology != null)
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 106, 185, 0)), targetRect);
//else if (target.EyefinityTopology != null)
// g.FillRectangle(new SolidBrush(Color.FromArgb(255, 99, 0, 0)), targetRect);
else if (path.Targets.Length > 1)
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 255, 97, 27)), targetRect);
else if (path.Position == Point.Empty)
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 0, 174, 241)), targetRect);
else
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 155, 155, 155)), targetRect);
g.DrawRectangle(new Pen(Color.FromArgb(125, 50, 50, 50), 2f), targetRect);
}
private void DrawView(Graphics g, float width, float height)
{
var viewSize = CalculateViewSize(Profile.Paths, true, PaddingX, PaddingY);
var standPadding = height*0.005f;
height -= standPadding*8;
var factor = Math.Min((width - 2*standPadding - 1)/viewSize.Width,
(height - 2*standPadding - 1)/viewSize.Height);
g.ScaleTransform(factor, factor);
var xOffset = ((width - 1)/factor - viewSize.Width)/2f;
var yOffset = ((height - 1)/factor - viewSize.Height)/2f;
g.TranslateTransform(-viewSize.X + xOffset, -viewSize.Y + yOffset);
if (standPadding*6 >= 1)
{
using (var boundRect = RoundedRect(viewSize, 2*standPadding/factor))
{
g.FillPath(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), boundRect);
g.DrawPath(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding/factor), boundRect);
}
using (
var boundRect =
RoundedRect(
new RectangleF(viewSize.Width*0.375f + viewSize.X, viewSize.Height + standPadding/factor,
viewSize.Width/4, standPadding*7/factor), 2*standPadding/factor))
{
g.FillPath(new SolidBrush(Color.FromArgb(250, 50, 50, 50)), boundRect);
g.DrawPath(new Pen(Color.FromArgb(50, 255, 255, 255), 2/factor), boundRect);
}
}
else
{
g.FillRectangle(new SolidBrush(Color.FromArgb(200, 255, 255, 255)), viewSize);
g.DrawRectangle(new Pen(Color.FromArgb(170, 50, 50, 50), standPadding/factor), viewSize.X, viewSize.Y,
viewSize.Width, viewSize.Height);
}
foreach (var path in Profile.Paths)
DrawPath(g, path);
}
}
}