2017-02-26 19:23:31 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
|
|
|
using System.Linq;
|
|
|
|
using System.Reflection;
|
|
|
|
using System.Text;
|
|
|
|
using System.Threading;
|
2018-10-20 00:23:43 +00:00
|
|
|
using System.Windows.Forms;
|
2017-02-26 19:23:31 +00:00
|
|
|
using WindowsDisplayAPI.DisplayConfig;
|
2020-04-23 08:16:16 +00:00
|
|
|
using HeliosPlus.Shared.Resources;
|
2018-10-20 00:13:40 +00:00
|
|
|
using Newtonsoft.Json;
|
2017-02-26 19:23:31 +00:00
|
|
|
using NvAPIWrapper.GPU;
|
|
|
|
using NvAPIWrapper.Mosaic;
|
|
|
|
using NvAPIWrapper.Native.Mosaic;
|
2020-05-09 13:02:07 +00:00
|
|
|
using HeliosPlus.Shared.Topology;
|
|
|
|
using System.Drawing;
|
|
|
|
using System.Drawing.Imaging;
|
2020-05-12 10:46:23 +00:00
|
|
|
using WindowsDisplayAPI;
|
|
|
|
using System.Text.RegularExpressions;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-04-23 08:16:16 +00:00
|
|
|
namespace HeliosPlus.Shared
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
|
|
|
public class Profile : IEquatable<Profile>
|
|
|
|
{
|
|
|
|
private static Profile _currentProfile;
|
2020-05-09 13:02:07 +00:00
|
|
|
private static List<Profile> _allSavedProfiles = new List<Profile>();
|
|
|
|
private ProfileIcon _profileIcon;
|
|
|
|
private Bitmap _profileBitmap;
|
2020-05-12 10:46:23 +00:00
|
|
|
private static List<Display> _availableDisplays;
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
internal static string AppDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "HeliosPlus");
|
|
|
|
|
|
|
|
|
|
|
|
#region JsonConverterBitmap
|
|
|
|
internal class CustomBitmapConverter : JsonConverter
|
|
|
|
{
|
|
|
|
public override bool CanConvert(Type objectType)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//convert from byte to bitmap (deserialize)
|
|
|
|
|
|
|
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
|
|
|
{
|
|
|
|
string image = (string)reader.Value;
|
|
|
|
|
|
|
|
byte[] byteBuffer = Convert.FromBase64String(image);
|
|
|
|
MemoryStream memoryStream = new MemoryStream(byteBuffer);
|
|
|
|
memoryStream.Position = 0;
|
|
|
|
|
|
|
|
return (Bitmap)Bitmap.FromStream(memoryStream);
|
|
|
|
}
|
|
|
|
|
|
|
|
//convert bitmap to byte (serialize)
|
|
|
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
|
|
|
{
|
|
|
|
Bitmap bitmap = (Bitmap)value;
|
|
|
|
|
|
|
|
ImageConverter converter = new ImageConverter();
|
|
|
|
writer.WriteValue((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
|
|
|
|
}
|
|
|
|
|
|
|
|
public static System.Drawing.Imaging.ImageFormat GetImageFormat(Bitmap bitmap)
|
|
|
|
{
|
|
|
|
ImageFormat img = bitmap.RawFormat;
|
|
|
|
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Jpeg;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Bmp;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Png))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Png;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Emf))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Emf;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Exif))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Exif;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Gif))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Gif;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Icon))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Icon;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.MemoryBmp;
|
|
|
|
if (img.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Tiff;
|
|
|
|
else
|
|
|
|
return System.Drawing.Imaging.ImageFormat.Wmf;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
2017-02-26 19:23:31 +00:00
|
|
|
static Profile()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
NvAPIWrapper.NVIDIA.Initialize();
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
// ignored
|
|
|
|
}
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
public static Version Version = new Version(2, 1);
|
|
|
|
|
2018-10-23 23:34:49 +00:00
|
|
|
public string Id { get; set; } = Guid.NewGuid().ToString("B");
|
|
|
|
|
2018-10-20 00:13:40 +00:00
|
|
|
[JsonIgnore]
|
2017-02-26 19:23:31 +00:00
|
|
|
public bool IsActive
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return _currentProfile.Equals(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-20 00:13:40 +00:00
|
|
|
[JsonIgnore]
|
2017-02-26 19:23:31 +00:00
|
|
|
public bool IsPossible
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
|
|
|
|
// Firstly check which displays are attached to this computer
|
|
|
|
_availableDisplays = Display.GetDisplays().ToList();
|
|
|
|
// DevicePath "\\\\?\\DISPLAY#DELD065#5&38860457&0&UID4609#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}"
|
|
|
|
List<string> availableDevicePath = new List<string>();
|
|
|
|
foreach (Display aDisplay in _availableDisplays)
|
|
|
|
{
|
|
|
|
// Grab the shorter device path from the display Api
|
|
|
|
Regex devicePathRegex = new Regex(@"^(.+?)#\{", RegexOptions.IgnoreCase);
|
|
|
|
Match devicePathMatches = devicePathRegex.Match(aDisplay.DevicePath);
|
|
|
|
if (devicePathMatches.Success)
|
|
|
|
{
|
|
|
|
availableDevicePath.Add(devicePathMatches.Groups[1].Value.ToString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (availableDevicePath.Count > 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
int profileDisplaysCount = 0;
|
|
|
|
int profileDisplaysFoundCount = 0;
|
|
|
|
// Then go through the displays in the profile and check they're live
|
|
|
|
foreach (ProfileViewport profileViewport in Viewports)
|
|
|
|
{
|
|
|
|
foreach (ProfileViewportTargetDisplay profileViewportTargetDisplay in profileViewport.TargetDisplays)
|
|
|
|
{
|
|
|
|
profileDisplaysCount++;
|
|
|
|
if (profileViewportTargetDisplay.DevicePath.Equals(availableDevicePath));
|
|
|
|
profileDisplaysFoundCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (profileDisplaysCount == profileDisplaysFoundCount)
|
|
|
|
{
|
|
|
|
// If we found all our profile displays in the available displays!
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// This should include the ones not currently enabled.
|
|
|
|
var displayAdapters = DisplayAdapter.GetDisplayAdapters().ToArray();
|
|
|
|
var displays = Display.GetDisplays().ToArray();
|
|
|
|
|
|
|
|
|
|
|
|
var physicalGPUs = PhysicalGPU.GetPhysicalGPUs();
|
|
|
|
var displayDevices = physicalGPUs[0].GetDisplayDevices().ToArray();
|
|
|
|
return true;
|
|
|
|
|
|
|
|
/*var surroundTopologies =
|
|
|
|
Viewports.SelectMany(path => path.TargetDisplays)
|
2017-02-26 19:23:31 +00:00
|
|
|
.Select(target => target.SurroundTopology)
|
|
|
|
.Where(topology => topology != null).ToArray();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
if (surroundTopologies.Length > 0)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Not working quite well yet
|
|
|
|
//var status =
|
|
|
|
// GridTopology.ValidateGridTopologies(
|
|
|
|
// SurroundTopologies.Select(topology => topology.ToGridTopology()).ToArray(),
|
|
|
|
// SetDisplayTopologyFlag.MaximizePerformance);
|
|
|
|
//return status.All(topologyStatus => topologyStatus.Errors == DisplayCapacityProblem.NoProblem);
|
|
|
|
|
|
|
|
// Least we can do is to check for the availability of all display devices
|
|
|
|
var displayDevices =
|
|
|
|
PhysicalGPU.GetPhysicalGPUs()
|
|
|
|
.SelectMany(gpu => gpu.GetDisplayDevices())
|
|
|
|
.Select(device => device.DisplayId);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
if (!
|
|
|
|
surroundTopologies.All(
|
2018-10-20 00:27:25 +00:00
|
|
|
topology =>
|
|
|
|
topology.Displays.All(display => displayDevices.Contains(display.DisplayId))))
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
return false;
|
2018-10-20 00:27:25 +00:00
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
|
|
|
// And to see if one path have two surround targets
|
2020-05-12 10:46:23 +00:00
|
|
|
if (Viewports.Any(path => path.TargetDisplays.Count(target => target.SurroundTopology != null) > 1))
|
2018-10-20 00:27:25 +00:00
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
return false;
|
2018-10-20 00:27:25 +00:00
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
// ignore
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
return true;*/
|
2017-02-26 19:23:31 +00:00
|
|
|
//return PathInfo.ValidatePathInfos(Paths.Select(path => path.ToPathInfo()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
public ProfileViewport[] Viewports { get; set; } = new ProfileViewport[0];
|
2017-02-26 19:23:31 +00:00
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
public static string SavedProfilesFilePath
|
2018-10-20 00:13:40 +00:00
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
get => System.IO.Path.Combine(AppDataPath, $"Profiles\\DisplayProfiles_{Version.ToString(2)}.json");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static string SavedProfilesPath
|
|
|
|
{
|
|
|
|
get => System.IO.Path.Combine(AppDataPath, $"Profiles");
|
2020-05-09 13:02:07 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static List<Profile> AllSavedProfiles
|
|
|
|
{
|
|
|
|
get => _allSavedProfiles;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Profile CurrentProfile
|
|
|
|
{
|
|
|
|
get => _currentProfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public ProfileIcon ProfileIcon
|
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_profileIcon != null)
|
|
|
|
return _profileIcon;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_profileIcon = new ProfileIcon(this);
|
|
|
|
return _profileIcon;
|
|
|
|
}
|
|
|
|
}
|
2020-05-09 13:02:07 +00:00
|
|
|
set
|
|
|
|
{
|
|
|
|
_profileIcon = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
public string SavedProfileCacheFilename { get; set; }
|
|
|
|
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
[JsonConverter(typeof(CustomBitmapConverter))]
|
|
|
|
public Bitmap ProfileBitmap
|
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_profileBitmap != null)
|
|
|
|
return _profileBitmap;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_profileBitmap = this.ProfileIcon.ToBitmap(128, 128);
|
|
|
|
return _profileBitmap;
|
|
|
|
}
|
|
|
|
}
|
2020-05-09 13:02:07 +00:00
|
|
|
set
|
|
|
|
{
|
|
|
|
_profileBitmap = value;
|
|
|
|
}
|
|
|
|
|
2018-10-20 00:13:40 +00:00
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public bool Equals(Profile other)
|
|
|
|
{
|
2020-05-11 11:11:26 +00:00
|
|
|
//if the other profile points to null, it's not equal
|
2018-10-20 00:27:25 +00:00
|
|
|
if (ReferenceEquals(null, other))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-11 11:11:26 +00:00
|
|
|
//if the other profile is the same object, it's equal
|
2018-10-20 00:27:25 +00:00
|
|
|
if (ReferenceEquals(this, other))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-05-11 11:11:26 +00:00
|
|
|
//return Paths.All(path => other.Paths.Contains(path));
|
2020-05-12 10:46:23 +00:00
|
|
|
if (Viewports.Length != other.Viewports.Length)
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
int thisToOtherViewportCount = 0;
|
|
|
|
int otherToThisViewportCount = 0;
|
2020-05-11 11:11:26 +00:00
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
foreach (ProfileViewport myProfileViewport in Viewports)
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
foreach (ProfileViewport otherProfileViewport in other.Viewports)
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
if (myProfileViewport.Equals(otherProfileViewport))
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
thisToOtherViewportCount++;
|
2020-05-11 11:11:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
foreach (ProfileViewport otherProfileViewport in other.Viewports)
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
foreach (ProfileViewport myProfileViewport in Viewports)
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
if (myProfileViewport.Equals(otherProfileViewport))
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
otherToThisViewportCount++;
|
2020-05-11 11:11:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
if (thisToOtherViewportCount == otherToThisViewportCount)
|
2020-05-11 11:11:26 +00:00
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
public static IEnumerable<Profile> LoadAllProfiles()
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
|
|
|
|
if (File.Exists(SavedProfilesFilePath))
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
var json = File.ReadAllText(SavedProfilesFilePath, Encoding.Unicode);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
if (!string.IsNullOrWhiteSpace(json))
|
|
|
|
{
|
|
|
|
List<Profile> profiles = new List<Profile>();
|
|
|
|
try
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
//var profiles = JsonConvert.DeserializeObject<Profile[]>(json, new JsonSerializerSettings
|
2020-05-10 10:47:18 +00:00
|
|
|
profiles = JsonConvert.DeserializeObject<List<Profile>>(json, new JsonSerializerSettings
|
2018-10-23 23:34:49 +00:00
|
|
|
{
|
|
|
|
MissingMemberHandling = MissingMemberHandling.Ignore,
|
|
|
|
NullValueHandling = NullValueHandling.Ignore,
|
|
|
|
DefaultValueHandling = DefaultValueHandling.Include,
|
|
|
|
TypeNameHandling = TypeNameHandling.Auto
|
|
|
|
});
|
2020-05-10 10:47:18 +00:00
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
// ignored
|
|
|
|
Console.WriteLine("Unable to deserialize profile: " + ex.Message);
|
|
|
|
}
|
2018-10-23 23:34:49 +00:00
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
//Convert array to list
|
|
|
|
//List<Profile> profilesList = profiles.ToList<Profile>();
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
// Find which entry is being used now, and save that info in a class variable
|
|
|
|
Profile myCurrentProfile = new Profile
|
|
|
|
{
|
|
|
|
Name = "Current Display Profile",
|
2020-05-12 10:46:23 +00:00
|
|
|
Viewports = PathInfo.GetActivePaths().Select(info => new ProfileViewport(info)).ToArray()
|
2020-05-10 10:47:18 +00:00
|
|
|
};
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
_currentProfile = myCurrentProfile;
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
foreach (Profile loadedProfile in profiles)
|
|
|
|
{
|
|
|
|
// Save a profile Icon to the profile
|
|
|
|
loadedProfile.ProfileIcon = new ProfileIcon(loadedProfile);
|
|
|
|
loadedProfile.ProfileBitmap = loadedProfile.ProfileIcon.ToBitmap(128,128);
|
2020-05-09 13:02:07 +00:00
|
|
|
|
2020-05-11 11:11:26 +00:00
|
|
|
if (loadedProfile.Equals(myCurrentProfile)) {
|
2020-05-10 10:47:18 +00:00
|
|
|
_currentProfile = loadedProfile;
|
2018-10-23 23:34:49 +00:00
|
|
|
}
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
2020-05-10 10:47:18 +00:00
|
|
|
|
|
|
|
_allSavedProfiles = profiles;
|
|
|
|
|
|
|
|
return _allSavedProfiles;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
// If we get here, then we don't have any profiles saved!
|
|
|
|
// So we gotta start from scratch
|
|
|
|
// Create a new profile based on our current display settings
|
2017-02-26 19:23:31 +00:00
|
|
|
_currentProfile = new Profile
|
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
Name = "Current Display Profile",
|
2020-05-12 10:46:23 +00:00
|
|
|
Viewports = PathInfo.GetActivePaths().Select(info => new ProfileViewport(info)).ToArray()
|
2017-02-26 19:23:31 +00:00
|
|
|
};
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
// Save a profile Icon to the profile
|
|
|
|
_currentProfile.ProfileIcon = new ProfileIcon(_currentProfile);
|
|
|
|
_currentProfile.ProfileBitmap = _currentProfile.ProfileIcon.ToBitmap(128, 128);
|
|
|
|
|
|
|
|
// Create a new empty list of all our display profiles as we don't have any saved!
|
|
|
|
_allSavedProfiles = new List<Profile>();
|
|
|
|
|
|
|
|
return _allSavedProfiles;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
public static bool operator ==(Profile left, Profile right)
|
|
|
|
{
|
2018-10-20 00:17:32 +00:00
|
|
|
return Equals(left, right) || left?.Equals(right) == true;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public static bool operator !=(Profile left, Profile right)
|
|
|
|
{
|
2018-10-20 00:17:32 +00:00
|
|
|
return !(left == right);
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
public static bool IsValidName(string testName)
|
|
|
|
{
|
|
|
|
foreach (Profile loadedProfile in _allSavedProfiles)
|
|
|
|
{
|
|
|
|
if (loadedProfile.Name == testName)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool IsValidId(string testId)
|
|
|
|
{
|
|
|
|
foreach (Profile loadedProfile in _allSavedProfiles)
|
|
|
|
{
|
|
|
|
if (loadedProfile.Id == testId)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
public static void RefreshActiveStatus()
|
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
//_currentProfile = null;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
|
2020-05-09 13:02:07 +00:00
|
|
|
public static bool SaveAllProfiles()
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
if (SaveAllProfiles(_allSavedProfiles))
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static bool SaveAllProfiles(List<Profile> profilesToSave)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (!Directory.Exists(SavedProfilesPath))
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
try
|
2018-10-23 23:34:49 +00:00
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
Directory.CreateDirectory(SavedProfilesPath);
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
Console.WriteLine("Unable to create Profile folder " + SavedProfilesPath + ": " + ex.Message);
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-09 13:02:07 +00:00
|
|
|
|
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
// Now we loop over the profiles and save their images for later
|
|
|
|
foreach (Profile profileToSave in profilesToSave)
|
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
profileToSave.SaveProfileImageToCache();
|
2020-05-10 10:47:18 +00:00
|
|
|
}
|
2020-05-09 13:02:07 +00:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
var json = JsonConvert.SerializeObject(profilesToSave, Formatting.Indented, new JsonSerializerSettings
|
|
|
|
{
|
|
|
|
NullValueHandling = NullValueHandling.Include,
|
|
|
|
DefaultValueHandling = DefaultValueHandling.Populate,
|
|
|
|
TypeNameHandling = TypeNameHandling.Auto
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(json))
|
|
|
|
{
|
2020-05-10 10:47:18 +00:00
|
|
|
var dir = System.IO.Path.GetDirectoryName(SavedProfilesFilePath);
|
2020-05-09 13:02:07 +00:00
|
|
|
|
|
|
|
if (dir != null)
|
|
|
|
{
|
|
|
|
Directory.CreateDirectory(dir);
|
2020-05-10 10:47:18 +00:00
|
|
|
File.WriteAllText(SavedProfilesFilePath, json, Encoding.Unicode);
|
2020-05-09 13:02:07 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2020-05-09 13:02:07 +00:00
|
|
|
Console.WriteLine("Unable to serialize profile: " + ex.Message);
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
// Overwrite the list of saved profiles as the new lot we received.
|
2020-05-09 13:02:07 +00:00
|
|
|
_allSavedProfiles = profilesToSave;
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public override bool Equals(object obj)
|
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
if (ReferenceEquals(null, obj))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ReferenceEquals(this, obj))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (obj.GetType() != GetType())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
return Equals((Profile) obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public override int GetHashCode()
|
|
|
|
{
|
|
|
|
unchecked
|
|
|
|
{
|
2020-05-12 10:46:23 +00:00
|
|
|
return (Viewports?.GetHashCode() ?? 0) * 397;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <inheritdoc />
|
|
|
|
public override string ToString()
|
|
|
|
{
|
|
|
|
return (Name ?? Language.UN_TITLED_PROFILE) + (IsActive ? " " + Language._Active_ : "");
|
|
|
|
}
|
|
|
|
|
2020-05-10 10:47:18 +00:00
|
|
|
private static string GetValidFilename(string uncheckedFilename)
|
|
|
|
{
|
|
|
|
string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
|
|
|
|
foreach (char c in invalid)
|
|
|
|
{
|
|
|
|
uncheckedFilename = uncheckedFilename.Replace(c.ToString(), "");
|
|
|
|
}
|
|
|
|
return uncheckedFilename;
|
|
|
|
}
|
|
|
|
|
2020-05-12 10:46:23 +00:00
|
|
|
public bool SaveProfileImageToCache()
|
|
|
|
{
|
|
|
|
this.SavedProfileCacheFilename = Path.Combine(SavedProfilesPath, GetValidFilename(String.Concat(this.Name + @".png")));
|
|
|
|
try
|
|
|
|
{
|
|
|
|
this.ProfileBitmap.Save(this.SavedProfileCacheFilename, ImageFormat.Png);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
Console.WriteLine("Unable to create profile image in cache using " + this.SavedProfileCacheFilename + ": " + ex.Message);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
public bool Apply()
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
Thread.Sleep(2000);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
var surroundTopologies =
|
2020-05-12 10:46:23 +00:00
|
|
|
Viewports.SelectMany(path => path.TargetDisplays)
|
2017-02-26 19:23:31 +00:00
|
|
|
.Select(target => target.SurroundTopology)
|
|
|
|
.Where(topology => topology != null)
|
|
|
|
.Select(topology => topology.ToGridTopology())
|
|
|
|
.ToArray();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
if (surroundTopologies.Length == 0)
|
|
|
|
{
|
|
|
|
var currentTopologies = GridTopology.GetGridTopologies();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
|
|
|
if (currentTopologies.Any(topology => topology.Rows * topology.Columns > 1))
|
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
surroundTopologies =
|
|
|
|
GridTopology.GetGridTopologies()
|
|
|
|
.SelectMany(topology => topology.Displays)
|
|
|
|
.Select(displays => new GridTopology(1, 1, new[] {displays}))
|
|
|
|
.ToArray();
|
2018-10-20 00:27:25 +00:00
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
if (surroundTopologies.Length > 0)
|
2018-10-20 00:27:25 +00:00
|
|
|
{
|
2017-02-26 19:23:31 +00:00
|
|
|
GridTopology.SetGridTopologies(surroundTopologies, SetDisplayTopologyFlag.MaximizePerformance);
|
2018-10-20 00:27:25 +00:00
|
|
|
}
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
|
|
|
// ignored
|
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2018-10-20 00:23:43 +00:00
|
|
|
Thread.Sleep(18000);
|
2020-05-12 10:46:23 +00:00
|
|
|
var pathInfos = Viewports.Select(path => path.ToPathInfo()).Where(info => info != null).ToArray();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2018-10-20 00:23:43 +00:00
|
|
|
if (!pathInfos.Any())
|
|
|
|
{
|
2018-10-20 00:27:25 +00:00
|
|
|
throw new InvalidOperationException(
|
|
|
|
@"Display configuration changed since this profile is created. Please re-create this profile.");
|
2018-10-20 00:23:43 +00:00
|
|
|
}
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2018-10-20 00:23:43 +00:00
|
|
|
PathInfo.ApplyPathInfos(pathInfos, true, true, true);
|
|
|
|
Thread.Sleep(10000);
|
2017-02-26 19:23:31 +00:00
|
|
|
RefreshActiveStatus();
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
2018-10-20 00:23:43 +00:00
|
|
|
catch (Exception ex)
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
|
|
|
RefreshActiveStatus();
|
2018-10-20 00:23:43 +00:00
|
|
|
MessageBox.Show(ex.Message, @"Profile", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2017-02-26 19:23:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public Profile Clone()
|
|
|
|
{
|
2018-10-20 00:13:40 +00:00
|
|
|
try
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2018-10-20 00:13:40 +00:00
|
|
|
var serialized = JsonConvert.SerializeObject(this);
|
2018-10-20 00:27:25 +00:00
|
|
|
|
2018-10-23 23:52:18 +00:00
|
|
|
var cloned = JsonConvert.DeserializeObject<Profile>(serialized);
|
|
|
|
cloned.Id = Guid.NewGuid().ToString("B");
|
|
|
|
|
|
|
|
return cloned;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
2018-10-20 00:13:40 +00:00
|
|
|
catch
|
2017-02-26 19:23:31 +00:00
|
|
|
{
|
2018-10-20 00:13:40 +00:00
|
|
|
return null;
|
2017-02-26 19:23:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|