diff --git a/HeliosPlus.Shared/ProfileRepository.cs b/HeliosPlus.Shared/ProfileRepository.cs
index 30d9367..4602232 100644
--- a/HeliosPlus.Shared/ProfileRepository.cs
+++ b/HeliosPlus.Shared/ProfileRepository.cs
@@ -576,7 +576,7 @@ namespace HeliosPlus.Shared
// Now lets start by changing the display topology
Task applyProfileTopologyTask = Task.Run(() =>
{
- Console.WriteLine("ShortcutRepository/SaveShortcutIconToCache : Applying Profile Topology " + profile.Name);
+ Console.WriteLine("ProfileRepository/SaveShortcutIconToCache : Applying Profile Topology " + profile.Name);
ApplyTopology(profile);
});
applyProfileTopologyTask.Wait();
@@ -584,7 +584,7 @@ namespace HeliosPlus.Shared
// And then change the path information
Task applyProfilePathInfoTask = Task.Run(() =>
{
- Console.WriteLine("ShortcutRepository/SaveShortcutIconToCache : Applying Profile Path " + profile.Name);
+ Console.WriteLine("ProfileRepository/SaveShortcutIconToCache : Applying Profile Path " + profile.Name);
ApplyPathInfo(profile);
});
applyProfilePathInfoTask.Wait();
@@ -593,16 +593,17 @@ namespace HeliosPlus.Shared
}
catch (Exception ex)
{
- Console.WriteLine($"ShortcutRepository/ApplyTopology exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
+ Console.WriteLine($"ProfileRepository/ApplyTopology exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
return false;
}
}
- private static void ApplyTopology(ProfileItem profile)
+ public static bool ApplyTopology(ProfileItem profile)
{
- Debug.Print("ShortcutRepository.ApplyTopology()");
- if (profile == null)
- return;
+ Debug.Print("ProfileRepository.ApplyTopology()");
+
+ if (!(profile is ProfileItem))
+ return false;
try
{
@@ -615,6 +616,7 @@ namespace HeliosPlus.Shared
if (surroundTopologies.Length == 0)
{
+ // This profile does not use NVIDIA Surround
var currentTopologies = GridTopology.GetGridTopologies();
if (currentTopologies.Any(topology => topology.Rows * topology.Columns > 1))
@@ -625,34 +627,39 @@ namespace HeliosPlus.Shared
.Select(displays => new GridTopology(1, 1, new[] { displays }))
.ToArray();
}
- }
-
- if (surroundTopologies.Length > 0)
+ } else if (surroundTopologies.Length > 0)
{
+ // This profile is an NVIDIA Surround profile
GridTopology.SetGridTopologies(surroundTopologies, SetDisplayTopologyFlag.MaximizePerformance);
}
+
+ return true;
}
catch (Exception ex)
{
- Console.WriteLine($"ShortcutRepository/ApplyTopology exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
- // ignored
+ Console.WriteLine($"ProfileRepository/ApplyTopology exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
+ return false;
}
}
- private static void ApplyPathInfo(ProfileItem profile)
+ public static bool ApplyPathInfo(ProfileItem profile)
{
- Debug.Print("ShortcutRepository.ApplyPathInfo()");
- if (profile == null)
- return;
+ Debug.Print("ProfileRepository.ApplyPathInfo()");
+ if (!(profile is ProfileItem))
+ return false;
- if (!profile.IsPossible)
+ try
{
- throw new InvalidOperationException(
- $"ShortcutRepository/ApplyPathInfo exception: Problem applying the '{profile.Name}' Display Profile! The display configuration changed since this profile is created. Please re-create this profile.");
+ var pathInfos = profile.Viewports.Select(viewport => viewport.ToPathInfo()).Where(info => info != null).ToArray();
+ WindowsDisplayAPI.DisplayConfig.PathInfo.ApplyPathInfos(pathInfos, true, true, true);
+ return true;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"ProfileRepository/ApplyPathInfo exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
+ return false;
}
- var pathInfos = profile.Viewports.Select(viewport => viewport.ToPathInfo()).Where(info => info != null).ToArray();
- WindowsDisplayAPI.DisplayConfig.PathInfo.ApplyPathInfos(pathInfos, true, true, true);
}
public static bool IsValidFilename(string testName)
diff --git a/HeliosPlus/HeliosPlus.csproj b/HeliosPlus/HeliosPlus.csproj
index 8580f36..62f724b 100644
--- a/HeliosPlus/HeliosPlus.csproj
+++ b/HeliosPlus/HeliosPlus.csproj
@@ -80,8 +80,15 @@
+
+
+ Form
+
+
+ ApplyingProfileForm.cs
+
@@ -139,6 +146,9 @@
Language.Designer.cs
Designer
+
+ ApplyingProfileForm.cs
+
MainForm.cs
Designer
diff --git a/HeliosPlus/Program.cs b/HeliosPlus/Program.cs
index fa0268f..2f16e0d 100644
--- a/HeliosPlus/Program.cs
+++ b/HeliosPlus/Program.cs
@@ -19,6 +19,7 @@ using HeliosPlus.UIForms;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;
using System.Drawing;
+using System.Diagnostics.Contracts;
namespace HeliosPlus {
public enum SupportedProgramMode
@@ -329,14 +330,74 @@ namespace HeliosPlus {
return true;
}
-/* public static string GetValidFilename(string uncheckedFilename)
+ /* public 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;
+ }*/
+
+ // ApplyProfile lives here so that the UI works.
+ public static bool ApplyProfile(ProfileItem profile)
{
- string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
- foreach (char c in invalid)
+ // If we're already on the wanted profile then no need to change!
+ if (ProfileRepository.IsActiveProfile(profile))
+ return true;
+
+ // We need to check if the profile is valid
+ if (!profile.IsPossible)
+ return false;
+
+ try
{
- uncheckedFilename = uncheckedFilename.Replace(c.ToString(), "");
+ // Set up the UI forms to show
+ ApplyingProfileForm timeoutForm = new ApplyingProfileForm(3, 0, $"Applying Profile '{profile.Name}'", $"Press ESC to timeout");
+ ApplyingProfileForm topologyForm = new ApplyingProfileForm(0, 30, $"Applying Profile '{profile.Name}' Topology");
+ ApplyingProfileForm pathInfoForm = new ApplyingProfileForm(0, 30, $"Applying Profile '{profile.Name}' Path");
+
+ topologyForm.ShowDialog();
+ // Now lets start by changing the display topology
+ Task applyTopologyTask = Task.Run(() =>
+ {
+ Console.WriteLine("ProfileRepository/SaveShortcutIconToCache : Applying Profile Topology " + profile.Name);
+ ProfileRepository.ApplyTopology(profile);
+ });
+ applyTopologyTask.Wait();
+ topologyForm.Close();
+
+ if (applyTopologyTask.IsCompleted)
+ {
+ pathInfoForm.ShowDialog();
+ Task applyPathInfoTask = Task.Run(() => {
+ Console.WriteLine("ProfileRepository/SaveShortcutIconToCache : Applying Profile Path " + profile.Name);
+ ProfileRepository.ApplyPathInfo(profile);
+ });
+
+ applyPathInfoTask.Wait();
+ pathInfoForm.Close();
+ // And then change the path information
+ if (applyPathInfoTask.IsCompleted)
+ return true;
+
+
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+
+
}
- return uncheckedFilename;
- }*/
+ catch (Exception ex)
+ {
+ Console.WriteLine($"ProfileRepository/ApplyTopology exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
+ return false;
+ }
+ }
+
}
}
\ No newline at end of file
diff --git a/HeliosPlus/ProgressReporter.cs b/HeliosPlus/ProgressReporter.cs
new file mode 100644
index 0000000..a4b8320
--- /dev/null
+++ b/HeliosPlus/ProgressReporter.cs
@@ -0,0 +1,160 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace HeliosPlus
+{
+ using System;
+ using System.Threading;
+ using System.Threading.Tasks;
+
+ ///
+ /// A class used by Tasks to report progress or completion updates back to the UI.
+ ///
+ public sealed class ProgressReporter
+ {
+ ///
+ /// The underlying scheduler for the UI's synchronization context.
+ ///
+ private readonly TaskScheduler scheduler;
+
+ ///
+ /// Initializes a new instance of the class.
+ /// This should be run on a UI thread.
+ ///
+ public ProgressReporter()
+ {
+ this.scheduler = TaskScheduler.FromCurrentSynchronizationContext();
+ }
+
+ ///
+ /// Gets the task scheduler which executes tasks on the UI thread.
+ ///
+ public TaskScheduler Scheduler
+ {
+ get { return this.scheduler; }
+ }
+
+ ///
+ /// Reports the progress to the UI thread. This method should be called from the task.
+ /// Note that the progress update is asynchronous with respect to the reporting Task.
+ /// For a synchronous progress update, wait on the returned .
+ ///
+ /// The action to perform in the context of the UI thread.
+ /// Note that this action is run asynchronously on the UI thread.
+ /// The task queued to the UI thread.
+ public Task ReportProgressAsync(Action action)
+ {
+ return Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, this.scheduler);
+ }
+
+ ///
+ /// Reports the progress to the UI thread, and waits for the UI thread to process
+ /// the update before returning. This method should be called from the task.
+ ///
+ /// The action to perform in the context of the UI thread.
+ public void ReportProgress(Action action)
+ {
+ this.ReportProgressAsync(action).Wait();
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task finishes execution,
+ /// whether it finishes with success, failiure, or cancellation.
+ ///
+ /// The task to monitor for completion.
+ /// The action to take when the task has completed, in the context of the UI thread.
+ /// The continuation created to handle completion. This is normally ignored.
+ public Task RegisterContinuation(Task task, Action action)
+ {
+ return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.None, this.scheduler);
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task finishes execution,
+ /// whether it finishes with success, failiure, or cancellation.
+ ///
+ /// The type of the task result.
+ /// The task to monitor for completion.
+ /// The action to take when the task has completed, in the context of the UI thread.
+ /// The continuation created to handle completion. This is normally ignored.
+ public Task RegisterContinuation(Task task, Action action)
+ {
+ return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.None, this.scheduler);
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task successfully finishes execution.
+ ///
+ /// The task to monitor for successful completion.
+ /// The action to take when the task has successfully completed, in the context of the UI thread.
+ /// The continuation created to handle successful completion. This is normally ignored.
+ public Task RegisterSucceededHandler(Task task, Action action)
+ {
+ return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this.scheduler);
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task successfully finishes execution
+ /// and returns a result.
+ ///
+ /// The type of the task result.
+ /// The task to monitor for successful completion.
+ /// The action to take when the task has successfully completed, in the context of the UI thread.
+ /// The argument to the action is the return value of the task.
+ /// The continuation created to handle successful completion. This is normally ignored.
+ public Task RegisterSucceededHandler(Task task, Action action)
+ {
+ return task.ContinueWith(t => action(t.Result), CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, this.Scheduler);
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task becomes faulted.
+ ///
+ /// The task to monitor for faulting.
+ /// The action to take when the task has faulted, in the context of the UI thread.
+ /// The continuation created to handle faulting. This is normally ignored.
+ public Task RegisterFaultedHandler(Task task, Action action)
+ {
+ return task.ContinueWith(t => action(t.Exception), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, this.Scheduler);
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task becomes faulted.
+ ///
+ /// The type of the task result.
+ /// The task to monitor for faulting.
+ /// The action to take when the task has faulted, in the context of the UI thread.
+ /// The continuation created to handle faulting. This is normally ignored.
+ public Task RegisterFaultedHandler(Task task, Action action)
+ {
+ return task.ContinueWith(t => action(t.Exception), CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, this.Scheduler);
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task is cancelled.
+ ///
+ /// The task to monitor for cancellation.
+ /// The action to take when the task is cancelled, in the context of the UI thread.
+ /// The continuation created to handle cancellation. This is normally ignored.
+ public Task RegisterCancelledHandler(Task task, Action action)
+ {
+ return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);
+ }
+
+ ///
+ /// Registers a UI thread handler for when the specified task is cancelled.
+ ///
+ /// The type of the task result.
+ /// The task to monitor for cancellation.
+ /// The action to take when the task is cancelled, in the context of the UI thread.
+ /// The continuation created to handle cancellation. This is normally ignored.
+ public Task RegisterCancelledHandler(Task task, Action action)
+ {
+ return task.ContinueWith(_ => action(), CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, this.Scheduler);
+ }
+ }
+}
diff --git a/HeliosPlus/ShortcutRepository.cs b/HeliosPlus/ShortcutRepository.cs
index 76c2dfd..d1c027d 100644
--- a/HeliosPlus/ShortcutRepository.cs
+++ b/HeliosPlus/ShortcutRepository.cs
@@ -484,7 +484,8 @@ namespace HeliosPlus
IPCService.GetInstance().Status = InstanceStatus.Busy;
// Apply the Profile!
- if (!ProfileRepository.ApplyProfile(shortcutToUse.ProfileToUse))
+ //if (!ProfileRepository.ApplyProfile(shortcutToUse.ProfileToUse))
+ if (!Program.ApplyProfile(shortcutToUse.ProfileToUse))
{
throw new Exception(Language.Cannot_change_active_profile);
}
@@ -694,7 +695,8 @@ namespace HeliosPlus
// Change back to the original profile if it is different
if (!ProfileRepository.IsActiveProfile(rollbackProfile))
{
- if (!ProfileRepository.ApplyProfile(rollbackProfile))
+ //if (!ProfileRepository.ApplyProfile(rollbackProfile))
+ if (!Program.ApplyProfile(rollbackProfile))
{
throw new Exception(Language.Cannot_change_active_profile);
}
diff --git a/HeliosPlus/UIForms/ApplyingChangesForm.Designer.cs b/HeliosPlus/UIForms/ApplyingChangesForm.Designer.cs
index 9c20f46..03d11c4 100644
--- a/HeliosPlus/UIForms/ApplyingChangesForm.Designer.cs
+++ b/HeliosPlus/UIForms/ApplyingChangesForm.Designer.cs
@@ -37,7 +37,7 @@ namespace HeliosPlus.UIForms
this.lbl_sub_message = new System.Windows.Forms.Label();
this.lbl_message = new System.Windows.Forms.Label();
this.progressBar = new CircularProgressBar.CircularProgressBar();
- this.t_start = new System.Windows.Forms.Timer(this.components);
+ this.t_cancellation = new System.Windows.Forms.Timer(this.components);
this.t_countdown = new System.Windows.Forms.Timer(this.components);
this.progressPanel.SuspendLayout();
this.SuspendLayout();
@@ -106,8 +106,8 @@ namespace HeliosPlus.UIForms
//
// t_start
//
- this.t_start.Interval = 1000;
- this.t_start.Tick += new System.EventHandler(this.t_start_Tick);
+ this.t_cancellation.Interval = 1000;
+ this.t_cancellation.Tick += new System.EventHandler(this.t_cancellation_Tick);
//
// t_countdown
//
@@ -150,7 +150,7 @@ namespace HeliosPlus.UIForms
private Panel progressPanel;
private CircularProgressBar.CircularProgressBar progressBar;
private System.Windows.Forms.Label lbl_message;
- private System.Windows.Forms.Timer t_start;
+ private System.Windows.Forms.Timer t_cancellation;
private System.Windows.Forms.Timer t_countdown;
private Label lbl_sub_message;
}
diff --git a/HeliosPlus/UIForms/ApplyingChangesForm.cs b/HeliosPlus/UIForms/ApplyingChangesForm.cs
index fdb360a..2b0da67 100644
--- a/HeliosPlus/UIForms/ApplyingChangesForm.cs
+++ b/HeliosPlus/UIForms/ApplyingChangesForm.cs
@@ -79,9 +79,9 @@ namespace HeliosPlus.UIForms
return base.ProcessCmdKey(ref msg, keyData);
}
- if (t_start.Enabled)
+ if (t_cancellation.Enabled)
{
- t_start.Stop();
+ t_cancellation.Stop();
t_countdown.Stop();
DialogResult = DialogResult.Cancel;
Close();
@@ -133,14 +133,14 @@ namespace HeliosPlus.UIForms
private void DoTimeout()
{
- lbl_message.Text = CancellationMessage;
- lbl_sub_message.Text = CancellationSubMessage;
- progressBar.ProgressColor = Color.DodgerBlue;
if (_startCounter > 0)
{
+ lbl_message.Text = CancellationMessage;
+ lbl_sub_message.Text = CancellationSubMessage;
+ progressBar.ProgressColor = Color.DodgerBlue;
progressBar.Text = (progressBar.Value = progressBar.Maximum = _startCounter).ToString();
- t_start.Start();
+ t_cancellation.Start();
}
else
{
@@ -241,11 +241,11 @@ namespace HeliosPlus.UIForms
Reposition();
}
- private void t_start_Tick(object sender, EventArgs e)
+ private void t_cancellation_Tick(object sender, EventArgs e)
{
if (_startCounter < 0)
{
- t_start.Stop();
+ t_cancellation.Stop();
DoJob();
return;
diff --git a/HeliosPlus/UIForms/ApplyingProfileForm.Designer.cs b/HeliosPlus/UIForms/ApplyingProfileForm.Designer.cs
new file mode 100644
index 0000000..8decd29
--- /dev/null
+++ b/HeliosPlus/UIForms/ApplyingProfileForm.Designer.cs
@@ -0,0 +1,149 @@
+namespace HeliosPlus.UIForms
+{
+ partial class ApplyingProfileForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.progressPanel = new System.Windows.Forms.Panel();
+ this.lbl_sub_message = new System.Windows.Forms.Label();
+ this.progressBar = new CircularProgressBar.CircularProgressBar();
+ this.lbl_message = new System.Windows.Forms.Label();
+ this.t_countdown = new System.Windows.Forms.Timer(this.components);
+ this.t_cancellation = new System.Windows.Forms.Timer(this.components);
+ this.progressPanel.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // progressPanel
+ //
+ this.progressPanel.Anchor = System.Windows.Forms.AnchorStyles.None;
+ this.progressPanel.Controls.Add(this.lbl_sub_message);
+ this.progressPanel.Controls.Add(this.progressBar);
+ this.progressPanel.Controls.Add(this.lbl_message);
+ this.progressPanel.Location = new System.Drawing.Point(77, 154);
+ this.progressPanel.Name = "progressPanel";
+ this.progressPanel.Size = new System.Drawing.Size(621, 270);
+ this.progressPanel.TabIndex = 1;
+ //
+ // lbl_sub_message
+ //
+ this.lbl_sub_message.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.lbl_sub_message.ForeColor = System.Drawing.Color.White;
+ this.lbl_sub_message.Location = new System.Drawing.Point(159, 87);
+ this.lbl_sub_message.Name = "lbl_sub_message";
+ this.lbl_sub_message.Size = new System.Drawing.Size(300, 16);
+ this.lbl_sub_message.TabIndex = 2;
+ this.lbl_sub_message.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // progressBar
+ //
+ this.progressBar.AnimationFunction = WinFormAnimation.KnownAnimationFunctions.Liner;
+ this.progressBar.AnimationSpeed = 1000;
+ this.progressBar.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
+ this.progressBar.Font = new System.Drawing.Font("Microsoft Sans Serif", 39.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.progressBar.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this.progressBar.InnerColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this.progressBar.InnerMargin = 0;
+ this.progressBar.InnerWidth = 0;
+ this.progressBar.Location = new System.Drawing.Point(243, 125);
+ this.progressBar.MarqueeAnimationSpeed = 2000;
+ this.progressBar.Name = "progressBar";
+ this.progressBar.OuterColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(64)))), ((int)(((byte)(64)))));
+ this.progressBar.OuterMargin = -8;
+ this.progressBar.OuterWidth = 6;
+ this.progressBar.ProgressColor = System.Drawing.Color.DodgerBlue;
+ this.progressBar.ProgressWidth = 10;
+ this.progressBar.SecondaryFont = new System.Drawing.Font("Microsoft Sans Serif", 26.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.progressBar.Size = new System.Drawing.Size(135, 135);
+ this.progressBar.StartAngle = 270;
+ this.progressBar.SubscriptColor = System.Drawing.Color.FromArgb(((int)(((byte)(166)))), ((int)(((byte)(166)))), ((int)(((byte)(166)))));
+ this.progressBar.SubscriptMargin = new System.Windows.Forms.Padding(10, -35, 0, 0);
+ this.progressBar.SubscriptText = "";
+ this.progressBar.SuperscriptColor = System.Drawing.Color.Gray;
+ this.progressBar.SuperscriptMargin = new System.Windows.Forms.Padding(0, 30, 0, 0);
+ this.progressBar.SuperscriptText = "";
+ this.progressBar.TabIndex = 0;
+ this.progressBar.TextMargin = new System.Windows.Forms.Padding(2, 5, 0, 0);
+ this.progressBar.Value = 68;
+ //
+ // lbl_message
+ //
+ this.lbl_message.Font = new System.Drawing.Font("Microsoft Sans Serif", 27.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(178)));
+ this.lbl_message.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+ this.lbl_message.Location = new System.Drawing.Point(3, 0);
+ this.lbl_message.Name = "lbl_message";
+ this.lbl_message.Size = new System.Drawing.Size(615, 61);
+ this.lbl_message.TabIndex = 1;
+ this.lbl_message.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // t_countdown
+ //
+ this.t_countdown.Interval = 1000;
+ this.t_countdown.Tick += new System.EventHandler(this.t_countdown_Tick);
+ //
+ // t_cancellation
+ //
+ this.t_cancellation.Interval = 1000;
+ this.t_cancellation.Tick += new System.EventHandler(this.t_cancellation_Tick);
+ //
+ // ApplyingProfileForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
+ this.ClientSize = new System.Drawing.Size(800, 450);
+ this.Controls.Add(this.progressPanel);
+ this.DoubleBuffered = true;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.KeyPreview = true;
+ this.Name = "ApplyingProfileForm";
+ this.Opacity = 0D;
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "HeliosPlus - Please Wait";
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ApplyingProfileForm_FormClosing);
+ this.Load += new System.EventHandler(this.ApplyingProfileForm_Reposition);
+ this.Shown += new System.EventHandler(this.ApplyingProfileForm_Shown);
+ this.LocationChanged += new System.EventHandler(this.ApplyingProfileForm_Reposition);
+ this.Leave += new System.EventHandler(this.ApplyingProfileForm_Reposition);
+ this.Move += new System.EventHandler(this.ApplyingProfileForm_Reposition);
+ this.progressPanel.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Panel progressPanel;
+ private CircularProgressBar.CircularProgressBar progressBar;
+ private System.Windows.Forms.Label lbl_sub_message;
+ private System.Windows.Forms.Label lbl_message;
+ private System.Windows.Forms.Timer t_countdown;
+ private System.Windows.Forms.Timer t_cancellation;
+ }
+}
\ No newline at end of file
diff --git a/HeliosPlus/UIForms/ApplyingProfileForm.cs b/HeliosPlus/UIForms/ApplyingProfileForm.cs
new file mode 100644
index 0000000..b767a6b
--- /dev/null
+++ b/HeliosPlus/UIForms/ApplyingProfileForm.cs
@@ -0,0 +1,300 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using WinFormAnimation;
+
+namespace HeliosPlus.UIForms
+{
+ public partial class ApplyingProfileForm : Form
+ {
+ private readonly Bitmap _progressImage;
+ private readonly List _progressPositions = new List();
+ private int _countdownCounter;
+ private readonly int _displayChangeMaxDelta = -1;
+ private int _displayChangeDelta;
+ private int _lastCount;
+ private bool _isClosing;
+ private int _cancellationCounter;
+
+ public ApplyingProfileForm()
+ {
+ InitializeComponent();
+ _progressImage = new Bitmap(progressPanel.Width, progressPanel.Height);
+ Controls.Remove(progressPanel);
+ progressPanel.BackColor = BackColor;
+ progressBar.Invalidated += (sender, args) => Invalidate();
+ progressPanel.Invalidated += (sender, args) => Invalidate();
+ Reposition();
+ }
+
+ public ApplyingProfileForm(int cancellationTimeout = 0, int countdown = 0, string title = null, string message = null, int displayChangeMaxDelta = 5) : this()
+ {
+ _cancellationCounter = cancellationTimeout;
+ _countdownCounter = countdown;
+ _lastCount = _countdownCounter;
+ _displayChangeMaxDelta = displayChangeMaxDelta;
+ if (!string.IsNullOrEmpty(title)) CountdownTitle = title;
+ if (!string.IsNullOrEmpty(message)) CountdownMessage = message;
+ }
+
+ public string CancellationTitle { get; set; } = "Starting in ...";
+ public string CancellationMessage { get; set; } = "Please press ESC to cancel";
+
+ public string CountdownTitle { get; set; } = "Please wait...";
+ public string CountdownMessage { get; set; } = "It won't be long now!";
+
+ protected override void OnKeyDown(KeyEventArgs e)
+ {
+ e.Handled = true;
+ }
+
+ protected override void OnPaint(PaintEventArgs e)
+ {
+ lock (_progressPositions)
+ {
+ progressPanel.DrawToBitmap(_progressImage, new Rectangle(Point.Empty, progressPanel.Size));
+
+ foreach (var position in _progressPositions)
+ {
+ e.Graphics.DrawImage(_progressImage, new Rectangle(position, progressPanel.Size));
+ }
+ }
+
+ base.OnPaint(e);
+ }
+
+ protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
+ {
+ if (keyData != Keys.Escape)
+ {
+ return base.ProcessCmdKey(ref msg, keyData);
+ }
+
+ if (t_cancellation.Enabled)
+ {
+ t_cancellation.Stop();
+ t_countdown.Stop();
+ DialogResult = DialogResult.Cancel;
+ Close();
+
+ return true;
+ }
+
+ return true;
+ }
+
+ private void HandleDisplayChangeDelta()
+ {
+ if (_displayChangeMaxDelta <= -1) return;
+ _displayChangeDelta = _lastCount - _countdownCounter;
+ if (_displayChangeDelta > _displayChangeMaxDelta)
+ {
+ Debug.Print("_displayChangeDelta > _displayChangeMaxDelta! " + _displayChangeDelta + " > " + _displayChangeMaxDelta);
+ DialogResult = DialogResult.OK;
+ Close();
+ }
+ }
+
+ private void DoCountdown()
+ {
+ if (_countdownCounter > 0)
+ {
+ lbl_message.Text = CountdownTitle;
+ lbl_sub_message.Text = CountdownMessage;
+ progressBar.ProgressColor = Color.OrangeRed;
+ progressBar.Text = (progressBar.Value = progressBar.Maximum = _countdownCounter).ToString();
+ t_countdown.Start();
+ }
+ else
+ {
+ progressBar.Style = ProgressBarStyle.Marquee;
+ progressBar.Text = "";
+ progressBar.Maximum = 100;
+ progressBar.Value = 50;
+ progressBar.Style = ProgressBarStyle.Marquee;
+ DialogResult = DialogResult.OK;
+ Close();
+ }
+
+ HandleDisplayChangeDelta();
+ }
+
+ private void DoCancellationTimeout()
+ {
+ if (_cancellationCounter > 0)
+ {
+ lbl_message.Text = CancellationTitle;
+ lbl_sub_message.Text = CancellationMessage;
+ progressBar.ProgressColor = Color.DodgerBlue;
+ progressBar.Text = (progressBar.Value = progressBar.Maximum = _cancellationCounter).ToString();
+ t_cancellation.Start();
+ }
+ else
+ {
+ DoCountdown();
+ }
+ HandleDisplayChangeDelta();
+ }
+
+ private void Reposition()
+ {
+ lock (_progressPositions)
+ {
+
+ Screen[] screens = Screen.AllScreens;
+ Size = screens.Select(screen => screen.Bounds)
+ .Aggregate(Rectangle.Union)
+ .Size;
+
+ _progressPositions.Clear();
+ _progressPositions.AddRange(
+ screens.Select(
+ screen =>
+ new Point(screen.Bounds.X + ((screen.Bounds.Width - progressPanel.Width) / 2),
+ screen.Bounds.Y + ((screen.Bounds.Height - progressPanel.Height) / 2))
+ )
+ );
+ }
+ Invalidate();
+ }
+
+ private void ApplyingProfileForm_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (_isClosing)
+ {
+ return;
+ }
+
+ _isClosing = true;
+ e.Cancel = true;
+ var dialogResult = DialogResult;
+ new Animator(new Path((float)Opacity, 0, 200))
+ .Play(new SafeInvoker(f =>
+ {
+ try
+ {
+ Opacity = f;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"ApplyingProfileForm/ApplyingProfileForm_FormClosing exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
+ // ignored
+ }
+ }, this), new SafeInvoker(() =>
+ {
+ DialogResult = dialogResult;
+ Close();
+ }, this));
+ }
+
+ private void ApplyingProfileForm_Reposition(object sender, EventArgs e)
+ {
+ Reposition();
+ }
+
+ private void ApplyingProfileForm_Shown(object sender, EventArgs e)
+ {
+ new Animator(new Path((float)Opacity, 0.97f, 200))
+ .Play(new SafeInvoker(f =>
+ {
+ try
+ {
+ Opacity = f;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"ApplyingProfileForm/ApplyingProfileForm_Shown exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
+ // ignored
+ }
+ }, this), new SafeInvoker(DoCancellationTimeout, this));
+ }
+
+ private void t_countdown_Tick(object sender, EventArgs e)
+ {
+ if (_countdownCounter < 0)
+ {
+ t_countdown.Stop();
+ DialogResult = DialogResult.OK;
+ Close();
+
+ return;
+ }
+
+ HandleDisplayChangeDelta();
+
+ progressBar.Value = _countdownCounter;
+ progressBar.Text = progressBar.Value.ToString();
+ _countdownCounter--;
+ Reposition();
+ }
+
+ private void t_cancellation_Tick(object sender, EventArgs e)
+ {
+ if (_cancellationCounter < 0)
+ {
+ t_cancellation.Stop();
+ DoCountdown();
+
+ return;
+ }
+
+ progressBar.Value = _cancellationCounter;
+ progressBar.Text = progressBar.Value.ToString();
+ _cancellationCounter--;
+ Reposition();
+ }
+
+ protected override void WndProc(ref Message m)
+ {
+ const int WM_SETTINGCHANGE = 0x001A;
+ const int SPI_SETWORKAREA = 0x02F;
+ const int WM_DISPLAYCHANGE = 0x007E;
+
+ const int x_bitshift = 0;
+ const int y_bitshift = 16;
+ const int xy_mask = 0xFFFF;
+
+ bool displayChange = false;
+
+ switch (m.Msg)
+ {
+ case WM_SETTINGCHANGE:
+ Debug.Print("Message: " + m.ToString());
+ Debug.Print("WM_SETTINGCHANGE");
+ switch ((int)m.WParam)
+ {
+ case SPI_SETWORKAREA:
+ Debug.Print("SPI_SETWORKAREA");
+ displayChange = true;
+ break;
+ }
+ break;
+ case WM_DISPLAYCHANGE:
+ int cxScreen = (xy_mask & ((int)m.LParam) >> x_bitshift);
+ int cyScreen = (xy_mask & ((int)m.LParam) >> y_bitshift);
+ Debug.Print("Message: " + m.ToString());
+ Debug.Print("WM_DISPLAYCHANGE");
+ Debug.Print("cxScreen: " + cxScreen + " cyScreen: " + cyScreen);
+ displayChange = true;
+ break;
+ }
+ if (displayChange)
+ {
+ _displayChangeDelta = _lastCount - _countdownCounter;
+ _lastCount = _countdownCounter;
+ Debug.Print("Display Change Detected at t " + _lastCount + " difference between changes is " + _displayChangeDelta);
+ }
+
+ base.WndProc(ref m);
+ }
+
+ }
+}
+
diff --git a/HeliosPlus/UIForms/ApplyingProfileForm.resx b/HeliosPlus/UIForms/ApplyingProfileForm.resx
new file mode 100644
index 0000000..305cd01
--- /dev/null
+++ b/HeliosPlus/UIForms/ApplyingProfileForm.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 143, 17
+
+
+ 17, 17
+
+
\ No newline at end of file
diff --git a/HeliosPlus/UIForms/DisplayProfileForm.Designer.cs b/HeliosPlus/UIForms/DisplayProfileForm.Designer.cs
index 5ed0d87..f6183ae 100644
--- a/HeliosPlus/UIForms/DisplayProfileForm.Designer.cs
+++ b/HeliosPlus/UIForms/DisplayProfileForm.Designer.cs
@@ -312,9 +312,8 @@ namespace HeliosPlus.UIForms
this.MinimumSize = new System.Drawing.Size(800, 400);
this.Name = "DisplayProfileForm";
this.ShowInTaskbar = false;
- this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "HeliosPlus - Setup Display Profiles";
- this.TopMost = true;
this.Activated += new System.EventHandler(this.DisplayProfileForm_Activated);
this.Load += new System.EventHandler(this.DisplayProfileForm_Load);
this.menu_profiles.ResumeLayout(false);
diff --git a/HeliosPlus/UIForms/DisplayProfileForm.cs b/HeliosPlus/UIForms/DisplayProfileForm.cs
index a9d6c39..2b44f60 100644
--- a/HeliosPlus/UIForms/DisplayProfileForm.cs
+++ b/HeliosPlus/UIForms/DisplayProfileForm.cs
@@ -46,7 +46,8 @@ namespace HeliosPlus.UIForms
}
// Apply the Profile
- ProfileRepository.ApplyProfile(_selectedProfile);
+ //ProfileRepository.ApplyProfile(_selectedProfile);
+ Program.ApplyProfile(_selectedProfile);
}