[WIP] Connecting AMDProfile to screens

Trying to figure out a video card agnostic way
of generating the display icons fo both standard
and spanned displays. Still trying to figure out
exactly which AMD ADL calls I need to make to
get all the information I need. It is NOT very well
documented. It's actually really annoying! AMD
need to do better.
This commit is contained in:
Terry MacDonald
2021-06-25 21:52:02 +12:00
parent 5cb0984637
commit 6a3068fb32
9 changed files with 212 additions and 134 deletions

View File

@ -58,7 +58,7 @@ namespace DisplayMagician
// .Select(grouping => grouping.First()).ToList(); // .Select(grouping => grouping.First()).ToList();
var displays = new List<DisplayRepresentation>(); var displays = new List<DisplayRepresentation>();
if (profile != null) /*if (profile != null)
{ {
foreach (var target in profile.Paths.SelectMany(path => path.TargetDisplays)) foreach (var target in profile.Paths.SelectMany(path => path.TargetDisplays))
{ {
@ -67,7 +67,7 @@ namespace DisplayMagician
displays.Add(new DisplayRepresentation(target)); displays.Add(new DisplayRepresentation(target));
} }
} }
} }*/
return displays; return displays;
} }
@ -77,7 +77,7 @@ namespace DisplayMagician
return Display.GetDisplays().FirstOrDefault(display => display.DevicePath.StartsWith(Path)); return Display.GetDisplays().FirstOrDefault(display => display.DevicePath.StartsWith(Path));
} }
public Path GetPathSource(ProfileItem profile) /*public Path GetPathSource(ProfileItem profile)
{ {
return profile.Paths.FirstOrDefault(path => path.TargetDisplays.Any(target => target.DevicePath == Path)); return profile.Paths.FirstOrDefault(path => path.TargetDisplays.Any(target => target.DevicePath == Path));
} }
@ -85,7 +85,7 @@ namespace DisplayMagician
public PathTarget GetPathTarget(ProfileItem profile) public PathTarget GetPathTarget(ProfileItem profile)
{ {
return profile.Paths.SelectMany(path => path.TargetDisplays).FirstOrDefault(target => target.DevicePath == Path); return profile.Paths.SelectMany(path => path.TargetDisplays).FirstOrDefault(target => target.DevicePath == Path);
} }*/
public PathDisplayTarget GetTargetInfo() public PathDisplayTarget GetTargetInfo()
{ {
@ -101,7 +101,7 @@ namespace DisplayMagician
var targetInfo = GetTargetInfo(); var targetInfo = GetTargetInfo();
var resolution = Size.Empty; var resolution = Size.Empty;
if (targetInfo != null && targetInfo.IsAvailable) /*if (targetInfo != null && targetInfo.IsAvailable)
{ {
resolution = targetInfo.PreferredResolution; resolution = targetInfo.PreferredResolution;
} }
@ -113,9 +113,11 @@ namespace DisplayMagician
{ {
resolution = targetPath.Resolution; resolution = targetPath.Resolution;
} }
} }*/
var p = new ProfileItem();
/*var p = new ProfileItem {Paths = new Path[1]};
var p = new ProfileItem {Paths = new Path[1]};
p.Paths[0] = new Path p.Paths[0] = new Path
{ {
Resolution = resolution, Resolution = resolution,
@ -132,7 +134,7 @@ namespace DisplayMagician
{ {
p.Paths[0].TargetDisplays[0].SurroundTopology = targetPath.SurroundTopology; p.Paths[0].TargetDisplays[0].SurroundTopology = targetPath.SurroundTopology;
} }
} }*/
return new ProfileIcon(p).ToBitmap(size.Width, size.Height); return new ProfileIcon(p).ToBitmap(size.Width, size.Height);
} }

View File

@ -587,7 +587,7 @@ namespace DisplayMagician {
return ApplyProfileResult.Successful; return ApplyProfileResult.Successful;
} }
try /*try
{ {
// Now lets prepare changing the display topology task // Now lets prepare changing the display topology task
Task applyTopologyTask = new Task(() => Task applyTopologyTask = new Task(() =>
@ -720,7 +720,7 @@ namespace DisplayMagician {
logger.Debug($"Program/ApplyProfile: Failed to complete changing the Windows Display layout"); logger.Debug($"Program/ApplyProfile: Failed to complete changing the Windows Display layout");
return ApplyProfileResult.Error; return ApplyProfileResult.Error;
} }
} }*/
ProfileRepository.UpdateActiveProfile(); ProfileRepository.UpdateActiveProfile();

View File

@ -344,15 +344,20 @@ namespace DisplayMagician.UIForms
ToolStripSeparator separator = new ToolStripSeparator(); ToolStripSeparator separator = new ToolStripSeparator();
profileToolStripMenuItem.DropDownItems.Add(separator); profileToolStripMenuItem.DropDownItems.Add(separator);
// Add the current slist of profiles into the NotifyIcon context menu
foreach (ProfileItem profile in ProfileRepository.AllProfiles) if (ProfileRepository.AllProfiles.Count > 0)
{ {
ToolStripMenuItem profileMenuItem = new ToolStripMenuItem(profile.Name, profile.ProfileBitmap, runProfileToolStripMenuItem_Click); // Add the current slist of profiles into the NotifyIcon context menu
if (profile.IsActive || !profile.IsPossible) foreach (ProfileItem profile in ProfileRepository.AllProfiles)
profileMenuItem.Enabled = false; {
else ToolStripMenuItem profileMenuItem = new ToolStripMenuItem(profile.Name, profile.ProfileBitmap, runProfileToolStripMenuItem_Click);
profileMenuItem.Enabled = true; if (profile.IsActive || !profile.IsPossible)
profileToolStripMenuItem.DropDownItems.Add(profileMenuItem); profileMenuItem.Enabled = false;
else
profileMenuItem.Enabled = true;
profileToolStripMenuItem.DropDownItems.Add(profileMenuItem);
}
} }
// Clear all the shortcuts // Clear all the shortcuts
@ -365,16 +370,20 @@ namespace DisplayMagician.UIForms
shortcutToolStripMenuItem.DropDownItems.Add(heading); shortcutToolStripMenuItem.DropDownItems.Add(heading);
separator = new ToolStripSeparator(); separator = new ToolStripSeparator();
shortcutToolStripMenuItem.DropDownItems.Add(separator); shortcutToolStripMenuItem.DropDownItems.Add(separator);
// Add the current list of profiles into the NotifyIcon context menu if (ShortcutRepository.AllShortcuts.Count > 0)
foreach (ShortcutItem shortcut in ShortcutRepository.AllShortcuts)
{ {
ToolStripMenuItem shortcutMenuItem = new ToolStripMenuItem(shortcut.Name, shortcut.ShortcutBitmap, runShortcutToolStripMenuItem_Click); // Add the current list of profiles into the NotifyIcon context menu
if (shortcut.IsValid == ShortcutValidity.Warning || shortcut.IsValid == ShortcutValidity.Error) foreach (ShortcutItem shortcut in ShortcutRepository.AllShortcuts)
shortcutMenuItem.Enabled = false; {
else ToolStripMenuItem shortcutMenuItem = new ToolStripMenuItem(shortcut.Name, shortcut.ShortcutBitmap, runShortcutToolStripMenuItem_Click);
shortcutMenuItem.Enabled = true; if (shortcut.IsValid == ShortcutValidity.Warning || shortcut.IsValid == ShortcutValidity.Error)
shortcutToolStripMenuItem.DropDownItems.Add(shortcutMenuItem); shortcutMenuItem.Enabled = false;
else
shortcutMenuItem.Enabled = true;
shortcutToolStripMenuItem.DropDownItems.Add(shortcutMenuItem);
}
} }
} }

View File

@ -1539,5 +1539,14 @@ namespace DisplayMagicianShared.AMD
{ {
return true; return true;
} }
public List<ScreenPosition> GenerateScreenPositions()
{
List<ScreenPosition> screens = new List<ScreenPosition>();
return screens;
}
} }
} }

View File

@ -20,7 +20,7 @@ namespace DisplayMagicianShared.AMD
private Bitmap _profileBitmap, _profileShortcutBitmap; private Bitmap _profileBitmap, _profileShortcutBitmap;
private List<string> _profileDisplayIdentifiers = new List<string>(); private List<string> _profileDisplayIdentifiers = new List<string>();
private List<ScreenPosition> _screens; private List<ScreenPosition> _screens;
private AMDLibrary.AMDProfile _profileData = new AMDLibrary.AMDProfile();
private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$"; private static readonly string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$";
private string _uuid = ""; private string _uuid = "";
@ -70,7 +70,22 @@ namespace DisplayMagicianShared.AMD
//public Topology.Path[] Paths { get; set; } = new Topology.Path[0]; //public Topology.Path[] Paths { get; set; } = new Topology.Path[0];
public AMDLibrary.AMDProfile ProfileData { get; set; } = new AMDLibrary.AMDProfile(); public AMDLibrary.AMDProfile ProfileData
{
get
{
return _profileData;
}
set
{
_profileData = new AMDLibrary.AMDProfile();
// We also update the screenPositions too so that
// the icons will work and graphics will display
//GetScreenPositions();
}
}
public override List<string> ProfileDisplayIdentifiers public override List<string> ProfileDisplayIdentifiers
{ {
@ -179,7 +194,37 @@ namespace DisplayMagicianShared.AMD
public override List<ScreenPosition> GetScreenPositions() public override List<ScreenPosition> GetScreenPositions()
{ {
return new List<ScreenPosition>(); if (_screens.Count == 0)
{
// Now we create the screens structure from the AMD profile information
_screens = new List<ScreenPosition>();
if ( _profileData.Adapters.Count > 0)
{
foreach ( var adapter in _profileData.Adapters)
{
foreach (var display in adapter.Displays)
{
foreach (var mode in display.DisplayModes)
{
ScreenPosition screen = new ScreenPosition();
screen.Colour = Color.Red; // represents AMD
screen.Name = mode.DisplayID.ToString();
screen.ScreenX = mode.XPos;
screen.ScreenY = mode.YPos;
screen.ScreenWidth = mode.XRes;
screen.ScreenHeight = mode.YRes;
screen.IsSpanned = false;
//screen.Features = mode.ModeValue;
_screens.Add(screen);
}
}
}
}
}
return _screens;
} }

View File

@ -31,9 +31,8 @@ namespace DisplayMagicianShared
// ReSharper disable once TooManyArguments // ReSharper disable once TooManyArguments
public static RectangleF CalculateViewSize( public static RectangleF CalculateViewSize(
List<ScreenPosition> screens, List<ScreenPosition> screens,
bool withPadding = false, int outsidePaddingSides = 0,
int paddingX = 0, int outsidePaddingTopBottom = 0)
int paddingY = 0)
{ {
var minX = 0; var minX = 0;
var maxX = 0; var maxX = 0;
@ -42,19 +41,19 @@ namespace DisplayMagicianShared
foreach (var screen in screens) foreach (var screen in screens)
{ {
var res = NormalizeResolution(screens); //var res = GetLargestResolution(screens);
minX = Math.Min(minX, screen.ScreenX); minX = Math.Min(minX, screen.ScreenX);
maxX = Math.Max(maxX, res.Width + screen.ScreenX); maxX = Math.Max(maxX, screen.ScreenX + screen.ScreenWidth);
minY = Math.Min(minY, screen.ScreenY); minY = Math.Min(minY, screen.ScreenY);
maxY = Math.Max(maxY, res.Height + screen.ScreenY); maxY = Math.Max(maxY, screen.ScreenY + screen.ScreenHeight);
} }
if (withPadding) if (outsidePaddingSides != 0)
{ {
minX -= paddingX; minX -= outsidePaddingSides;
maxX += paddingX; maxX += outsidePaddingSides;
minY -= paddingY; minY -= outsidePaddingTopBottom;
maxY += paddingY; maxY += outsidePaddingTopBottom;
} }
var size = new SizeF(Math.Abs(minX) + maxX, Math.Abs(minY) + maxY); var size = new SizeF(Math.Abs(minX) + maxX, Math.Abs(minY) + maxY);
@ -63,44 +62,20 @@ namespace DisplayMagicianShared
return rect; return rect;
} }
/*public static Size NormalizeResolution(Size resolution, Rotation rotation) /*public static Size GetLargestResolution(List<ScreenPosition> screens)
{ {
if (rotation == Rotation.Rotate90 || rotation == Rotation.Rotate270) Size largest = Size.Empty;
{
return new Size(resolution.Height, resolution.Width);
}
return resolution;
}*/
public static Size NormalizeResolution(List<ScreenPosition> screens)
{
Size biggest = Size.Empty;
foreach (ScreenPosition screen in screens) foreach (ScreenPosition screen in screens)
{ {
//var res = NormalizeResolution(screen.ScreenWidth, screen.ScreenHeight, screen.ScreenRotation); if ((ulong)screen.ScreenWidth * (ulong)screen.ScreenHeight > (ulong)largest.Width * (ulong)largest.Height)
int width = 0;
int height = 0;
if (screen.ScreenOrientation == Orientation.Vertical)
{ {
width = screen.ScreenHeight; largest = new Size(screen.ScreenWidth, screen.ScreenHeight);
height = screen.ScreenWidth;
}
else
{
width = screen.ScreenWidth;
height = screen.ScreenHeight;
}
if ((ulong) width * (ulong) height > (ulong) biggest.Width * (ulong) biggest.Height)
{
biggest = new Size(width,height);
} }
} }
return biggest; return largest;
} }*/
/// <summary> /// <summary>
@ -158,7 +133,7 @@ namespace DisplayMagicianShared
public Bitmap ToTightestBitmap(int width = 256, int height = 0, PixelFormat format = PixelFormat.Format32bppArgb) public Bitmap ToTightestBitmap(int width = 256, int height = 0, PixelFormat format = PixelFormat.Format32bppArgb)
{ {
var viewSize = CalculateViewSize(_profile.Screens, true, PaddingX, PaddingY); var viewSize = CalculateViewSize(_profile.Screens, 0, 0);
int viewSizeRatio = Convert.ToInt32(viewSize.Width / viewSize.Height); int viewSizeRatio = Convert.ToInt32(viewSize.Width / viewSize.Height);
if (height == 0) if (height == 0)
@ -214,7 +189,7 @@ namespace DisplayMagicianShared
return bitmap;*/ return bitmap;*/
var viewSize = CalculateViewSize(_profile.Screens, true, PaddingX, PaddingY); var viewSize = CalculateViewSize(_profile.Screens, PaddingX, PaddingY);
var width = bitmap.Width * 0.7f; var width = bitmap.Width * 0.7f;
var height = width / viewSize.Width * viewSize.Height; var height = width / viewSize.Width * viewSize.Height;
@ -317,16 +292,35 @@ namespace DisplayMagicianShared
return multiIcon; return multiIcon;
} }
private void DrawScreen(Graphics g, ScreenPosition screen) /*private void DrawSingleScreen(Graphics g, ScreenPosition screen)
{ {
//var res = NormalizeResolution(screen); //var res = NormalizeResolution(screen);
var rect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight); Rectangle rect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
var rows = rect.Width < rect.Height ? path.TargetDisplays.Length : 1; int rows = rect.Width < rect.Height ? path.TargetDisplays.Length : 1;
var cols = rect.Width >= rect.Height ? path.TargetDisplays.Length : 1; int cols = rect.Width >= rect.Height ? path.TargetDisplays.Length : 1;
for (var i = 0; i < path.TargetDisplays.Length; i++) for (var i = 0; i < path.TargetDisplays.Length; i++)
{ {
DrawTarget(g, path, path.TargetDisplays[i], DrawTarget(g, screen, path.TargetDisplays[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 DrawScreen(Graphics g, ScreenPosition screen)
{
//var res = NormalizeResolution(screen);
Rectangle rect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
int rows = rect.Width < rect.Height ? screen.SpannedScreens.Count : 1;
int cols = rect.Width >= rect.Height ? screen.SpannedScreens.Count : 1;
for(var i = 0; i < screen.SpannedScreens.Count ; i++)
{
DrawTarget(g, screen,
new Rectangle( new Rectangle(
rect.X + PaddingX, rect.X + PaddingX,
rect.Y + PaddingY, rect.Y + PaddingY,
@ -339,8 +333,7 @@ namespace DisplayMagicianShared
// ReSharper disable once TooManyArguments // ReSharper disable once TooManyArguments
private void DrawTarget( private void DrawTarget(
Graphics g, Graphics g,
Path path, ScreenPosition screen,
PathTarget target,
Rectangle rect, Rectangle rect,
int row, int row,
int col, int col,
@ -351,17 +344,15 @@ namespace DisplayMagicianShared
var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y); var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y);
var targetRect = new Rectangle(targetPosition, targetSize); var targetRect = new Rectangle(targetPosition, targetSize);
if (target.SurroundTopology != null) if (screen.IsSpanned)
{ {
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 106, 185, 0)), targetRect); g.FillRectangle(new SolidBrush(screen.Colour), targetRect);
} }
//else if (target.EyefinityTopology != null) else if (screen.SpannedScreens.Count > 1)
// g.FillRectangle(new SolidBrush(Color.FromArgb(255, 99, 0, 0)), targetRect);
else if (path.TargetDisplays.Length > 1)
{ {
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 255, 97, 27)), targetRect); g.FillRectangle(new SolidBrush(Color.FromArgb(255, 255, 97, 27)), targetRect);
} }
else if (path.Position == Point.Empty) else if (!screen.IsSpanned)
{ {
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 0, 174, 241)), targetRect); g.FillRectangle(new SolidBrush(Color.FromArgb(255, 0, 174, 241)), targetRect);
} }
@ -375,7 +366,7 @@ namespace DisplayMagicianShared
private void DrawView(Graphics g, float width, float height) private void DrawView(Graphics g, float width, float height)
{ {
var viewSize = CalculateViewSize(_profile.Screens, true, PaddingX, PaddingY); var viewSize = CalculateViewSize(_profile.Screens, PaddingX, PaddingY);
var standPadding = height * 0.005f; var standPadding = height * 0.005f;
height -= standPadding * 8; height -= standPadding * 8;
var factor = Math.Min((width - 2 * standPadding - 1) / viewSize.Width, var factor = Math.Min((width - 2 * standPadding - 1) / viewSize.Width,

View File

@ -15,16 +15,35 @@ namespace DisplayMagicianShared
{ {
public struct ScreenPosition public struct ScreenPosition
{
public int ScreenX;
public int ScreenY;
public int ScreenWidth;
public int ScreenHeight;
public string Name;
public bool IsPrimary;
public Color Colour;
public List<string> Features;
// If the screen is AMD Eyefinity or NVIDIA Surround or similar, it has screens that are part of it
// These two fields indicate this. THe spanned screens are added to the SpannedScreens field
public bool IsSpanned;
public List<SpannedScreenPosition> SpannedScreens;
public int SpannedColumns;
public int SpannedRows;
}
public struct SpannedScreenPosition
{ {
public int ScreenX; public int ScreenX;
public int ScreenY; public int ScreenY;
public int ScreenWidth; public int ScreenWidth;
public int ScreenHeight; public int ScreenHeight;
public Orientation ScreenOrientation;
public Rotation ScreenRotation;
public string Name; public string Name;
public bool IsPrimary; public bool IsPrimary;
public bool Colour; public Color Colour;
public List<string> Features;
public int Column;
public int Row;
} }
public class ProfileItem : IComparable public class ProfileItem : IComparable

View File

@ -572,20 +572,24 @@ namespace DisplayMagicianShared
Name = "Current Display Profile", Name = "Current Display Profile",
ProfileData = amdLibrary.GetActiveProfile() ProfileData = amdLibrary.GetActiveProfile()
//ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers() //ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers()
}; };
//activeProfile.ProfileIcon = new ProfileIcon(activeProfile);
//activeProfile.ProfileBitmap = activeProfile.ProfileIcon.ToBitmap(256, 256);
}
else {
SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Trying to access things using the NVIDIA video card driver");
activeProfile = new NVIDIAProfileItem
{
Name = "Current Display Profile",
Paths = PathInfo.GetActivePaths().Select(info => new DisplayMagicianShared.Topology.Path(info)).ToArray(),
//ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers()
};
activeProfile.ProfileIcon = new ProfileIcon(activeProfile); activeProfile.ProfileIcon = new ProfileIcon(activeProfile);
activeProfile.ProfileBitmap = activeProfile.ProfileIcon.ToBitmap(256, 256);
} }
SharedLogger.logger.Debug($"ProfileRepository/UpdateActiveProfile: Trying to access things using the NVIDIA video card driver");
activeProfile = new NVIDIAProfileItem
{
Name = "Current Display Profile",
Paths = PathInfo.GetActivePaths().Select(info => new DisplayMagicianShared.Topology.Path(info)).ToArray(),
//ProfileDisplayIdentifiers = ProfileRepository.GenerateProfileDisplayIdentifiers()
};
activeProfile.ProfileIcon = new ProfileIcon(activeProfile);
activeProfile.ProfileBitmap = activeProfile.ProfileIcon.ToBitmap(256, 256);
if (_profilesLoaded && _allProfiles.Count > 0) if (_profilesLoaded && _allProfiles.Count > 0)
{ {

View File

@ -42,26 +42,26 @@ namespace DisplayMagicianShared.UserControls
} }
} }
private virtual void DrawScreen(Graphics g, ScreenPosition screen) private void DrawScreen(Graphics g, ScreenPosition screen)
{ {
//var res = ProfileIcon.NormalizeResolution(screens); //var res = ProfileIcon.NormalizeResolution(screens);
var rect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight); var rect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
g.FillRectangle(new SolidBrush(Color.FromArgb(15, Color.White)), rect); g.FillRectangle(new SolidBrush(Color.FromArgb(15, Color.White)), rect);
g.DrawRectangle(Pens.Black, rect); g.DrawRectangle(Pens.Black, rect);
DrawString(g, path.Position.IsEmpty ? "[Primary]" : $"[{path.Position.X}, {path.Position.Y}]", rect.Size, /*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); 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 str = $"DISPLAY {screen.Name}{Environment.NewLine}{rect.Width}×{rect.Height}";
var strSize = DrawString(g, str, rect.Size, new PointF(rect.X - PaddingX / 2, rect.Y + PaddingY / 2), var strSize = DrawString(g, str, rect.Size, new PointF(rect.X - PaddingX / 2, rect.Y + PaddingY / 2),
StringAlignment.Near, StringAlignment.Far); StringAlignment.Near, StringAlignment.Far);
var rows = rect.Width < rect.Height ? path.TargetDisplays.Length : 1; var rows = rect.Width < rect.Height ? screen.SpannedScreens.Count : 1;
var cols = rect.Width >= rect.Height ? path.TargetDisplays.Length : 1; var cols = rect.Width >= rect.Height ? screen.SpannedScreens.Count : 1;
for (var i = 0; i < path.TargetDisplays.Length; i++) for (var i = 0; i < screen.SpannedScreens.Count; i++)
{ {
DrawTarget(g, path, path.TargetDisplays[i], DrawTarget(g, screen,
new Rectangle(rect.X + PaddingX, rect.Y + strSize.Height + PaddingY, rect.Width - 2 * PaddingX, new Rectangle(rect.X + PaddingX, rect.Y + strSize.Height + PaddingY, rect.Width - 2 * PaddingX,
rect.Height - strSize.Height - 2 * PaddingY), rect.Height - strSize.Height - 2 * PaddingY),
rows > 1 ? i : 0, cols > 1 ? i : 0, rows, cols); rows > 1 ? i : 0, cols > 1 ? i : 0, rows, cols);
@ -93,24 +93,24 @@ namespace DisplayMagicianShared.UserControls
return new Size((int) stringSize.Width, (int) stringSize.Height); return new Size((int) stringSize.Width, (int) stringSize.Height);
} }
private virtual void DrawSurroundTopology(Graphics g, PathTarget target, Rectangle rect) public virtual void DrawSpannedTopology(Graphics g, ScreenPosition screen, Rectangle rect)
{ {
g.DrawRectangle(Pens.Black, rect); g.DrawRectangle(Pens.Black, rect);
var targetSize = new Size(rect.Width / target.SurroundTopology.Columns, var targetSize = new Size(rect.Width / screen.SpannedColumns,
rect.Height / target.SurroundTopology.Rows); rect.Height / screen.SpannedRows);
for (var i = 0; i < target.SurroundTopology.Displays.Length; i++) for (var i = 0; i < screen.SpannedScreens.Count; i++)
{ {
var display = target.SurroundTopology.Displays[i]; var display = screen.SpannedScreens[i];
var row = i / target.SurroundTopology.Columns; var row = i / screen.SpannedColumns;
var col = i % target.SurroundTopology.Columns; var col = i % screen.SpannedColumns;
var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y); var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y);
var targetRect = new Rectangle(targetPosition, targetSize); var targetRect = new Rectangle(targetPosition, targetSize);
g.DrawRectangle(Pens.Black, targetRect); g.DrawRectangle(Pens.Black, targetRect);
switch (display.Rotation) /*switch (display.Rotation)
{ {
case Rotation.Rotate90: case Rotation.Rotate90:
DrawString(g, "90°", targetRect.Size, DrawString(g, "90°", targetRect.Size,
@ -130,26 +130,25 @@ namespace DisplayMagicianShared.UserControls
StringAlignment.Far); StringAlignment.Far);
break; break;
} }*/
if (!display.Overlap.IsEmpty) /*if (!display.Overlap.IsEmpty)
{ {
DrawString(g, $"[{-display.Overlap.X}, {-display.Overlap.Y}]", targetRect.Size, DrawString(g, $"[{-display.Overlap.X}, {-display.Overlap.Y}]", targetRect.Size,
new PointF(targetRect.X + PaddingY / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near, new PointF(targetRect.X + PaddingY / 2, targetRect.Y + PaddingY / 2), StringAlignment.Near,
StringAlignment.Near); StringAlignment.Near);
} }*/
// Invert to real monitor resolution // Invert to real monitor resolution
var res = ProfileIcon.NormalizeResolution(target.SurroundTopology.Resolution, display.Rotation); //var res = ProfileIcon.NormalizeResolution(target.SurroundTopology.Resolution, display.Rotation);
var str = $"{display.DisplayName}{Environment.NewLine}{res.Width}×{res.Height}"; /*var str = $"{display.DisplayName}{Environment.NewLine}{res.Width}×{res.Height}";
DrawString(g, str, targetRect.Size, targetRect.Location); DrawString(g, str, targetRect.Size, targetRect.Location);*/
} }
} }
private virtual void DrawTarget( private void DrawTarget(
Graphics g, Graphics g,
Path path, ScreenPosition screen,
PathTarget target,
Rectangle rect, Rectangle rect,
int row, int row,
int col, int col,
@ -160,17 +159,17 @@ namespace DisplayMagicianShared.UserControls
var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y); var targetPosition = new Point(targetSize.Width * col + rect.X, targetSize.Height * row + rect.Y);
var targetRect = new Rectangle(targetPosition, targetSize); var targetRect = new Rectangle(targetPosition, targetSize);
if (target.SurroundTopology != null) if (screen.IsSpanned)
{ {
g.FillRectangle(new SolidBrush(Color.FromArgb(150, 106, 185, 0)), targetRect); g.FillRectangle(new SolidBrush(Color.FromArgb(150, 106, 185, 0)), targetRect);
} }
//else if (target.EyefinityTopology != null) //else if (target.EyefinityTopology != null)
// g.FillRectangle(new SolidBrush(Color.FromArgb(150, 99, 0, 0)), targetRect); // g.FillRectangle(new SolidBrush(Color.FromArgb(150, 99, 0, 0)), targetRect);
else if (path.TargetDisplays.Length > 1) else if (screen.SpannedScreens.Count > 1)
{ {
g.FillRectangle(new SolidBrush(Color.FromArgb(150, 255, 97, 27)), targetRect); g.FillRectangle(new SolidBrush(Color.FromArgb(150, 255, 97, 27)), targetRect);
} }
else if (path.Position == Point.Empty) else if (!screen.IsSpanned)
{ {
g.FillRectangle(new SolidBrush(Color.FromArgb(150, 0, 174, 241)), targetRect); g.FillRectangle(new SolidBrush(Color.FromArgb(150, 0, 174, 241)), targetRect);
} }
@ -180,9 +179,9 @@ namespace DisplayMagicianShared.UserControls
} }
g.DrawRectangle(Pens.Black, targetRect); g.DrawRectangle(Pens.Black, targetRect);
var str = $"{target.DisplayName}{Environment.NewLine}{path.Resolution.Width}×{path.Resolution.Height}"; var str = $"{screen.Name}{Environment.NewLine}{screen.ScreenWidth}×{screen.ScreenHeight}";
switch (target.Rotation) /* switch (target.Rotation)
{ {
case Rotation.Rotate90: case Rotation.Rotate90:
DrawString(g, "90°", targetRect.Size, DrawString(g, "90°", targetRect.Size,
@ -203,13 +202,13 @@ namespace DisplayMagicianShared.UserControls
break; break;
} }
*/
if (target.SurroundTopology != null) if (screen.IsSpanned)
{ {
var strSize = DrawString(g, str, targetRect.Size, var strSize = DrawString(g, str, targetRect.Size,
new PointF(targetRect.X + PaddingX / 2, targetRect.Y + PaddingY / 2), new PointF(targetRect.X + PaddingX / 2, targetRect.Y + PaddingY / 2),
StringAlignment.Near, StringAlignment.Near); StringAlignment.Near, StringAlignment.Near);
DrawSurroundTopology(g, target, DrawSpannedTopology(g, screen,
new Rectangle( new Rectangle(
targetRect.X + PaddingX, targetRect.X + PaddingX,
targetRect.Y + strSize.Height + PaddingY, targetRect.Y + strSize.Height + PaddingY,
@ -224,7 +223,7 @@ namespace DisplayMagicianShared.UserControls
private void DrawView(Graphics g) private void DrawView(Graphics g)
{ {
var viewSize = ProfileIcon.CalculateViewSize(_profile.Screens, true, PaddingX, PaddingY); var viewSize = ProfileIcon.CalculateViewSize(_profile.Screens, PaddingX, PaddingY);
var factor = Math.Min(Width / viewSize.Width, Height / viewSize.Height); var factor = Math.Min(Width / viewSize.Width, Height / viewSize.Height);
g.ScaleTransform(factor, factor); g.ScaleTransform(factor, factor);