diff --git a/HeliosPlus.Shared/HeliosPlus.Shared.csproj b/HeliosPlus.Shared/HeliosPlus.Shared.csproj index 62606a5..fce0477 100644 --- a/HeliosPlus.Shared/HeliosPlus.Shared.csproj +++ b/HeliosPlus.Shared/HeliosPlus.Shared.csproj @@ -63,9 +63,9 @@ - - - + + + Language.resx diff --git a/HeliosPlus.Shared/ProfileIcon.cs b/HeliosPlus.Shared/ProfileIcon.cs index d3525a7..f063d12 100644 --- a/HeliosPlus.Shared/ProfileIcon.cs +++ b/HeliosPlus.Shared/ProfileIcon.cs @@ -28,7 +28,7 @@ namespace HeliosPlus.Shared // ReSharper disable once TooManyArguments public static RectangleF CalculateViewSize( - ProfileViewport[] paths, + Path[] paths, bool withPadding = false, int paddingX = 0, int paddingY = 0) @@ -71,7 +71,7 @@ namespace HeliosPlus.Shared return resolution; } - public static Size NormalizeResolution(ProfileViewport path) + public static Size NormalizeResolution(Path path) { var biggest = Size.Empty; @@ -144,7 +144,7 @@ namespace HeliosPlus.Shared public Bitmap ToTightestBitmap(int width = 256, int height = 0, PixelFormat format = PixelFormat.Format32bppArgb) { - var viewSize = CalculateViewSize(_profile.Viewports, true, PaddingX, PaddingY); + var viewSize = CalculateViewSize(_profile.Paths, true, PaddingX, PaddingY); int viewSizeRatio = Convert.ToInt32(viewSize.Width / viewSize.Height); if (height == 0) @@ -200,7 +200,7 @@ namespace HeliosPlus.Shared return bitmap;*/ - var viewSize = CalculateViewSize(_profile.Viewports, true, PaddingX, PaddingY); + var viewSize = CalculateViewSize(_profile.Paths, true, PaddingX, PaddingY); var width = bitmap.Width * 0.7f; var height = width / viewSize.Width * viewSize.Height; @@ -303,7 +303,7 @@ namespace HeliosPlus.Shared return multiIcon; } - private void DrawPath(Graphics g, ProfileViewport path) + private void DrawPath(Graphics g, Path path) { var res = NormalizeResolution(path); var rect = new Rectangle(path.Position, res); @@ -325,8 +325,8 @@ namespace HeliosPlus.Shared // ReSharper disable once TooManyArguments private void DrawTarget( Graphics g, - ProfileViewport path, - ProfileViewportTargetDisplay target, + Path path, + PathTarget target, Rectangle rect, int row, int col, @@ -361,7 +361,7 @@ namespace HeliosPlus.Shared private void DrawView(Graphics g, float width, float height) { - var viewSize = CalculateViewSize(_profile.Viewports, true, PaddingX, PaddingY); + 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, @@ -398,7 +398,7 @@ namespace HeliosPlus.Shared viewSize.Width, viewSize.Height); } - foreach (var path in _profile.Viewports) + foreach (var path in _profile.Paths) { DrawPath(g, path); } diff --git a/HeliosPlus.Shared/ProfileItem.cs b/HeliosPlus.Shared/ProfileItem.cs index a91d9d3..5813c51 100644 --- a/HeliosPlus.Shared/ProfileItem.cs +++ b/HeliosPlus.Shared/ProfileItem.cs @@ -160,8 +160,8 @@ namespace HeliosPlus.Shared public string Name { get; set; } - public Topology.Path[] Viewports { get; set; } = new Topology.Path[0]; - + public Topology.Path[] Paths { get; set; } = new Topology.Path[0]; + [JsonIgnore] public ProfileIcon ProfileIcon { @@ -269,7 +269,7 @@ namespace HeliosPlus.Shared public bool IsValid() { - if (Viewports != null && + if (Paths != null && ProfileIcon is Bitmap && File.Exists(SavedProfileIconCacheFilename) && ProfileBitmap is Bitmap && @@ -292,7 +292,7 @@ namespace HeliosPlus.Shared // Copy all our profile data over to the other profile profile.Name = Name; - profile.Viewports = Viewports; + profile.Paths = Paths; profile.ProfileIcon = ProfileIcon; profile.SavedProfileIconCacheFilename = SavedProfileIconCacheFilename; profile.ProfileBitmap = ProfileBitmap; @@ -340,7 +340,7 @@ namespace HeliosPlus.Shared // 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 (Viewports.SequenceEqual(other.Viewports)) + if (Paths.SequenceEqual(other.Paths)) return true; else return false; @@ -352,7 +352,7 @@ namespace HeliosPlus.Shared { // Get hash code for the Viewports field if it is not null. - int hashViewports = Viewports == null ? 0 : Viewports.GetHashCode(); + int hashViewports = Paths == null ? 0 : Paths.GetHashCode(); //Calculate the hash code for the product. return hashViewports; @@ -396,7 +396,7 @@ namespace HeliosPlus.Shared // 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.Viewports.Equals(y.Viewports)) + if (x.Paths.Equals(y.Paths)) return true; else return false; @@ -411,7 +411,7 @@ namespace HeliosPlus.Shared if (Object.ReferenceEquals(profile, null)) return 0; // Get hash code for the Viewports field if it is not null. - int hashViewports = profile.Viewports == null ? 0 : profile.Viewports.GetHashCode(); + int hashViewports = profile.Paths == null ? 0 : profile.Paths.GetHashCode(); //Calculate the hash code for the product. return hashViewports; diff --git a/HeliosPlus.Shared/ProfileRepository.cs b/HeliosPlus.Shared/ProfileRepository.cs index 01f7e10..cd57786 100644 --- a/HeliosPlus.Shared/ProfileRepository.cs +++ b/HeliosPlus.Shared/ProfileRepository.cs @@ -26,7 +26,7 @@ using System.Resources; using System.Net.NetworkInformation; using NvAPIWrapper.Mosaic; using NvAPIWrapper.Native.Mosaic; -using PathInfos = HeliosPlus.Shared.Topology.PathInfo; +using HeliosPlus.Shared.Topology; namespace HeliosPlus.Shared @@ -359,7 +359,7 @@ namespace HeliosPlus.Shared ProfileItem activeProfile = new ProfileItem { Name = "Current Display Profile", - Viewports = PathInfo.GetActivePaths().Select(info => new Path(info)).ToArray() + Paths = PathInfo.GetActivePaths().Select(info => new HeliosPlus.Shared.Topology.Path(info)).ToArray() }; activeProfile.ProfileIcon = new ProfileIcon(activeProfile); @@ -460,7 +460,7 @@ namespace HeliosPlus.Shared ProfileItem myCurrentProfile = new ProfileItem { Name = "Current Display Profile", - Viewports = PathInfo.GetActivePaths().Select(info => new Path(info)).ToArray() + Paths = PathInfo.GetActivePaths().Select(info => new HeliosPlus.Shared.Topology.Path(info)).ToArray() }; _currentProfile = myCurrentProfile; @@ -485,7 +485,7 @@ namespace HeliosPlus.Shared ProfileItem myCurrentProfile = new ProfileItem { Name = "Current Display Profile", - Viewports = PathInfo.GetActivePaths().Select(info => new Path(info)).ToArray() + Paths = PathInfo.GetActivePaths().Select(info => new HeliosPlus.Shared.Topology.Path(info)).ToArray() }; _currentProfile = myCurrentProfile; @@ -836,7 +836,7 @@ namespace HeliosPlus.Shared try { var surroundTopologies = - profile.Viewports.SelectMany(viewport => viewport.TargetDisplays) + profile.Paths.SelectMany(viewport => viewport.TargetDisplays) .Select(target => target.SurroundTopology) .Where(topology => topology != null) .Select(topology => topology.ToGridTopology()) @@ -878,13 +878,23 @@ namespace HeliosPlus.Shared try { - // If Nvidia then we need to handle NVidia style - - var pathInfos = profile.Viewports.Select(viewport => viewport.ToPathInfo()).Where(info => info != null).ToArray(); - var test = new NvAPIWrapper.Display.PathInfo; - var v2obj = test.GetPathInfoV2(); - - WindowsDisplayAPI.DisplayConfig.PathInfo.ApplyPathInfos(pathInfos, true, true, true); + /*var viewports = profile.Viewports; + foreach (var viewport in viewports) + { + var vpPathInfo = viewport.ToPathInfo(); + }*/ + + + + var pathInfos = profile.Paths.Select(viewport => viewport.ToPathInfo()).Where(info => info != null).ToArray(); + //var PathInfos2 = NvAPIWrapper.Display.PathInfo.GetDisplaysConfig(); + /*if (!pathInfos.Any()) + { + throw new InvalidOperationException( + @"Display configuration changed since this profile is created. Please re-create this profile."); + }*/ + //var PathInfo2 = WindowsDisplayAPI.DisplayConfig.PathInfo.GetActivePaths(); + PathInfo.ApplyPathInfos(pathInfos, true, true, true); return true; } catch (Exception ex) diff --git a/HeliosPlus.Shared/Topology/Path.cs b/HeliosPlus.Shared/Topology/Path.cs new file mode 100644 index 0000000..252e718 --- /dev/null +++ b/HeliosPlus.Shared/Topology/Path.cs @@ -0,0 +1,186 @@ +using System; +using System.Drawing; +using System.Linq; +using WindowsDisplayAPI.DisplayConfig; +using WindowsDisplayAPI.Native.DisplayConfig; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System.Collections.Generic; + +namespace HeliosPlus.Shared.Topology +{ + public class Path + { + public Path(PathInfo pathInfo) + { + SourceId = pathInfo.DisplaySource.SourceId; + PixelFormat = pathInfo.PixelFormat; + Position = pathInfo.Position; + Resolution = pathInfo.Resolution; + TargetDisplays = pathInfo.TargetsInfo.Select(targetDisplay => new PathTarget(targetDisplay)).ToArray(); + } + + public Path() + { + } + + [JsonConverter(typeof(StringEnumConverter))] + public DisplayConfigPixelFormat PixelFormat { get; set; } + + public Point Position { get; set; } + + public Size Resolution { get; set; } + + public uint SourceId { get; set; } + + public PathTarget[] TargetDisplays { get; set; } + + public override string ToString() + { + return $"\\\\.\\DISPLAY{SourceId}"; + } + + public PathInfo ToPathInfo() + { + var targetDisplays = TargetDisplays.Select(target => target.ToPathTargetInfo()).Where(info => info != null).ToArray(); + + if (targetDisplays.Any()) + { + return new PathInfo(new PathDisplaySource(targetDisplays.First().DisplayTarget.Adapter, SourceId), Position, + Resolution, PixelFormat, targetDisplays); + } + + return null; + } + + // The public override for the Object.Equals + public override bool Equals(object obj) + { + return this.Equals(obj as Path); + } + + // Profiles are equal if their contents (except name) are equal + public bool Equals(Path other) + { + + // If parameter is null, return false. + if (Object.ReferenceEquals(other, 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; + + // Check whether the Profile Viewport properties are equal + // Two profiles are equal only when they have the same viewport data exactly + if (PixelFormat == other.PixelFormat && + Position.Equals(other.Position) && + Resolution.Equals(other.Resolution) && + SourceId == other.SourceId) + { + // If the above all match, then we need to check the DisplayTargets + foreach (PathTarget targetDisplay in TargetDisplays) + { + if (!other.TargetDisplays.Contains(targetDisplay)) + return false; + } + 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 PixelFormat field if it is not null. + int hashPixelFormat = PixelFormat.GetHashCode(); + + // Get hash code for the Position field if it is not null. + int hashPosition = Position == null ? 0 : Position.GetHashCode(); + + // Get hash code for the Resolution field if it is not null. + int hashResolution = Resolution == null ? 0 : Resolution.GetHashCode(); + + // Get hash code for the SourceId field if it is not null. + int hashSourceId = SourceId.GetHashCode(); + + // Get hash code for the TargetDisplays field if it is not null. + int hashTargetDisplays = TargetDisplays == null ? 0 : TargetDisplays.GetHashCode(); + + //Calculate the hash code for the product. + return hashPixelFormat ^ hashPosition ^ hashResolution ^ hashSourceId ^ hashTargetDisplays; + } + } + + // Custom comparer for the ProfileViewport class + class ProfileViewportComparer : IEqualityComparer + { + // Products are equal if their names and product numbers are equal. + public bool Equals(Path x, Path 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 (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null)) + return false; + + // Check whether the Profile Viewport properties are equal + // Two profiles are equal only when they have the same viewport data exactly + if (x.PixelFormat == y.PixelFormat && + x.Position.Equals(y.Position) && + x.Resolution.Equals(y.Resolution) && + x.SourceId == y.SourceId) + { + // If the above all match, then we need to check the DisplayTargets + // If they aren't equal then we need to return false; + if (!x.TargetDisplays.SequenceEqual(y.TargetDisplays)) + return false; + else + return true; + /* foreach (ProfileViewportTargetDisplay xTargetDisplay in x.TargetDisplays) + { + if (!y.TargetDisplays.Contains(xTargetDisplay)) + return false; + }*/ + //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(Path profileViewport) + { + // Check whether the object is null + if (Object.ReferenceEquals(profileViewport, null)) return 0; + + // Get hash code for the PixelFormat field if it is not null. + int hashPixelFormat = profileViewport.PixelFormat.GetHashCode(); + + // Get hash code for the Position field if it is not null. + int hashPosition = profileViewport.Position == null ? 0 : profileViewport.Position.GetHashCode(); + + // Get hash code for the Resolution field if it is not null. + int hashResolution = profileViewport.Resolution == null ? 0 : profileViewport.Resolution.GetHashCode(); + + // Get hash code for the SourceId field if it is not null. + int hashSourceId = profileViewport.SourceId.GetHashCode(); + + // Get hash code for the TargetDisplays field if it is not null. + int hashTargetDisplays = profileViewport.TargetDisplays == null ? 0 : profileViewport.TargetDisplays.GetHashCode(); + + //Calculate the hash code for the product. + return hashPixelFormat ^ hashPosition ^ hashResolution ^ hashSourceId ^ hashTargetDisplays; + } + + } +} \ No newline at end of file diff --git a/HeliosPlus.Shared/Topology/ProfileViewportHelper.cs b/HeliosPlus.Shared/Topology/PathHelper.cs similarity index 98% rename from HeliosPlus.Shared/Topology/ProfileViewportHelper.cs rename to HeliosPlus.Shared/Topology/PathHelper.cs index 5482366..2368fe9 100644 --- a/HeliosPlus.Shared/Topology/ProfileViewportHelper.cs +++ b/HeliosPlus.Shared/Topology/PathHelper.cs @@ -2,7 +2,7 @@ namespace HeliosPlus.Shared.Topology { - internal static class ProfileViewportHelper + internal static class PathHelper { public static DisplayConfigRotation ToDisplayConfigRotation(this Rotation rotation) { diff --git a/HeliosPlus.Shared/Topology/ProfileViewportTargetDisplay.cs b/HeliosPlus.Shared/Topology/PathTarget.cs similarity index 93% rename from HeliosPlus.Shared/Topology/ProfileViewportTargetDisplay.cs rename to HeliosPlus.Shared/Topology/PathTarget.cs index c4bf802..4ac095e 100644 --- a/HeliosPlus.Shared/Topology/ProfileViewportTargetDisplay.cs +++ b/HeliosPlus.Shared/Topology/PathTarget.cs @@ -8,9 +8,9 @@ using System.Collections.Generic; namespace HeliosPlus.Shared.Topology { - public class ProfileViewportTargetDisplay : IEquatable + public class PathTarget : IEquatable { - public ProfileViewportTargetDisplay(PathTargetInfo targetInfo, SurroundTopology surround = null) + public PathTarget(PathTargetInfo targetInfo, SurroundTopology surround = null) { DevicePath = targetInfo.DisplayTarget.DevicePath; var index = DevicePath.IndexOf("{", StringComparison.InvariantCultureIgnoreCase); @@ -38,7 +38,7 @@ namespace HeliosPlus.Shared.Topology } - public ProfileViewportTargetDisplay() + public PathTarget() { } @@ -74,6 +74,10 @@ namespace HeliosPlus.Shared.Topology target => target.DevicePath.StartsWith(DevicePath, StringComparison.InvariantCultureIgnoreCase)); + // TODO fix - Trying to allow NVIDIA surround to non-NVIDIA surround move and doesnt work. + /* var targetDevice = + PathDisplayTarget.GetDisplayTargets().FirstOrDefault();*/ + if (targetDevice == null) { return null; @@ -87,11 +91,11 @@ namespace HeliosPlus.Shared.Topology // The public override for the Object.Equals public override bool Equals(object obj) { - return this.Equals(obj as ProfileViewportTargetDisplay); + return this.Equals(obj as PathTarget); } // Profiles are equal if their contents (except name) are equal - public bool Equals(ProfileViewportTargetDisplay other) + public bool Equals(PathTarget other) { // If parameter is null, return false. @@ -164,10 +168,10 @@ namespace HeliosPlus.Shared.Topology } // Custom comparer for the ProfileViewportTargetDisplay class - class ProfileViewportTargetDisplayComparer : IEqualityComparer + class ProfileViewportTargetDisplayComparer : IEqualityComparer { // Products are equal if their names and product numbers are equal. - public bool Equals(ProfileViewportTargetDisplay x, ProfileViewportTargetDisplay y) + public bool Equals(PathTarget x, PathTarget y) { //Check whether the compared objects reference the same data. @@ -204,7 +208,7 @@ namespace HeliosPlus.Shared.Topology // If Equals() returns true for a pair of objects // then GetHashCode() must return the same value for these objects. - public int GetHashCode(ProfileViewportTargetDisplay profileViewport) + public int GetHashCode(PathTarget profileViewport) { // Check whether the object is null if (Object.ReferenceEquals(profileViewport, null)) return 0; diff --git a/HeliosPlus.Shared/UserControls/DisplayView.cs b/HeliosPlus.Shared/UserControls/DisplayView.cs index e36ccbe..b81b4c5 100644 --- a/HeliosPlus.Shared/UserControls/DisplayView.cs +++ b/HeliosPlus.Shared/UserControls/DisplayView.cs @@ -38,7 +38,7 @@ namespace HeliosPlus.Shared.UserControls } } - private void DrawPath(Graphics g, ProfileViewport path) + private void DrawPath(Graphics g, Path path) { var res = ProfileIcon.NormalizeResolution(path); var rect = new Rectangle(path.Position, res); @@ -89,7 +89,7 @@ namespace HeliosPlus.Shared.UserControls return new Size((int) stringSize.Width, (int) stringSize.Height); } - private void DrawSurroundTopology(Graphics g, ProfileViewportTargetDisplay target, Rectangle rect) + private void DrawSurroundTopology(Graphics g, PathTarget target, Rectangle rect) { g.DrawRectangle(Pens.Black, rect); @@ -144,8 +144,8 @@ namespace HeliosPlus.Shared.UserControls private void DrawTarget( Graphics g, - ProfileViewport path, - ProfileViewportTargetDisplay target, + Path path, + PathTarget target, Rectangle rect, int row, int col, @@ -220,7 +220,7 @@ namespace HeliosPlus.Shared.UserControls private void DrawView(Graphics g) { - var viewSize = ProfileIcon.CalculateViewSize(_profile.Viewports, true, PaddingX, PaddingY); + var viewSize = ProfileIcon.CalculateViewSize(_profile.Paths, true, PaddingX, PaddingY); var factor = Math.Min(Width / viewSize.Width, Height / viewSize.Height); g.ScaleTransform(factor, factor); @@ -228,7 +228,7 @@ namespace HeliosPlus.Shared.UserControls var yOffset = (Height / factor - viewSize.Height) / 2f; g.TranslateTransform(-viewSize.X + xOffset, -viewSize.Y + yOffset); - foreach (var path in _profile.Viewports) + foreach (var path in _profile.Paths) { DrawPath(g, path); } diff --git a/HeliosPlus/DisplayRepresentation.cs b/HeliosPlus/DisplayRepresentation.cs index 9bea825..8b40657 100644 --- a/HeliosPlus/DisplayRepresentation.cs +++ b/HeliosPlus/DisplayRepresentation.cs @@ -30,7 +30,7 @@ namespace HeliosPlus } } - public DisplayRepresentation(ProfileViewportTargetDisplay display) + public DisplayRepresentation(PathTarget display) { Name = display.DisplayName; Path = display.DevicePath; @@ -60,7 +60,7 @@ namespace HeliosPlus if (profile != null) { - foreach (var target in profile.Viewports.SelectMany(path => path.TargetDisplays)) + foreach (var target in profile.Paths.SelectMany(path => path.TargetDisplays)) { if (displays.All(display => display.Path != target.DevicePath)) { @@ -77,14 +77,14 @@ namespace HeliosPlus return Display.GetDisplays().FirstOrDefault(display => display.DevicePath.StartsWith(Path)); } - public ProfileViewport GetPathSource(ProfileItem profile) + public Path GetPathSource(ProfileItem profile) { - return profile.Viewports.FirstOrDefault(path => path.TargetDisplays.Any(target => target.DevicePath == Path)); + return profile.Paths.FirstOrDefault(path => path.TargetDisplays.Any(target => target.DevicePath == Path)); } - public ProfileViewportTargetDisplay GetPathTarget(ProfileItem profile) + public PathTarget GetPathTarget(ProfileItem profile) { - return profile.Viewports.SelectMany(path => path.TargetDisplays).FirstOrDefault(target => target.DevicePath == Path); + return profile.Paths.SelectMany(path => path.TargetDisplays).FirstOrDefault(target => target.DevicePath == Path); } public PathDisplayTarget GetTargetInfo() @@ -115,14 +115,14 @@ namespace HeliosPlus } } - var p = new ProfileItem {Viewports = new ProfileViewport[1]}; - p.Viewports[0] = new ProfileViewport + var p = new ProfileItem {Paths = new Path[1]}; + p.Paths[0] = new Path { Resolution = resolution, Position = new Point(), - TargetDisplays = new ProfileViewportTargetDisplay[1] + TargetDisplays = new PathTarget[1] }; - p.Viewports[0].TargetDisplays[0] = new ProfileViewportTargetDisplay {DevicePath = Path}; + p.Paths[0].TargetDisplays[0] = new PathTarget {DevicePath = Path}; if (profile != null) { @@ -130,7 +130,7 @@ namespace HeliosPlus if (targetPath != null) { - p.Viewports[0].TargetDisplays[0].SurroundTopology = targetPath.SurroundTopology; + p.Paths[0].TargetDisplays[0].SurroundTopology = targetPath.SurroundTopology; } }