Working spanned screen bitmap drawing

This is the initial version of the spanned screen bitmap drawing. It woks by showing one giant screen, but it currently doesn't insert any information about the individual screens that make up the spanned screen at all. I'm going to add that improvement at a later date, because the main thing is to get the new libraries up and running, and used by people.
This commit is contained in:
Terry MacDonald 2021-08-24 21:49:18 +12:00
parent 90c13c7426
commit b65c1572bd
4 changed files with 97 additions and 252 deletions

View File

@ -13,6 +13,7 @@ using DisplayMagicianShared.Windows;
namespace DisplayMagicianShared.NVIDIA namespace DisplayMagicianShared.NVIDIA
{ {
public class NVIDIAProfileItem : ProfileItem, IComparable public class NVIDIAProfileItem : ProfileItem, IComparable
{ {
private static List<NVIDIAProfileItem> _allSavedProfiles = new List<NVIDIAProfileItem>(); private static List<NVIDIAProfileItem> _allSavedProfiles = new List<NVIDIAProfileItem>();
@ -220,6 +221,17 @@ namespace DisplayMagicianShared.NVIDIA
return _screens; return _screens;
} }
// TODO: Make the NVIDIA displays show the individual screens and overlap!
/*// Create a dictionary of all the screen sizes we want
Dictionary<string,SpannedScreenPosition> MosaicScreens = new Dictionary<string,SpannedScreenPosition>();
for (int i = 0; i < _nvidiaDisplayConfig.MosaicConfig.MosaicGridCount; i++)
{
for (int j = 0; j < _nvidiaDisplayConfig.MosaicConfig.MosaicViewports.Where(item => item); j++)
{
}
}*/
foreach (var path in _windowsDisplayConfig.DisplayConfigPaths) foreach (var path in _windowsDisplayConfig.DisplayConfigPaths)
{ {
// For each path we go through and get the relevant info we need. // For each path we go through and get the relevant info we need.
@ -232,6 +244,8 @@ namespace DisplayMagicianShared.NVIDIA
UInt32 sourceId = path.SourceInfo.Id; UInt32 sourceId = path.SourceInfo.Id;
UInt32 targetId = path.TargetInfo.Id; UInt32 targetId = path.TargetInfo.Id;
// Go through the screens as Windows knows them, and then enhance the info with Mosaic data if it applies
foreach (DISPLAYCONFIG_MODE_INFO displayMode in _windowsDisplayConfig.DisplayConfigModes) foreach (DISPLAYCONFIG_MODE_INFO displayMode in _windowsDisplayConfig.DisplayConfigModes)
{ {
// Find the matching Display Config Source Mode // Find the matching Display Config Source Mode
@ -250,6 +264,12 @@ namespace DisplayMagicianShared.NVIDIA
screen.IsPrimary = true; screen.IsPrimary = true;
} }
// Figure out if this is a spanned screen, and if so, record this info
if (_nvidiaDisplayConfig.MosaicConfig.IsMosaicEnabled)
{
}
break; break;
} }
} }
@ -300,6 +320,42 @@ namespace DisplayMagicianShared.NVIDIA
} }
} }
/*
// Go through the screens, and update the Mosaic screens with their info (if there are any)
if (_nvidiaDisplayConfig.MosaicConfig.IsMosaicEnabled)
{
// *** Enum values for the mosaic topology type ***
// NV_MOSAIC_TOPO_1x2_BASIC = 1
// NV_MOSAIC_TOPO_2x1_BASIC = 2,
// NV_MOSAIC_TOPO_1x3_BASIC = 3,
// NV_MOSAIC_TOPO_3x1_BASIC = 4,
// NV_MOSAIC_TOPO_1x4_BASIC = 5,
// NV_MOSAIC_TOPO_4x1_BASIC = 6,
// NV_MOSAIC_TOPO_2x2_BASIC = 7,
// NV_MOSAIC_TOPO_2x3_BASIC = 8,
// NV_MOSAIC_TOPO_2x4_BASIC = 9,
// NV_MOSAIC_TOPO_3x2_BASIC = 10,
// NV_MOSAIC_TOPO_4x2_BASIC = 11,
// NV_MOSAIC_TOPO_1x5_BASIC = 12,
// NV_MOSAIC_TOPO_1x6_BASIC = 13,
// NV_MOSAIC_TOPO_7x1_BASIC = 14,
// *** Enum values for the mosaic topology type ***
// NV_MOSAIC_TOPO_1x2_PASSIVE_STEREO = 23,
// NV_MOSAIC_TOPO_2x1_PASSIVE_STEREO = 24,
// NV_MOSAIC_TOPO_1x3_PASSIVE_STEREO = 25,
// NV_MOSAIC_TOPO_3x1_PASSIVE_STEREO = 26,
// NV_MOSAIC_TOPO_1x4_PASSIVE_STEREO = 27,
// NV_MOSAIC_TOPO_4x1_PASSIVE_STEREO = 28,
// NV_MOSAIC_TOPO_2x2_PASSIVE_STEREO = 29,
for (int screenIndex = 0; screenIndex < _screens.Count; screenIndex++)
{
// go through each screen, and check if it matches a mosaic screen
}
}*/
return _screens; return _screens;
} }

View File

@ -463,7 +463,18 @@ namespace DisplayMagicianShared
// draw the screen // draw the screen
if (screen.IsSpanned) if (screen.IsSpanned)
{ {
//g.FillRectangle(new SolidBrush(Color.FromArgb(150, 106, 185, 0)), targetRect); // We do these things only if the screen IS spanned!
// Draw the outline of the spanned monitor
Rectangle outlineRect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 33, 33, 33)), outlineRect);
g.DrawRectangle(Pens.Black, outlineRect);
// Draw the screen of the monitor
Rectangle screenRect = new Rectangle(screen.ScreenX + screenBezel, screen.ScreenY + screenBezel, screen.ScreenWidth - (screenBezel * 2), screen.ScreenHeight - (screenBezel * 2));
screenBgColour = screen.Colour;
g.FillRectangle(new SolidBrush(screenBgColour), screenRect);
g.DrawRectangle(Pens.Black, screenRect);
} }
else else
{ {

View File

@ -367,108 +367,6 @@ namespace DisplayMagicianShared
return false; return false;
} }
/* // The public override for the Object.Equals
public override bool Equals(object obj)
{
return this.Equals(obj as ProfileItem);
}
// Profiles are equal if their Viewports are equal
public virtual bool Equals(ProfileItem other)
{
// If parameter is null, return false.
if (other is null)
return false;
// Optimization for a common success case.
if (Object.ReferenceEquals(this, other))
return true;
// If run-time types are not exactly the same, return false.
if (this.GetType() != other.GetType())
return false;
//if (Paths.Length != other.Paths.Length)
// return false;
// Check if the profile identifiers are not the same, then return false
int foundDICount = 0;
foreach (string profileDI in ProfileDisplayIdentifiers)
{
if (other.ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != other.ProfileDisplayIdentifiers.Count)
return false;
foundDICount = 0;
foreach (string profileDI in other.ProfileDisplayIdentifiers)
{
if (ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != ProfileDisplayIdentifiers.Count)
return false;
// Check whether the profiles' properties are equal
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
// The data may be in different orders each run, so we need to compare them one by one
int foundPathsCount = 0;
int foundOtherPathsCount = 0;
*//*foreach (Topology.Path profilePath in Paths)
{
if (other.Paths.Contains(profilePath))
{
foundPathsCount++;
continue;
}
}
foreach (Topology.Path otherPath in other.Paths)
{
if (Paths.Contains(otherPath))
{
foundOtherPathsCount++;
continue;
}
}*//*
if (foundPathsCount == foundOtherPathsCount)
return true;
else
return false;
}*/
// If Equals() returns true for this object compared to another
// then GetHashCode() must return the same value for these objects.
/*public override int GetHashCode()
{
// Get hash code for the Viewports field if it is not null.
int hashPaths = Paths == null ? 0 : Paths.GetHashCode();
//Calculate the hash code for the product.
return hashPaths;
}*/
public override int GetHashCode() public override int GetHashCode()
{ {
@ -609,135 +507,5 @@ namespace DisplayMagicianShared
} }
} }
/*// Custom Equality comparer for the Profile class
// Allows us to use 'Contains'
class ProfileComparer : IEqualityComparer<ProfileItem>
{
// Products are equal if their names and product numbers are equal.
*//*public bool Equals(ProfileItem x, ProfileItem y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (x is null || y is null)
return false;
// Check whether the profiles' properties are equal
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
if (x.Paths.SequenceEqual(y.Paths))
return true;
else
return false;
}*//*
public bool Equals(ProfileItem x, ProfileItem y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (x is null || y is null)
return false;
//if (x.Paths.Length != y.Paths.Length)
// return false;
// Check if the profile identifiers are not the same, then return false
int foundDICount = 0;
foreach (string profileDI in x.ProfileDisplayIdentifiers)
{
if (y.ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != x.ProfileDisplayIdentifiers.Count)
return false;
foundDICount = 0;
foreach (string profileDI in y.ProfileDisplayIdentifiers)
{
if (x.ProfileDisplayIdentifiers.Contains(profileDI))
{
foundDICount++;
continue;
}
}
if (foundDICount != y.ProfileDisplayIdentifiers.Count)
return false;
// Check whether the profiles' properties are equal
// We need to exclude the name as the name is solely for saving to disk
// and displaying to the user.
// Two profiles are equal only when they have the same viewport data
int foundPathsCount = 0;
int foundOtherPathsCount = 0;
*//*foreach (Topology.Path profilePath in x.Paths)
{
if (y.Paths.Contains(profilePath))
{
foundPathsCount++;
continue;
}
}
foreach (Topology.Path otherPath in y.Paths)
{
if (x.Paths.Contains(otherPath))
{
foundOtherPathsCount++;
continue;
}
}*//*
if (foundPathsCount == foundOtherPathsCount)
return true;
else
return false;
}
// If Equals() returns true for a pair of objects
// then GetHashCode() must return the same value for these objects.
*//*public int GetHashCode(ProfileItem profile)
{
// Check whether the object is null
if (profile is null) return 0;
// Get hash code for the Viewports field if it is not null.
int hashPaths = profile.Paths == null ? 0 : profile.Paths.GetHashCode();
//Calculate the hash code for the product.
return hashPaths;
}*//*
// Modified the GetHashCode to compare the displayidentifier
public int GetHashCode(ProfileItem profile)
{
// Check whether the object is null
if (profile is null) return 0;
// Get hash code for the ProfileDisplayIdentifiers field if it is not null.
int hashIds = profile.ProfileDisplayIdentifiers == null ? 0 : profile.ProfileDisplayIdentifiers.GetHashCode();
// Get hash code for the Paths
//int hashPaths = profile.Paths == null ? 0 : profile.Paths.GetHashCode();
int hashPaths = 0;
//Calculate the hash code for the product.
return (hashIds,hashPaths).GetHashCode();
}
}*/
} }

View File

@ -247,7 +247,18 @@ namespace DisplayMagicianShared.UserControls
// draw the screen // draw the screen
if (screen.IsSpanned) if (screen.IsSpanned)
{ {
//g.FillRectangle(new SolidBrush(Color.FromArgb(150, 106, 185, 0)), targetRect); // We do these things only if the screen IS spanned!
// Draw the outline of the spanned monitor
Rectangle outlineRect = new Rectangle(screen.ScreenX, screen.ScreenY, screen.ScreenWidth, screen.ScreenHeight);
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 33, 33, 33)), outlineRect);
g.DrawRectangle(Pens.Black, outlineRect);
// Draw the screen of the monitor
Rectangle screenRect = new Rectangle(screen.ScreenX + screenBezel, screen.ScreenY + screenBezel, screen.ScreenWidth - (screenBezel * 2), screen.ScreenHeight - (screenBezel * 2));
screenBgColour = screen.Colour;
g.FillRectangle(new SolidBrush(screenBgColour), screenRect);
g.DrawRectangle(Pens.Black, screenRect);
} }
else else
{ {
@ -257,8 +268,6 @@ namespace DisplayMagicianShared.UserControls
g.FillRectangle(new SolidBrush(Color.FromArgb(255, 33, 33, 33)), outlineRect); g.FillRectangle(new SolidBrush(Color.FromArgb(255, 33, 33, 33)), outlineRect);
g.DrawRectangle(Pens.Black, outlineRect); g.DrawRectangle(Pens.Black, outlineRect);
// Draw the screen of the monitor
Rectangle screenRect = new Rectangle(screen.ScreenX + screenBezel, screen.ScreenY + screenBezel, screen.ScreenWidth - (screenBezel * 2), screen.ScreenHeight - (screenBezel * 2));
if (screen.IsPrimary) if (screen.IsPrimary)
{ {
//screenBgColour = Color.FromArgb(255, 66, 173, 245); //screenBgColour = Color.FromArgb(255, 66, 173, 245);
@ -276,25 +285,26 @@ namespace DisplayMagicianShared.UserControls
} }
} }
// Draw the screen of the monitor
Rectangle screenRect = new Rectangle(screen.ScreenX + screenBezel, screen.ScreenY + screenBezel, screen.ScreenWidth - (screenBezel * 2), screen.ScreenHeight - (screenBezel * 2));
g.FillRectangle(new SolidBrush(screenBgColour), screenRect); g.FillRectangle(new SolidBrush(screenBgColour), screenRect);
g.DrawRectangle(Pens.Black, screenRect); g.DrawRectangle(Pens.Black, screenRect);
Rectangle wordRect = new Rectangle(screen.ScreenX + screenBezel + screenWordBuffer, screen.ScreenY + screenBezel + screenWordBuffer, screen.ScreenWidth - (screenBezel * 2) - (screenWordBuffer * 2), screen.ScreenHeight - (screenBezel * 2) - (screenWordBuffer * 2));
Color wordTextColour = pickTextColorBasedOnBgColour(screenBgColour, lightTextColour, darkTextColour);
// Draw the name of the screen and the size of it
string str = $"{screen.Name}{Environment.NewLine}{screen.ScreenWidth}×{screen.ScreenHeight}{Environment.NewLine}{screen.DisplayConnector}";
if (screen.IsPrimary)
{
str = $"Primary Display{Environment.NewLine}" + str;
}
DrawString(g, str, wordTextColour, wordRect.Size, wordRect.Location);
// Draw the position of the screen
str = $"[{screen.ScreenX},{screen.ScreenY}]";
DrawString(g, str, wordTextColour, wordRect.Size, wordRect.Location, StringAlignment.Near, StringAlignment.Near);
} }
Rectangle wordRect = new Rectangle(screen.ScreenX + screenBezel + screenWordBuffer, screen.ScreenY + screenBezel + screenWordBuffer, screen.ScreenWidth - (screenBezel * 2) - (screenWordBuffer * 2), screen.ScreenHeight - (screenBezel * 2) - (screenWordBuffer * 2));
Color wordTextColour = pickTextColorBasedOnBgColour(screenBgColour, lightTextColour, darkTextColour);
// Draw the name of the screen and the size of it
string str = $"{screen.Name}{Environment.NewLine}{screen.ScreenWidth}×{screen.ScreenHeight}{Environment.NewLine}{screen.DisplayConnector}";
if (screen.IsPrimary)
{
str = $"Primary Display{Environment.NewLine}" + str;
}
DrawString(g, str, wordTextColour, wordRect.Size, wordRect.Location);
// Draw the position of the screen
str = $"[{screen.ScreenX},{screen.ScreenY}]";
DrawString(g, str, wordTextColour, wordRect.Size, wordRect.Location, StringAlignment.Near, StringAlignment.Near);
} }
} }