220 lines
6.8 KiB
C#
220 lines
6.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Windows.Forms;
|
|
using CursorGuardRail.Dtos;
|
|
using RyzStudio.Drawing;
|
|
|
|
namespace CursorGuardRail.Windows.Forms
|
|
{
|
|
public class ScreensLayout : RyzStudio.Windows.ThemedForms.T3UserControl
|
|
{
|
|
private readonly Pen screenBorderColour = new Pen(Color.Black, 2f);
|
|
private readonly Brush screenBackColour = new SolidBrush(Color.FromArgb(218, 218, 218));
|
|
private readonly Brush selectedScreenBackColour = new SolidBrush(Color.FromArgb(0, 120, 215));
|
|
private readonly Pen selectedAreaBorderColour = new Pen(Color.FromArgb(254, 135, 0), 2f)
|
|
{
|
|
DashStyle = System.Drawing.Drawing2D.DashStyle.Dot
|
|
};
|
|
|
|
|
|
public ScreensLayout()
|
|
{
|
|
this.Font = new Font(this.Font.FontFamily, 20f, FontStyle.Regular);
|
|
}
|
|
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
{
|
|
base.OnPaint(e);
|
|
|
|
var g = e.Graphics;
|
|
|
|
for (var i=0; i<this.Screens.Count; i++)
|
|
{
|
|
var screen = this.Screens[i];
|
|
var backColour = screen.IsSelected ? selectedScreenBackColour : screenBackColour;
|
|
var foreColour = screen.IsSelected ? Color.White : this.ForeColor;
|
|
var font = screen.IsPrimary ? new Font(this.Font, FontStyle.Bold) : this.Font;
|
|
var label = (i + 1).ToString();
|
|
|
|
var rect = screen.Bound.ToRectangle();
|
|
rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height - 5);
|
|
|
|
g.FillRectangle(backColour, screen.Bound);
|
|
g.DrawRectangle(screenBorderColour, screen.Bound);
|
|
|
|
TextRenderer.DrawText(g, label, font, rect, foreColour, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter | TextFormatFlags.NoPadding| TextFormatFlags.EndEllipsis);
|
|
}
|
|
|
|
if (this.Screens.Any(x => x.IsSelected))
|
|
{
|
|
var area = CalcMaxBound(this.Screens.Where(x => x.IsSelected).Select(x => x.Bound).ToList());
|
|
|
|
g.DrawRectangle(selectedAreaBorderColour, area);
|
|
}
|
|
|
|
g.Flush();
|
|
}
|
|
|
|
protected override void OnMouseDown(MouseEventArgs e)
|
|
{
|
|
base.OnMouseDown(e);
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
{
|
|
for (var i = 0; i < this.Screens.Count; i++)
|
|
{
|
|
if (this.Screens[i].Bound.Contains(e.Location))
|
|
{
|
|
this.Screens[i].IsSelected = !this.Screens[i].IsSelected;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnResize(EventArgs e)
|
|
{
|
|
base.OnResize(e);
|
|
|
|
this.InvalidateScreens();
|
|
}
|
|
|
|
|
|
protected override void UpdateBackground()
|
|
{
|
|
if (base.ClientRectangle.Width <= 0 || base.ClientRectangle.Height <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var backColour = Color.FromArgb(242, 242, 242);
|
|
var backgroundImage = new Rectangoid(base.ClientRectangle, CurrentStyle.Border.Radius, CurrentStyle.Border.Width).ToBitmap(new Pen(new SolidBrush(CurrentStyle.Border.Colour), CurrentStyle.Border.Width), new SolidBrush(backColour));
|
|
|
|
this.BackgroundImage = backgroundImage;
|
|
}
|
|
|
|
public void InvalidateScreens()
|
|
{
|
|
var virtualDesktop = SystemInformation.VirtualScreen;
|
|
var offsetX = (virtualDesktop.X <= 0 ? -virtualDesktop.X : 0);
|
|
|
|
this.Screens.Clear();
|
|
|
|
foreach (var screen in Screen.AllScreens)
|
|
{
|
|
var bound = screen.Bounds;
|
|
bound.Offset(offsetX, 0);
|
|
|
|
var newBound = new RectangleF(bound.X, bound.Y, bound.Width, bound.Height);
|
|
newBound = newBound.ScaleDown(ScaleRatio);
|
|
|
|
this.Screens.Add(new ScreenItem()
|
|
{
|
|
Bound = newBound,
|
|
IsPrimary = screen.Primary,
|
|
IsSelected = false
|
|
});
|
|
}
|
|
|
|
CenterRectangles(this.Screens);
|
|
|
|
this.Invalidate();
|
|
}
|
|
|
|
|
|
private int ActualWidth
|
|
{
|
|
get => this.ClientSize.Width - this.Padding.Horizontal;
|
|
}
|
|
|
|
private int ActualHeight
|
|
{
|
|
get => this.ClientSize.Height - this.Padding.Vertical;
|
|
}
|
|
|
|
public List<ScreenItem> Screens
|
|
{
|
|
get
|
|
{
|
|
if (field == null) field = new List<ScreenItem>();
|
|
|
|
return field;
|
|
}
|
|
private set
|
|
{
|
|
field = value;
|
|
|
|
//this.Invalidate();
|
|
}
|
|
}
|
|
|
|
private decimal ScaleRatio
|
|
{
|
|
get
|
|
{
|
|
var virtualScreen = SystemInformation.VirtualScreen;
|
|
|
|
var widthRatio = decimal.Divide(virtualScreen.Width, ActualWidth);
|
|
var heightRatio = decimal.Divide(virtualScreen.Height, ActualHeight);
|
|
|
|
return Math.Max(widthRatio, heightRatio);
|
|
}
|
|
}
|
|
|
|
private PointF CalcCentreOffset(List<RectangleF> rectangles)
|
|
{
|
|
if (rectangles.Count <= 0)
|
|
{
|
|
return PointF.Empty;
|
|
}
|
|
|
|
// Find the bounds
|
|
var left = rectangles.Min(r => r.Left);
|
|
var top = rectangles.Min(r => r.Top);
|
|
var right = rectangles.Max(r => r.Right);
|
|
var bottom = rectangles.Max(r => r.Bottom);
|
|
|
|
var bounds = RectangleF.FromLTRB(left, top, right, bottom);
|
|
|
|
// Calculate offset
|
|
var offsetX = this.Padding.Left + (ActualWidth - bounds.Width) / 2 - bounds.Left;
|
|
var offsetY = this.Padding.Top + (ActualHeight - bounds.Height) / 2 - bounds.Top;
|
|
|
|
return new PointF(offsetX, offsetY);
|
|
}
|
|
|
|
private void CenterRectangles(List<ScreenItem> screen)
|
|
{
|
|
var offset = CalcCentreOffset(screen.Select(x => x.Bound).ToList());
|
|
|
|
for (var i=0; i<screen.Count; i++)
|
|
{
|
|
screen[i].Bound = new RectangleF(screen[i].Bound.X + offset.X, screen[i].Bound.Y + offset.Y, screen[i].Bound.Width, screen[i].Bound.Height);
|
|
}
|
|
}
|
|
|
|
private RectangleF CalcMaxBound(List<RectangleF> bounds)
|
|
{
|
|
RectangleF? rect = null;
|
|
|
|
for (var i = 0; i < bounds.Count; i++)
|
|
{
|
|
if (rect == null)
|
|
{
|
|
rect = bounds[i];
|
|
}
|
|
else
|
|
{
|
|
rect = RectangleF.Union(bounds[i], rect.Value);
|
|
}
|
|
}
|
|
|
|
return rect ?? Rectangle.Empty;
|
|
}
|
|
|
|
}
|
|
}
|