mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
Renamed app to HeliosPlus namespace so that the updated changes don't interfere with HeliosDisplayManagement if that is also installed. The fact that I've changed so much of the app means that my changes would be unlikely to be accepted by Soroush, so I'm best to release this work in a similar way to other projects like Notepad++, by keeping the same root name, and adding a plus. I've also changed the Shortcut form to put all the games in a single list to reduce the number of clicks a user has to do in order for them to create a shortcut. I have begun to prepare the form so that it will support multiple game libraries, but now I am at a point that I need to fix the Steam and Uplay game detection mechanisms so that they report the correct information for the lv_games list view.
237 lines
9.3 KiB
C#
237 lines
9.3 KiB
C#
using System;
|
||
using System.Drawing;
|
||
using System.Windows.Forms;
|
||
using HeliosPlus.Shared.Topology;
|
||
|
||
namespace HeliosPlus.Shared.UserControls
|
||
{
|
||
public partial class DisplayView : UserControl
|
||
{
|
||
private Profile _profile;
|
||
|
||
public DisplayView()
|
||
{
|
||
InitializeComponent();
|
||
ResizeRedraw = true;
|
||
}
|
||
|
||
public int PaddingX { get; set; } = 100;
|
||
public int PaddingY { get; set; } = 100;
|
||
|
||
public Profile Profile
|
||
{
|
||
get => _profile;
|
||
set
|
||
{
|
||
_profile = value;
|
||
Invalidate();
|
||
}
|
||
}
|
||
|
||
protected override void OnPaint(PaintEventArgs e)
|
||
{
|
||
base.OnPaint(e);
|
||
|
||
if (_profile != null)
|
||
{
|
||
DrawView(e.Graphics);
|
||
}
|
||
}
|
||
|
||
private void DrawPath(Graphics g, Path path)
|
||
{
|
||
var res = ProfileIcon.NormalizeResolution(path);
|
||
var rect = new Rectangle(path.Position, res);
|
||
g.FillRectangle(new SolidBrush(Color.FromArgb(15, Color.White)), rect);
|
||
g.DrawRectangle(Pens.Black, rect);
|
||
|
||
DrawString(g, path.Position.IsEmpty ? "[Primary]" : $"[{path.Position.X}, {path.Position.Y}]", rect.Size,
|
||
new PointF(rect.X + PaddingY / 2, rect.Y + PaddingY / 2), StringAlignment.Near, StringAlignment.Near);
|
||
|
||
var str = $"DISPLAY #{path.SourceId + 1}{Environment.NewLine}{rect.Width}×{rect.Height}";
|
||
var strSize = DrawString(g, str, rect.Size, new PointF(rect.X - PaddingX / 2, rect.Y + PaddingY / 2),
|
||
StringAlignment.Near, StringAlignment.Far);
|
||
|
||
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 + strSize.Height + PaddingY, rect.Width - 2 * PaddingX,
|
||
rect.Height - strSize.Height - 2 * PaddingY),
|
||
rows > 1 ? i : 0, cols > 1 ? i : 0, rows, cols);
|
||
}
|
||
}
|
||
|
||
private Size DrawString(
|
||
Graphics g,
|
||
string str,
|
||
SizeF drawingSize = default(SizeF),
|
||
PointF? drawingPoint = null,
|
||
StringAlignment vertical = StringAlignment.Center,
|
||
StringAlignment horizontal = StringAlignment.Center)
|
||
{
|
||
var format = new StringFormat(StringFormat.GenericTypographic)
|
||
{
|
||
Alignment = horizontal,
|
||
LineAlignment = vertical,
|
||
FormatFlags = StringFormatFlags.NoClip
|
||
};
|
||
var stringSize = g.MeasureString(str, Font, drawingSize, format);
|
||
|
||
if (drawingPoint != null)
|
||
{
|
||
g.DrawString(str, Font, new SolidBrush(ForeColor), new RectangleF(drawingPoint.Value, drawingSize),
|
||
format);
|
||
}
|
||
|
||
return new Size((int) stringSize.Width, (int) stringSize.Height);
|
||
}
|
||
|
||
private void DrawSurroundTopology(Graphics g, PathTarget target, Rectangle rect)
|
||
{
|
||
g.DrawRectangle(Pens.Black, rect);
|
||
|
||
var targetSize = new Size(rect.Width / target.SurroundTopology.Columns,
|
||
rect.Height / target.SurroundTopology.Rows);
|
||
|
||
for (var i = 0; i < target.SurroundTopology.Displays.Length; i++)
|
||
{
|
||
var display = target.SurroundTopology.Displays[i];
|
||
var row = i / target.SurroundTopology.Columns;
|
||
var col = i % target.SurroundTopology.Columns;
|
||
var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y);
|
||
var targetRect = new Rectangle(targetPosition, targetSize);
|
||
|
||
g.DrawRectangle(Pens.Black, targetRect);
|
||
|
||
switch (display.Rotation)
|
||
{
|
||
case Rotation.Rotate90:
|
||
DrawString(g, "90°", targetRect.Size,
|
||
new PointF(targetRect.X - PaddingX / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
|
||
StringAlignment.Far);
|
||
|
||
break;
|
||
case Rotation.Rotate180:
|
||
DrawString(g, "180°", targetRect.Size,
|
||
new PointF(targetRect.X - PaddingX / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
|
||
StringAlignment.Far);
|
||
|
||
break;
|
||
case Rotation.Rotate270:
|
||
DrawString(g, "270°", targetRect.Size,
|
||
new PointF(targetRect.X - PaddingX / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
|
||
StringAlignment.Far);
|
||
|
||
break;
|
||
}
|
||
|
||
if (!display.Overlap.IsEmpty)
|
||
{
|
||
DrawString(g, $"[{-display.Overlap.X}, {-display.Overlap.Y}]", targetRect.Size,
|
||
new PointF(targetRect.X + PaddingY / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
|
||
StringAlignment.Near);
|
||
}
|
||
|
||
// Invert to real monitor resolution
|
||
var res = ProfileIcon.NormalizeResolution(target.SurroundTopology.Resolution, display.Rotation);
|
||
var str = $"{display.DisplayName}{Environment.NewLine}{res.Width}×{res.Height}";
|
||
DrawString(g, str, targetRect.Size, targetRect.Location);
|
||
}
|
||
}
|
||
|
||
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(150, 106, 185, 0)), targetRect);
|
||
}
|
||
//else if (target.EyefinityTopology != null)
|
||
// g.FillRectangle(new SolidBrush(Color.FromArgb(150, 99, 0, 0)), targetRect);
|
||
else if (path.Targets.Length > 1)
|
||
{
|
||
g.FillRectangle(new SolidBrush(Color.FromArgb(150, 255, 97, 27)), targetRect);
|
||
}
|
||
else if (path.Position == Point.Empty)
|
||
{
|
||
g.FillRectangle(new SolidBrush(Color.FromArgb(150, 0, 174, 241)), targetRect);
|
||
}
|
||
else
|
||
{
|
||
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 155, 155, 155)), targetRect);
|
||
}
|
||
|
||
g.DrawRectangle(Pens.Black, targetRect);
|
||
var str = $"{target.DisplayName}{Environment.NewLine}{path.Resolution.Width}×{path.Resolution.Height}";
|
||
|
||
switch (target.Rotation)
|
||
{
|
||
case Rotation.Rotate90:
|
||
DrawString(g, "90°", targetRect.Size,
|
||
new PointF(targetRect.X - PaddingX / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
|
||
StringAlignment.Far);
|
||
|
||
break;
|
||
case Rotation.Rotate180:
|
||
DrawString(g, "180°", targetRect.Size,
|
||
new PointF(targetRect.X - PaddingX / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
|
||
StringAlignment.Far);
|
||
|
||
break;
|
||
case Rotation.Rotate270:
|
||
DrawString(g, "270°", targetRect.Size,
|
||
new PointF(targetRect.X - PaddingX / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
|
||
StringAlignment.Far);
|
||
|
||
break;
|
||
}
|
||
|
||
if (target.SurroundTopology != null)
|
||
{
|
||
var strSize = DrawString(g, str, targetRect.Size,
|
||
new PointF(targetRect.X + PaddingX / 2, targetRect.Y + PaddingY / 2),
|
||
StringAlignment.Near, StringAlignment.Near);
|
||
DrawSurroundTopology(g, target,
|
||
new Rectangle(
|
||
targetRect.X + PaddingX,
|
||
targetRect.Y + strSize.Height + PaddingY,
|
||
targetRect.Width - 2 * PaddingX,
|
||
targetRect.Height - strSize.Height - 2 * PaddingY));
|
||
}
|
||
else
|
||
{
|
||
DrawString(g, str, targetRect.Size, targetRect.Location);
|
||
}
|
||
}
|
||
|
||
private void DrawView(Graphics g)
|
||
{
|
||
var viewSize = ProfileIcon.CalculateViewSize(_profile.Paths, true, PaddingX, PaddingY);
|
||
var factor = Math.Min(Width / viewSize.Width, Height / viewSize.Height);
|
||
g.ScaleTransform(factor, factor);
|
||
|
||
var xOffset = (Width / factor - viewSize.Width) / 2f;
|
||
var yOffset = (Height / factor - viewSize.Height) / 2f;
|
||
g.TranslateTransform(-viewSize.X + xOffset, -viewSize.Y + yOffset);
|
||
|
||
foreach (var path in _profile.Paths)
|
||
{
|
||
DrawPath(g, path);
|
||
}
|
||
}
|
||
}
|
||
} |