diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96e8672 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +ScreenDimmer/obj +/ScreenDimmer/bin/Debug +/.vs +/ScreenDimmer/build_verify diff --git a/README.md b/README.md index 78ac830..06a42da 100644 --- a/README.md +++ b/README.md @@ -1,74 +1,18 @@ # ScreenDimmer -Screen Dimmer Free (Enhanced version for Monash CoC) +ScreenDimmer-MultiScreen -Copyleft (ↄ) Augustine's Software 2015 - 2017 +Fork of [ScreenDimmer](https://github.com/datbnh/ScreenDimmer) -Augustine's Software +## Changes -datbnh[at]gmail.com +Support multiple screens and displays them in a layout that should approximate the layout of the users screens. -### Download latest version: -https://github.com/datbnh/ScreenDimmer/releases/latest +Home Assistant integration. Just add credentials to the config file for your mqtt server and it should auto-configure your pc and screens as entities. -## Description -As the minimum brightness of a monitor is sometimes still too bright for you to work at night, the original purpose of Screen Dimmer was to simply render a black layer on top of it to even lower the brightness of your screen. +Upgraded to dotnet 8 -Screen Dimmer allows you to set the brightness level easily and quickly by using hotkeys. You can also change the color of the overlay layer (e.g. to yellow) to use Screen Dimmer as a blue-light filter to protect your precious eyes. +Configs migrated to json from xml -Plus, if you works with multiple screens, Screen Dimmer gives you the capablity of dimming the one that you want, with hotkeys! This can be handy when you are giving presentation and want to mute the secondary screen without any accesses in hand. +![Home Assistant Integration](https://raw.githubusercontent.com/Wixely/ScreenDimmer-MultiScreen/master/Screenshots/Home%20Assistant%20Integration.jpg?raw=true "Home Assistant Integration") -Home page and documentation: https://github.com/datbnh/ScreenDimmer/ - -Source code (GPL): https://github.com/datbnh/ScreenDimmer/ - -## Main Features -* Adjust the screen brightness -* Change the overlay color (e.g. blue light filter) -* Hotkeys supported -* Secondary monitor supported -* Automatically store the current settings and restore them on the next launch of the application - -## System Requirements -Windows operating system is required. *Only tested on Windows 8.1 32-bit and 64-bit, 96-DPI and 125-DPI monitors.* - -## Screenshots -### Main UI -![Main UI basic](https://raw.githubusercontent.com/datbnh/ScreenDimmer/master/Screenshots/Main%20UI.png "Screen Dimmer main UI") -![Main UI advanced](https://raw.githubusercontent.com/datbnh/ScreenDimmer/master/Screenshots/Main%20UI%202.png?raw=true "Screen Dimmer main UI") -### Hotkeys -![Hotkeys](https://raw.githubusercontent.com/datbnh/ScreenDimmer/master/Screenshots/Hotkeys.png?raw=true "Screen Dimmer hotkeys") -### Application in action -![Full Brightness](https://raw.githubusercontent.com/datbnh/ScreenDimmer/master/Screenshots/FullBrightness.png?raw=true "Full brightness") -![Dimmed](https://raw.githubusercontent.com/datbnh/ScreenDimmer/master/Screenshots/OSD.png?raw=true "Dimmed") -### Blue-light filter -![Blue Light Filter](https://raw.githubusercontent.com/datbnh/ScreenDimmer/master/Screenshots/BlueLight%20Filter.png?raw=true "Blue-light filter in action") - -## Change Log -### Version 3.3 -+ On Screen Display (OSD) for brightness level (when main UI is closed to system tray) -+ [Fixed issue] UI fixed to work with high DPI setting -+ [Fixed bug] User has to press "Increase Brightness" hotkey four times for the first increasement - -### Version 3.2 -+ Smooth transition supported -+ Some minor bugs fixed -+ [Known issue] UI layout changes upexpectedly whith high DPI setting - -### Version 3.1 -+ Configurations automatically saved to local file and restored when launch the application next time - -### Version 3.0 -+ Architechture completely changed -+ Global hotkeys supported -+ Performance improved - -### Version 2.1 -+ Extended screen supported -+ Dim & Bright buttons introduced - -### Version 2.0 -+ Application minimized to system tray - -### Version 1 -+ Initial version -+ Overlay color changeable but limited +![Main UI](https://raw.githubusercontent.com/Wixely/ScreenDimmer-MultiScreen/master/Screenshots/Screen%20Layout.jpg?raw=true "Main UI") diff --git a/ScreenDimmer-MultiScreen.sln b/ScreenDimmer-MultiScreen.sln new file mode 100644 index 0000000..9d031cc --- /dev/null +++ b/ScreenDimmer-MultiScreen.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.9.34728.123 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScreenDimmer", "ScreenDimmer\ScreenDimmer.csproj", "{D4C8496F-0990-44B6-A60D-5BB154045873}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D4C8496F-0990-44B6-A60D-5BB154045873}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4C8496F-0990-44B6-A60D-5BB154045873}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4C8496F-0990-44B6-A60D-5BB154045873}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4C8496F-0990-44B6-A60D-5BB154045873}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1A5FE0B2-7245-40FF-9F17-AABA2493784B} + EndGlobalSection +EndGlobal diff --git a/ScreenDimmer/AboutBox1.Designer.cs b/ScreenDimmer/AboutBox.Designer.cs similarity index 97% rename from ScreenDimmer/AboutBox1.Designer.cs rename to ScreenDimmer/AboutBox.Designer.cs index ada8d90..8f31f2a 100644 --- a/ScreenDimmer/AboutBox1.Designer.cs +++ b/ScreenDimmer/AboutBox.Designer.cs @@ -1,204 +1,204 @@ -namespace Augustine.ScreenDimmer -{ - partial class AboutBox1 - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - 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() - { - System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutBox1)); - this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); - this.logoPictureBox = new System.Windows.Forms.PictureBox(); - this.labelProductName = new System.Windows.Forms.TextBox(); - this.labelVersion = new System.Windows.Forms.TextBox(); - this.labelCopyright = new System.Windows.Forms.TextBox(); - this.labelCompanyName = new System.Windows.Forms.TextBox(); - this.textBoxDescription = new System.Windows.Forms.RichTextBox(); - this.okButton = new System.Windows.Forms.Button(); - this.tableLayoutPanel.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); - this.SuspendLayout(); - // - // tableLayoutPanel - // - this.tableLayoutPanel.AutoSize = true; - this.tableLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.tableLayoutPanel.ColumnCount = 2; - this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 40F)); - this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); - this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0); - this.tableLayoutPanel.Controls.Add(this.labelVersion, 0, 3); - this.tableLayoutPanel.Controls.Add(this.labelCopyright, 0, 4); - this.tableLayoutPanel.Controls.Add(this.labelCompanyName, 0, 5); - this.tableLayoutPanel.Controls.Add(this.textBoxDescription, 0, 6); - this.tableLayoutPanel.Controls.Add(this.okButton, 1, 7); - this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel.Location = new System.Drawing.Point(9, 9); - this.tableLayoutPanel.Name = "tableLayoutPanel"; - this.tableLayoutPanel.RowCount = 8; - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel.Size = new System.Drawing.Size(516, 343); - this.tableLayoutPanel.TabIndex = 0; - // - // logoPictureBox - // - this.logoPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; - this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); - this.logoPictureBox.Location = new System.Drawing.Point(3, 3); - this.logoPictureBox.Name = "logoPictureBox"; - this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 2); - this.logoPictureBox.Size = new System.Drawing.Size(34, 34); - this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; - this.logoPictureBox.TabIndex = 12; - this.logoPictureBox.TabStop = false; - // - // labelProductName - // - this.labelProductName.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelProductName.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelProductName.Location = new System.Drawing.Point(46, 0); - this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); - this.labelProductName.Multiline = true; - this.labelProductName.Name = "labelProductName"; - this.labelProductName.ReadOnly = true; - this.tableLayoutPanel.SetRowSpan(this.labelProductName, 2); - this.labelProductName.Size = new System.Drawing.Size(469, 58); - this.labelProductName.TabIndex = 19; - this.labelProductName.TabStop = false; - this.labelProductName.Text = "Product Name"; - // - // labelVersion - // - this.labelVersion.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.tableLayoutPanel.SetColumnSpan(this.labelVersion, 2); - this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelVersion.Location = new System.Drawing.Point(6, 58); - this.labelVersion.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); - this.labelVersion.Name = "labelVersion"; - this.labelVersion.ReadOnly = true; - this.labelVersion.Size = new System.Drawing.Size(509, 15); - this.labelVersion.TabIndex = 20; - this.labelVersion.TabStop = false; - this.labelVersion.Text = "Version"; - // - // labelCopyright - // - this.labelCopyright.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.tableLayoutPanel.SetColumnSpan(this.labelCopyright, 2); - this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelCopyright.Location = new System.Drawing.Point(6, 73); - this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); - this.labelCopyright.Name = "labelCopyright"; - this.labelCopyright.ReadOnly = true; - this.labelCopyright.Size = new System.Drawing.Size(509, 15); - this.labelCopyright.TabIndex = 21; - this.labelCopyright.TabStop = false; - this.labelCopyright.Text = "Copyright"; - // - // labelCompanyName - // - this.labelCompanyName.BorderStyle = System.Windows.Forms.BorderStyle.None; - this.tableLayoutPanel.SetColumnSpan(this.labelCompanyName, 2); - this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelCompanyName.Location = new System.Drawing.Point(6, 88); - this.labelCompanyName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); - this.labelCompanyName.Name = "labelCompanyName"; - this.labelCompanyName.ReadOnly = true; - this.labelCompanyName.Size = new System.Drawing.Size(509, 15); - this.labelCompanyName.TabIndex = 22; - this.labelCompanyName.TabStop = false; - this.labelCompanyName.Text = "Company Name"; - // - // textBoxDescription - // - this.tableLayoutPanel.SetColumnSpan(this.textBoxDescription, 2); - this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; - this.textBoxDescription.Location = new System.Drawing.Point(3, 106); - this.textBoxDescription.MinimumSize = new System.Drawing.Size(4, 125); - this.textBoxDescription.Name = "textBoxDescription"; - this.textBoxDescription.ReadOnly = true; - this.textBoxDescription.Size = new System.Drawing.Size(512, 205); - this.textBoxDescription.TabIndex = 23; - this.textBoxDescription.TabStop = false; - this.textBoxDescription.Text = "Description"; - // - // okButton - // - this.okButton.AutoSize = true; - this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.okButton.Dock = System.Windows.Forms.DockStyle.Right; - this.okButton.Location = new System.Drawing.Point(440, 317); - this.okButton.Name = "okButton"; - this.okButton.Size = new System.Drawing.Size(75, 23); - this.okButton.TabIndex = 24; - this.okButton.Text = "&OK"; - // - // AboutBox1 - // - this.AcceptButton = this.okButton; - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.ClientSize = new System.Drawing.Size(534, 361); - this.Controls.Add(this.tableLayoutPanel); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "AboutBox1"; - this.Padding = new System.Windows.Forms.Padding(9); - this.ShowIcon = false; - this.ShowInTaskbar = false; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "AboutBox1"; - this.tableLayoutPanel.ResumeLayout(false); - this.tableLayoutPanel.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); - this.ResumeLayout(false); - this.PerformLayout(); - - } - - #endregion - - private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; - private System.Windows.Forms.PictureBox logoPictureBox; - private System.Windows.Forms.TextBox labelVersion; - private System.Windows.Forms.TextBox labelCopyright; - private System.Windows.Forms.TextBox labelCompanyName; - private System.Windows.Forms.RichTextBox textBoxDescription; - private System.Windows.Forms.Button okButton; - private System.Windows.Forms.TextBox labelProductName; - } -} +namespace Augustine.ScreenDimmer +{ + partial class AboutBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + 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() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutBox)); + this.tableLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.logoPictureBox = new System.Windows.Forms.PictureBox(); + this.labelProductName = new System.Windows.Forms.TextBox(); + this.labelVersion = new System.Windows.Forms.TextBox(); + this.labelCopyright = new System.Windows.Forms.TextBox(); + this.labelCompanyName = new System.Windows.Forms.TextBox(); + this.textBoxDescription = new System.Windows.Forms.RichTextBox(); + this.okButton = new System.Windows.Forms.Button(); + this.tableLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit(); + this.SuspendLayout(); + // + // tableLayoutPanel + // + this.tableLayoutPanel.AutoSize = true; + this.tableLayoutPanel.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.tableLayoutPanel.ColumnCount = 2; + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 40F)); + this.tableLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel.Controls.Add(this.logoPictureBox, 0, 0); + this.tableLayoutPanel.Controls.Add(this.labelProductName, 1, 0); + this.tableLayoutPanel.Controls.Add(this.labelVersion, 0, 3); + this.tableLayoutPanel.Controls.Add(this.labelCopyright, 0, 4); + this.tableLayoutPanel.Controls.Add(this.labelCompanyName, 0, 5); + this.tableLayoutPanel.Controls.Add(this.textBoxDescription, 0, 6); + this.tableLayoutPanel.Controls.Add(this.okButton, 1, 7); + this.tableLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel.Location = new System.Drawing.Point(9, 9); + this.tableLayoutPanel.Name = "tableLayoutPanel"; + this.tableLayoutPanel.RowCount = 8; + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle()); + this.tableLayoutPanel.Size = new System.Drawing.Size(516, 343); + this.tableLayoutPanel.TabIndex = 0; + // + // logoPictureBox + // + this.logoPictureBox.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.logoPictureBox.Image = ((System.Drawing.Image)(resources.GetObject("logoPictureBox.Image"))); + this.logoPictureBox.Location = new System.Drawing.Point(3, 3); + this.logoPictureBox.Name = "logoPictureBox"; + this.tableLayoutPanel.SetRowSpan(this.logoPictureBox, 2); + this.logoPictureBox.Size = new System.Drawing.Size(34, 34); + this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; + this.logoPictureBox.TabIndex = 12; + this.logoPictureBox.TabStop = false; + // + // labelProductName + // + this.labelProductName.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.labelProductName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelProductName.Font = new System.Drawing.Font("Segoe UI Semibold", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.labelProductName.Location = new System.Drawing.Point(46, 0); + this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelProductName.Multiline = true; + this.labelProductName.Name = "labelProductName"; + this.labelProductName.ReadOnly = true; + this.tableLayoutPanel.SetRowSpan(this.labelProductName, 2); + this.labelProductName.Size = new System.Drawing.Size(469, 58); + this.labelProductName.TabIndex = 19; + this.labelProductName.TabStop = false; + this.labelProductName.Text = "Product Name"; + // + // labelVersion + // + this.labelVersion.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.tableLayoutPanel.SetColumnSpan(this.labelVersion, 2); + this.labelVersion.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelVersion.Location = new System.Drawing.Point(6, 58); + this.labelVersion.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelVersion.Name = "labelVersion"; + this.labelVersion.ReadOnly = true; + this.labelVersion.Size = new System.Drawing.Size(509, 15); + this.labelVersion.TabIndex = 20; + this.labelVersion.TabStop = false; + this.labelVersion.Text = "Version"; + // + // labelCopyright + // + this.labelCopyright.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.tableLayoutPanel.SetColumnSpan(this.labelCopyright, 2); + this.labelCopyright.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCopyright.Location = new System.Drawing.Point(6, 73); + this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCopyright.Name = "labelCopyright"; + this.labelCopyright.ReadOnly = true; + this.labelCopyright.Size = new System.Drawing.Size(509, 15); + this.labelCopyright.TabIndex = 21; + this.labelCopyright.TabStop = false; + this.labelCopyright.Text = "Copyright"; + // + // labelCompanyName + // + this.labelCompanyName.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.tableLayoutPanel.SetColumnSpan(this.labelCompanyName, 2); + this.labelCompanyName.Dock = System.Windows.Forms.DockStyle.Fill; + this.labelCompanyName.Location = new System.Drawing.Point(6, 88); + this.labelCompanyName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0); + this.labelCompanyName.Name = "labelCompanyName"; + this.labelCompanyName.ReadOnly = true; + this.labelCompanyName.Size = new System.Drawing.Size(509, 15); + this.labelCompanyName.TabIndex = 22; + this.labelCompanyName.TabStop = false; + this.labelCompanyName.Text = "Company Name"; + // + // textBoxDescription + // + this.tableLayoutPanel.SetColumnSpan(this.textBoxDescription, 2); + this.textBoxDescription.Dock = System.Windows.Forms.DockStyle.Fill; + this.textBoxDescription.Location = new System.Drawing.Point(3, 106); + this.textBoxDescription.MinimumSize = new System.Drawing.Size(4, 125); + this.textBoxDescription.Name = "textBoxDescription"; + this.textBoxDescription.ReadOnly = true; + this.textBoxDescription.Size = new System.Drawing.Size(512, 205); + this.textBoxDescription.TabIndex = 23; + this.textBoxDescription.TabStop = false; + this.textBoxDescription.Text = "Description"; + // + // okButton + // + this.okButton.AutoSize = true; + this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.okButton.Dock = System.Windows.Forms.DockStyle.Right; + this.okButton.Location = new System.Drawing.Point(440, 317); + this.okButton.Name = "okButton"; + this.okButton.Size = new System.Drawing.Size(75, 23); + this.okButton.TabIndex = 24; + this.okButton.Text = "&OK"; + // + // AboutBox1 + // + this.AcceptButton = this.okButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.AutoSize = true; + this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.ClientSize = new System.Drawing.Size(534, 361); + this.Controls.Add(this.tableLayoutPanel); + this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "AboutBox1"; + this.Padding = new System.Windows.Forms.Padding(9); + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "AboutBox1"; + this.tableLayoutPanel.ResumeLayout(false); + this.tableLayoutPanel.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TableLayoutPanel tableLayoutPanel; + private System.Windows.Forms.PictureBox logoPictureBox; + private System.Windows.Forms.TextBox labelVersion; + private System.Windows.Forms.TextBox labelCopyright; + private System.Windows.Forms.TextBox labelCompanyName; + private System.Windows.Forms.RichTextBox textBoxDescription; + private System.Windows.Forms.Button okButton; + private System.Windows.Forms.TextBox labelProductName; + } +} diff --git a/ScreenDimmer/AboutBox.cs b/ScreenDimmer/AboutBox.cs new file mode 100644 index 0000000..2959919 --- /dev/null +++ b/ScreenDimmer/AboutBox.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Augustine.ScreenDimmer +{ + partial class AboutBox : Form + { + public static Version version = new Version(1,0); + + public AboutBox() + { + InitializeComponent(); + this.Text = "About ScreenDimmer-MultiScreen"; + this.labelProductName.Text = AssemblyProduct; + this.labelVersion.Text = String.Format("Version {0}", AssemblyVersion); + this.labelCopyright.Text = AssemblyCopyright; + this.labelCompanyName.Text = ""; + this.textBoxDescription.Text = AssemblyDescription; + this.Icon = ScreenDimmer.IconMediumBright32x32; + this.logoPictureBox.Image = TextIcon.CreateTextIcon("\uE286", Color.Black, "", 32).ToBitmap(); + } + + #region Assembly Attribute Accessors + + public string AssemblyVersion + { + get + { + return version.ToString(); + } + } + + public string AssemblyDescription + { + get + { + return + "ScreenDimmer-Multiscreen is a fork of ScreenDimmer with support for multiple monitors\n" + + "Source: https://github.com/Wixely/ScreenDimmer-MultiScreen\n\n" + + "Credit: https://github.com/datbnh/ScreenDimmer"; + } + } + + public string AssemblyProduct + { + get + { + object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); + if (attributes.Length == 0) + { + return ""; + } + return ((AssemblyProductAttribute)attributes[0]).Product; + } + } + + public string AssemblyCopyright + { + get + { + return "ↄ2025"; + } + } + #endregion + } +} diff --git a/ScreenDimmer/AboutBox1.resx b/ScreenDimmer/AboutBox.resx similarity index 98% rename from ScreenDimmer/AboutBox1.resx rename to ScreenDimmer/AboutBox.resx index 4fcac39..76cc9af 100644 --- a/ScreenDimmer/AboutBox1.resx +++ b/ScreenDimmer/AboutBox.resx @@ -1,603 +1,603 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 - - - - - 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 - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + + + 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 + + \ No newline at end of file diff --git a/ScreenDimmer/AboutBox1.cs b/ScreenDimmer/AboutBox1.cs deleted file mode 100644 index 19079a2..0000000 --- a/ScreenDimmer/AboutBox1.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Drawing; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace Augustine.ScreenDimmer -{ - partial class AboutBox1 : Form - { - public AboutBox1() - { - InitializeComponent(); - Version version = Assembly.GetExecutingAssembly().GetName().Version; - DateTime buildDate = new DateTime(2000, 1, 1) - .AddDays(version.Build).AddSeconds(version.Revision * 2); - this.Text = String.Format("About {0}", AssemblyTitle); - this.labelProductName.Text = AssemblyProduct; - this.labelVersion.Text = String.Format("Version {0} (Built {1})", AssemblyVersion, buildDate); - this.labelCopyright.Text = AssemblyCopyright; - this.labelCompanyName.Text = AssemblyCompany; - this.textBoxDescription.Text = AssemblyDescription; - this.Icon = ScreenDimmer.IconMediumBright32x32; - this.logoPictureBox.Image = TextIcon.CreateTextIcon("\uE286", Color.Black, "", 32).ToBitmap(); - } - - #region Assembly Attribute Accessors - - public string AssemblyTitle - { - get - { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false); - if (attributes.Length > 0) - { - AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0]; - if (titleAttribute.Title != "") - { - return titleAttribute.Title; - } - } - return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().CodeBase); - } - } - - public string AssemblyVersion - { - get - { - return Assembly.GetExecutingAssembly().GetName().Version.ToString(); - } - } - - public string AssemblyDescription - { - get - { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyDescriptionAttribute)attributes[0]).Description; - } - } - - public string AssemblyProduct - { - get - { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyProductAttribute)attributes[0]).Product; - } - } - - public string AssemblyCopyright - { - get - { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyCopyrightAttribute)attributes[0]).Copyright; - } - } - - public string AssemblyCompany - { - get - { - object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false); - if (attributes.Length == 0) - { - return ""; - } - return ((AssemblyCompanyAttribute)attributes[0]).Company; - } - } - #endregion - } -} diff --git a/ScreenDimmer/App.config b/ScreenDimmer/App.config index 8e15646..4bfa005 100644 --- a/ScreenDimmer/App.config +++ b/ScreenDimmer/App.config @@ -1,6 +1,6 @@ - + - + - \ No newline at end of file + diff --git a/ScreenDimmer/CheckboxButton.cs b/ScreenDimmer/CheckboxButton.cs new file mode 100644 index 0000000..1a97598 --- /dev/null +++ b/ScreenDimmer/CheckboxButton.cs @@ -0,0 +1,67 @@ +using System; +using System.Windows.Forms; + +namespace Augustine.ScreenDimmer +{ + public class CheckboxButton : Button + { + + private bool isChecked = false; + public static int DefaultSize = 30; + + public bool Checked + { + get { return isChecked; } + set { + var triggerChange = (isChecked != value); + isChecked = value; + if (triggerChange) + { + RunUpdate(); + } + } + } + + public string CBName = ""; + public static string TextEnabled = "🕶️"; + public static string TextDisabled = "🔆"; + + public event EventHandler CheckedChanged; + + public CheckboxButton() + { + UpdateText(); + this.Click += CheckboxButton_Click; + } + + private void CheckboxButton_Click(object sender, EventArgs e) + { + Toggle(); + } + + public void Toggle() + { + Checked = !Checked; + } + + public void SetEnable() + { + Checked = true; + } + + public void SetDisable() + { + Checked = false; + } + public void UpdateText() + { + Text = $"{(Checked ? TextEnabled : TextDisabled)}"; + } + + public void RunUpdate() + { + UpdateText(); + CheckedChanged?.Invoke(this, EventArgs.Empty); + } + } +} diff --git a/ScreenDimmer/Configuration.cs b/ScreenDimmer/Configuration.cs index fc75e18..6d0c150 100644 --- a/ScreenDimmer/Configuration.cs +++ b/ScreenDimmer/Configuration.cs @@ -5,6 +5,7 @@ using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; +using System.Windows.Forms; namespace Augustine.ScreenDimmer { @@ -19,8 +20,6 @@ internal class Configuration internal bool IsDebug; [DataMember(Name = "AllowTransition")] internal bool IsTransition; - [DataMember(Name = "MonitorIndex")] - internal byte MonitorIndex; /// /// Range: 0-100 /// @@ -71,30 +70,103 @@ private string hotKeyHalt { set { HotKeyHalt = GlobalHotkeyParser.Parse(value); } } internal GlobalHotKey HotKeyHalt; + [DataMember(Name = "ScreenToggleHotKeys")] + private List screenToggleHotKeys + { + get { return ScreenToggleHotKeys?.Select(o => o.ToString()).ToList(); } + set { ConfiguredScreenToggleHotKeys = value ?? new List(); } + } + internal List ScreenToggleHotKeys; + internal List ConfiguredScreenToggleHotKeys; + + [DataMember(Name = "EnabledScreens")] + internal List EnabledScreens; + + [DataMember(Name = "MQTTHostName")] + internal string MQTTHostName; + + [DataMember(Name = "MQTTUsername")] + internal string MQTTUsername; + + [DataMember(Name = "MQTTPassword")] + internal string MQTTPassword; + + private void EnsureHotKeysInitialized() + { + HotKeyDim ??= new GlobalHotKey(); + HotKeyBrighten ??= new GlobalHotKey(); + HotKeyIncreaseBrightness ??= new GlobalHotKey(); + HotKeyDecreaseBrightness ??= new GlobalHotKey(); + HotKeyForceOnTop ??= new GlobalHotKey(); + HotKeyHalt ??= new GlobalHotKey(); + ScreenToggleHotKeys ??= new List(); + ConfiguredScreenToggleHotKeys ??= new List(); + } + + private void EnsureConfigurationState() + { + EnsureHotKeysInitialized(); + EnabledScreens ??= new List(); + } + internal Configuration() { - HotKeyDim = new GlobalHotKey(); - HotKeyBrighten = new GlobalHotKey(); - HotKeyIncreaseBrightness = new GlobalHotKey(); - HotKeyDecreaseBrightness = new GlobalHotKey(); - HotKeyForceOnTop = new GlobalHotKey(); - HotKeyHalt = new GlobalHotKey(); + EnsureConfigurationState(); } private void setHotkeyDescriptions() { + EnsureHotKeysInitialized(); HotKeyDim.SetDescription("Dim (minimum brightness)"); HotKeyBrighten.SetDescription("Brighten (maximum brightness)"); HotKeyIncreaseBrightness.SetDescription("Increase Brightness"); HotKeyDecreaseBrightness.SetDescription("Decrease Brightness"); HotKeyForceOnTop.SetDescription("Force on Top"); HotKeyHalt.SetDescription("Immediately Halt Program"); + for (int i = 0; i < ScreenToggleHotKeys.Count; i++) + { + ScreenToggleHotKeys[i].SetDescription($"Toggle Screen {i + 1}"); + } + } + + private void buildScreenToggleHotKeys() + { + EnsureHotKeysInitialized(); + var configuredHotkeys = ConfiguredScreenToggleHotKeys.ToList(); + ScreenToggleHotKeys = new List(); + var supportedScreenCount = Math.Min(ScreenExtended.AllScreens.Count, 12); + for (int i = 0; i < supportedScreenCount; i++) + { + ScreenToggleHotKeys.Add(createScreenToggleHotKey(i, configuredHotkeys.ElementAtOrDefault(i))); + } + ConfiguredScreenToggleHotKeys = ScreenToggleHotKeys.Select(o => o.ToString()).ToList(); + } + + private GlobalHotKey createScreenToggleHotKey(int screenIndex, string configuredHotKey) + { + if (!string.IsNullOrWhiteSpace(configuredHotKey)) + { + try + { + return GlobalHotkeyParser.Parse(configuredHotKey); + } + catch + { + } + } + + var key = (Keys)((int)Keys.F13 + screenIndex); + return new GlobalHotKey( + KeyModifiers.NONE, + key, + $"Toggle Screen {screenIndex + 1}"); } internal void LoadDefault() { - MonitorIndex = 0; + EnsureConfigurationState(); CurrentBrightness = 70; + EnabledScreens = ScreenExtended.AllScreens.Select(o => o.DeviceName).ToList(); IsZeroBrightness = true; IsEnforceOnTop = false; IsDebug = false; @@ -107,6 +179,7 @@ internal void LoadDefault() HotKeyIncreaseBrightness.SetKey(KeyModifiers.MOD_WIN | KeyModifiers.MOD_CONTROL, System.Windows.Forms.Keys.Up); HotKeyForceOnTop.SetKey(KeyModifiers.MOD_WIN | KeyModifiers.MOD_CONTROL, System.Windows.Forms.Keys.T); HotKeyHalt.SetKey(KeyModifiers.MOD_WIN | KeyModifiers.MOD_CONTROL, System.Windows.Forms.Keys.H); + buildScreenToggleHotKeys(); setHotkeyDescriptions(); } @@ -121,12 +194,14 @@ internal static Configuration LoadFromFile(string fileName) { throw new Exception("Cannot parse configuration from file.", ex); } - deserialized.setHotkeyDescriptions(); + deserialized.EnsureConfigurationState(); // For the purpose of robustness. Non-positive fade duration will cause trouble. if (deserialized.FadeDuration < 1) { deserialized.FadeDuration = 250; } + deserialized.buildScreenToggleHotKeys(); + deserialized.setHotkeyDescriptions(); return deserialized; //this.CurrentBrightness = deserialized.CurrentBrightness; //this.DimColor = deserialized.DimColor; diff --git a/ScreenDimmer/Extensions.cs b/ScreenDimmer/Extensions.cs new file mode 100644 index 0000000..4d78878 --- /dev/null +++ b/ScreenDimmer/Extensions.cs @@ -0,0 +1,331 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System; +using System.Windows.Forms; +using System.Linq; + +namespace Augustine.ScreenDimmer +{ + public static class Extensions + { + public static void InvokeIfRequired(this Control control, MethodInvoker action) + { + // See Update 2 for edits Mike de Klerk suggests to insert here. + + if (control.InvokeRequired) + { + control.Invoke(action); + } + else + { + action(); + } + } + } + + //https://stackoverflow.com/questions/4958683/how-do-i-get-the-actual-monitor-name-as-seen-in-the-resolution-dialog + public static class ScreenInterrogatory + { + public const int ERROR_SUCCESS = 0; + + #region enums + + public enum QUERY_DEVICE_CONFIG_FLAGS : uint + { + QDC_ALL_PATHS = 0x00000001, + QDC_ONLY_ACTIVE_PATHS = 0x00000002, + QDC_DATABASE_CURRENT = 0x00000004 + } + + public enum DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY : uint + { + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_OTHER = 0xFFFFFFFF, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HD15 = 0, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPOSITE_VIDEO = 2, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_COMPONENT_VIDEO = 3, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DVI = 4, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_HDMI = 5, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_LVDS = 6, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_D_JPN = 8, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDI = 9, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EXTERNAL = 10, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED = 11, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EXTERNAL = 12, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_UDI_EMBEDDED = 13, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SDTVDONGLE = 14, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_MIRACAST = 15, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000, + DISPLAYCONFIG_OUTPUT_TECHNOLOGY_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_SCANLINE_ORDERING : uint + { + DISPLAYCONFIG_SCANLINE_ORDERING_UNSPECIFIED = 0, + DISPLAYCONFIG_SCANLINE_ORDERING_PROGRESSIVE = 1, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED = 2, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_UPPERFIELDFIRST = DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED, + DISPLAYCONFIG_SCANLINE_ORDERING_INTERLACED_LOWERFIELDFIRST = 3, + DISPLAYCONFIG_SCANLINE_ORDERING_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_ROTATION : uint + { + DISPLAYCONFIG_ROTATION_IDENTITY = 1, + DISPLAYCONFIG_ROTATION_ROTATE90 = 2, + DISPLAYCONFIG_ROTATION_ROTATE180 = 3, + DISPLAYCONFIG_ROTATION_ROTATE270 = 4, + DISPLAYCONFIG_ROTATION_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_SCALING : uint + { + DISPLAYCONFIG_SCALING_IDENTITY = 1, + DISPLAYCONFIG_SCALING_CENTERED = 2, + DISPLAYCONFIG_SCALING_STRETCHED = 3, + DISPLAYCONFIG_SCALING_ASPECTRATIOCENTEREDMAX = 4, + DISPLAYCONFIG_SCALING_CUSTOM = 5, + DISPLAYCONFIG_SCALING_PREFERRED = 128, + DISPLAYCONFIG_SCALING_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_PIXELFORMAT : uint + { + DISPLAYCONFIG_PIXELFORMAT_8BPP = 1, + DISPLAYCONFIG_PIXELFORMAT_16BPP = 2, + DISPLAYCONFIG_PIXELFORMAT_24BPP = 3, + DISPLAYCONFIG_PIXELFORMAT_32BPP = 4, + DISPLAYCONFIG_PIXELFORMAT_NONGDI = 5, + DISPLAYCONFIG_PIXELFORMAT_FORCE_UINT32 = 0xffffffff + } + + public enum DISPLAYCONFIG_MODE_INFO_TYPE : uint + { + DISPLAYCONFIG_MODE_INFO_TYPE_SOURCE = 1, + DISPLAYCONFIG_MODE_INFO_TYPE_TARGET = 2, + DISPLAYCONFIG_MODE_INFO_TYPE_FORCE_UINT32 = 0xFFFFFFFF + } + + public enum DISPLAYCONFIG_DEVICE_INFO_TYPE : uint + { + DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME = 1, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME = 2, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE = 3, + DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME = 4, + DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE = 5, + DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE = 6, + DISPLAYCONFIG_DEVICE_INFO_FORCE_UINT32 = 0xFFFFFFFF + } + + #endregion + + #region structs + + [StructLayout(LayoutKind.Sequential)] + public struct LUID + { + public uint LowPart; + public int HighPart; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_PATH_SOURCE_INFO + { + public LUID adapterId; + public uint id; + public uint modeInfoIdx; + public uint statusFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_PATH_TARGET_INFO + { + public LUID adapterId; + public uint id; + public uint modeInfoIdx; + private DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; + private DISPLAYCONFIG_ROTATION rotation; + private DISPLAYCONFIG_SCALING scaling; + private DISPLAYCONFIG_RATIONAL refreshRate; + private DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; + public bool targetAvailable; + public uint statusFlags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_RATIONAL + { + public uint Numerator; + public uint Denominator; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_PATH_INFO + { + public DISPLAYCONFIG_PATH_SOURCE_INFO sourceInfo; + public DISPLAYCONFIG_PATH_TARGET_INFO targetInfo; + public uint flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_2DREGION + { + public uint cx; + public uint cy; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_VIDEO_SIGNAL_INFO + { + public ulong pixelRate; + public DISPLAYCONFIG_RATIONAL hSyncFreq; + public DISPLAYCONFIG_RATIONAL vSyncFreq; + public DISPLAYCONFIG_2DREGION activeSize; + public DISPLAYCONFIG_2DREGION totalSize; + public uint videoStandard; + public DISPLAYCONFIG_SCANLINE_ORDERING scanLineOrdering; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_TARGET_MODE + { + public DISPLAYCONFIG_VIDEO_SIGNAL_INFO targetVideoSignalInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct POINTL + { + private int x; + private int y; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_SOURCE_MODE + { + public uint width; + public uint height; + public DISPLAYCONFIG_PIXELFORMAT pixelFormat; + public POINTL position; + } + + [StructLayout(LayoutKind.Explicit)] + public struct DISPLAYCONFIG_MODE_INFO_UNION + { + [FieldOffset(0)] + public DISPLAYCONFIG_TARGET_MODE targetMode; + + [FieldOffset(0)] + public DISPLAYCONFIG_SOURCE_MODE sourceMode; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_MODE_INFO + { + public DISPLAYCONFIG_MODE_INFO_TYPE infoType; + public uint id; + public LUID adapterId; + public DISPLAYCONFIG_MODE_INFO_UNION modeInfo; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS + { + public uint value; + } + + [StructLayout(LayoutKind.Sequential)] + public struct DISPLAYCONFIG_DEVICE_INFO_HEADER + { + public DISPLAYCONFIG_DEVICE_INFO_TYPE type; + public uint size; + public LUID adapterId; + public uint id; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct DISPLAYCONFIG_TARGET_DEVICE_NAME + { + public DISPLAYCONFIG_DEVICE_INFO_HEADER header; + public DISPLAYCONFIG_TARGET_DEVICE_NAME_FLAGS flags; + public DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY outputTechnology; + public ushort edidManufactureId; + public ushort edidProductCodeId; + public uint connectorInstance; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string monitorFriendlyDeviceName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string monitorDevicePath; + } + + #endregion + + #region DLL-Imports + + [DllImport("user32.dll")] + public static extern int GetDisplayConfigBufferSizes( + QUERY_DEVICE_CONFIG_FLAGS flags, out uint numPathArrayElements, out uint numModeInfoArrayElements); + + [DllImport("user32.dll")] + public static extern int QueryDisplayConfig( + QUERY_DEVICE_CONFIG_FLAGS flags, + ref uint numPathArrayElements, [Out] DISPLAYCONFIG_PATH_INFO[] PathInfoArray, + ref uint numModeInfoArrayElements, [Out] DISPLAYCONFIG_MODE_INFO[] ModeInfoArray, + IntPtr currentTopologyId + ); + + [DllImport("user32.dll")] + public static extern int DisplayConfigGetDeviceInfo(ref DISPLAYCONFIG_TARGET_DEVICE_NAME deviceName); + + #endregion + + private static string MonitorFriendlyName(LUID adapterId, uint targetId) + { + var deviceName = new DISPLAYCONFIG_TARGET_DEVICE_NAME + { + header = + { + size = (uint)Marshal.SizeOf(typeof (DISPLAYCONFIG_TARGET_DEVICE_NAME)), + adapterId = adapterId, + id = targetId, + type = DISPLAYCONFIG_DEVICE_INFO_TYPE.DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME + } + }; + var error = DisplayConfigGetDeviceInfo(ref deviceName); + if (error != ERROR_SUCCESS) + throw new Win32Exception(error); + return deviceName.monitorFriendlyDeviceName; + } + + private static IEnumerable GetAllMonitorsFriendlyNames() + { + uint pathCount, modeCount; + var error = GetDisplayConfigBufferSizes(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, out pathCount, out modeCount); + if (error != ERROR_SUCCESS) + throw new Win32Exception(error); + + var displayPaths = new DISPLAYCONFIG_PATH_INFO[pathCount]; + var displayModes = new DISPLAYCONFIG_MODE_INFO[modeCount]; + error = QueryDisplayConfig(QUERY_DEVICE_CONFIG_FLAGS.QDC_ONLY_ACTIVE_PATHS, + ref pathCount, displayPaths, ref modeCount, displayModes, IntPtr.Zero); + if (error != ERROR_SUCCESS) + throw new Win32Exception(error); + + for (var i = 0; i < modeCount; i++) + if (displayModes[i].infoType == DISPLAYCONFIG_MODE_INFO_TYPE.DISPLAYCONFIG_MODE_INFO_TYPE_TARGET) + yield return MonitorFriendlyName(displayModes[i].adapterId, displayModes[i].id); + } + + public static string DeviceFriendlyName(this Screen screen) + { + var allFriendlyNames = GetAllMonitorsFriendlyNames(); + for (var index = 0; index < ScreenExtended.AllScreens.Count; index++) + if (Equals(screen, ScreenExtended.AllScreens[index])) + return allFriendlyNames.ToArray()[index]; + return null; + } + + } +} diff --git a/ScreenDimmer/GlobalHotKey.cs b/ScreenDimmer/GlobalHotKey.cs index 7d7b729..f27bd3a 100644 --- a/ScreenDimmer/GlobalHotKey.cs +++ b/ScreenDimmer/GlobalHotKey.cs @@ -97,11 +97,19 @@ public void Unregister() } public static bool operator ==(GlobalHotKey a, GlobalHotKey b) { + if (ReferenceEquals(a, b)) + { + return true; + } + if (a is null || b is null) + { + return false; + } return a.GetHashCode() == b.GetHashCode(); } public static bool operator !=(GlobalHotKey a, GlobalHotKey b) { - return a.GetHashCode() != b.GetHashCode(); + return !(a == b); } public override bool Equals(object obj) diff --git a/ScreenDimmer/MQTTService.cs b/ScreenDimmer/MQTTService.cs new file mode 100644 index 0000000..ffef723 --- /dev/null +++ b/ScreenDimmer/MQTTService.cs @@ -0,0 +1,193 @@ +using HiveMQtt.Client; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HiveMQtt.Client; +using HiveMQtt.MQTT5.Types; +using Newtonsoft.Json; +using System.Xml; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; + +namespace Augustine.ScreenDimmer +{ + public class MQTTService + { + public static ScreenDimmer screenDimmerMain; + public static HiveMQClient client; + + public const string HASwitchOn = "ON"; + public const string HASwitchOff = "OFF"; + + + public static string ConfigHost = ""; + public static string ConfigUserName = ""; + public static string ConfigPassword = ""; + + + + public static string HABase = "homeassistant"; + public static string AppBase = "ScreenDimmer"; + + public static async Task Connect(ScreenDimmer screenDimmer) + { + screenDimmerMain = screenDimmer; + try + { + if (ConfigHost == null) + return; // do not set up mqtt + + + // Setup Client options and instantiate + var options = new HiveMQClientOptionsBuilder(). + WithBroker(ConfigHost). + WithUseTls(false). + WithUserName(ConfigUserName). + WithPassword(ConfigPassword). + Build(); + + client = new HiveMQClient(options); + + // Connect to the MQTT broker + var connectResult = await client.ConnectAsync().ConfigureAwait(false); + + // Configure the subscriptions we want and subscribe + var builder = new SubscribeOptionsBuilder(); + var machineName = System.Environment.MachineName; + + // Setup an application message handlers BEFORE subscribing to a topic + client.OnMessageReceived += (sender, args) => + { + if (args.PublishMessage.Topic.EndsWith("brightness")) + { + if (float.TryParse(args.PublishMessage.PayloadAsString, out float newBrightness)) + { + screenDimmerMain.InvokeIfRequired(() => + { + screenDimmerMain.SetCurrentBrightness(newBrightness); + }); + } + } + else + { + var overlay = screenDimmerMain.overlayWindows.Values.FirstOrDefault(o => $"ScreenDimmer/{machineName}/{o.mqReference.cmd_t.Trim('~')}" == args.PublishMessage.Topic); + + if (overlay != null) + { + overlay.cbReference.InvokeIfRequired(() => + { + overlay.cbReference.Checked = args.PublishMessage.PayloadAsString == MQTTService.HASwitchOn; + }); + } + } + }; + + foreach (var scr in screenDimmerMain.overlayWindows.Values) + { + var mqEntity = scr.mqReference; + builder.WithSubscription($"ScreenDimmer/{machineName}/{mqEntity.cmd_t.Trim('~')}", QualityOfService.ExactlyOnceDelivery, true); + var publishResult1 = await client.PublishAsync($"{HABase}/switch/{mqEntity.uniq_id}/config", JsonConvert.SerializeObject(mqEntity)); + } + + + //setup dim value + var brightnessSensor = new HAValue() + { + brightness = screenDimmerMain.GetCurrentBrightness() + }; + builder.WithSubscription($"ScreenDimmer/{machineName}/{brightnessSensor.cmd_t.Trim('~')}", QualityOfService.ExactlyOnceDelivery, true); + var publishResult2 = await client.PublishAsync($"{HABase}/number/{brightnessSensor.uniq_id}/config", JsonConvert.SerializeObject(brightnessSensor)); + + var subscribeOptions = builder.Build(); + var subscribeResult = await client.SubscribeAsync(subscribeOptions); + + //foreach (var scr in screenDimmerMain.overlayWindows.Values) + //{ + // var mqEntity = scr.mqReference; + //} + var publishResult3 = await client.PublishAsync($"ScreenDimmer/{machineName}/mqtt", "connected"); + } + catch (Exception ex) + { + + } + + } + + + } + + + public class HAAvailability + { + public long _timestamp { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + [JsonProperty(PropertyName = "~")] + public string availability { get { return $"ScreenDimmer/{device.name}/"; } } + public string avty_t { get; set; } = "~mqtt"; + public HADevice device { get; set; } = new HADevice(); + public string pl_avail { get; set; } = "connected"; + public string pl_not_avail { get; set; } = "disconnected"; + public string pl_off { get; set; } = MQTTService.HASwitchOff; + public string pl_on { get; set; } = MQTTService.HASwitchOn; + public string uniq_id { get { return $"{device.ids}_{name.ToUpper()}_ENABLED"; } } + public string name { get; set; } + public string stat_t { get { return $"~hassControl_{name.ToUpper()}/state"; } } + public string cmd_t { get { return $"~hassControl_{name.ToUpper()}/state"; } } + public string ha_sensor_type { get; set; } = "switch"; + public string ic { get; set; } = "mdi:monitor-arrow-down-variant"; + } + + + public class HADevice + { + public string ids { get; set; } = GenerateMachineNameHash(); + public string name { get; set; } = Environment.MachineName; + public string mf { get; set; } = "ScreenDimmer"; + public string mdl { get; set; } = "HomeAssistant Discovery for ScreenDimmer"; + public string sw { get; set; } = "HomeAssistant Discovery for ScreenDimmer"; + + + public static string GenerateMachineNameHash() + { + // Get the machine name + string machineName = Environment.MachineName; + + // Create an MD5 instance + using (MD5 md5 = MD5.Create()) + { + // Convert the machine name into a byte array and compute the hash + byte[] inputBytes = Encoding.UTF8.GetBytes(machineName); + byte[] hashBytes = md5.ComputeHash(inputBytes); + + // Convert the byte array to a hexadecimal string + StringBuilder sb = new StringBuilder(); + foreach (byte b in hashBytes) + { + sb.Append(b.ToString("x2")); + } + return sb.ToString(); + } + } + } + + + public class HAValue + { + public long _timestamp { get; set; } = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + [JsonProperty(PropertyName = "~")] + public string availability { get { return $"ScreenDimmer/{device.name}/"; } } + public string avty_t { get; set; } = "~mqtt"; + public HADevice device { get; set; } = new HADevice(); + public string pl_avail { get; set; } = "connected"; + public string pl_not_avail { get; set; } = "disconnected"; + public float brightness { get; set; } = 50; + public string uniq_id { get { return $"{device.ids}_{name.ToUpper()}"; } } + public string name { get; set; } = "Brightness"; + public string stat_t { get { return $"~hassControl_{name.ToUpper()}/brightness"; } } + public string cmd_t { get { return $"~hassControl_{name.ToUpper()}/brightness"; } } + public string ha_sensor_type { get; set; } = "number"; + public string ic { get; set; } = "mdi:emoticon-cool"; + } +} diff --git a/ScreenDimmer/OsdWindow.Designer.cs b/ScreenDimmer/OsdWindow.Designer.cs index 3c2b9d4..d88e654 100644 --- a/ScreenDimmer/OsdWindow.Designer.cs +++ b/ScreenDimmer/OsdWindow.Designer.cs @@ -28,33 +28,32 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.label1 = new System.Windows.Forms.Label(); - this.SuspendLayout(); + label1 = new System.Windows.Forms.Label(); + SuspendLayout(); // // label1 // - this.label1.AutoSize = true; - this.label1.Dock = System.Windows.Forms.DockStyle.Fill; - this.label1.Location = new System.Drawing.Point(0, 0); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(32, 13); - this.label1.TabIndex = 0; - this.label1.Text = "label1"; + label1.AutoSize = true; + label1.Dock = System.Windows.Forms.DockStyle.Fill; + label1.Location = new System.Drawing.Point(0, 0); + label1.Name = "label1"; + label1.Size = new System.Drawing.Size(49, 23); + label1.TabIndex = 0; + label1.Text = "label1"; // // OsdWindow // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.ClientSize = new System.Drawing.Size(284, 261); - this.Controls.Add(this.label1); - this.Font = new System.Drawing.Font("Segoe UI Light", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.Name = "OsdWindow"; - this.Text = "OsdWindow"; - this.ResumeLayout(false); - this.PerformLayout(); - + AutoScaleDimensions = new System.Drawing.SizeF(9F, 23F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + AutoSize = true; + AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + ClientSize = new System.Drawing.Size(284, 261); + Controls.Add(label1); + Font = new System.Drawing.Font("Segoe UI Light", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + Name = "OsdWindow"; + Text = "OsdWindow"; + ResumeLayout(false); + PerformLayout(); } #endregion diff --git a/ScreenDimmer/OsdWindow.cs b/ScreenDimmer/OsdWindow.cs index 2284d64..9630d0c 100644 --- a/ScreenDimmer/OsdWindow.cs +++ b/ScreenDimmer/OsdWindow.cs @@ -20,16 +20,18 @@ public partial class OsdWindow : Form private byte targetOpacity; // 0 - 255 private DateTime effectStartTime; private bool isDisplaying = false; + private ScreenExtended relatedScreen; - public OsdWindow() + public OsdWindow(ScreenExtended screen) { + relatedScreen = screen; InitializeComponent(); initialize(); // Display("Hello World", new Font("Segeo UI", 32), Color.Black, Color.White, //20, 20, 255, 1000, 1000, 2000); } - public void Display(string text, Font font, Color backcolor, Color textcolor, int X, int Y, byte opacity, + public void Display(string text, Font font, Color backcolor, Color textcolor, byte opacity, int fadeInInterval, int delayTime, int fadeOutInterval) { label1.Text = text; @@ -38,7 +40,7 @@ public void Display(string text, Font font, Color backcolor, Color textcolor, in Font = font; BackColor = backcolor; ForeColor = textcolor; - Location = new Point(X, Y); + Location = new Point(relatedScreen.Screen.Bounds.X+20, relatedScreen.Screen.Bounds.Y + 20); targetOpacity = opacity; isDisplaying = true; diff --git a/ScreenDimmer/OsdWindow.resx b/ScreenDimmer/OsdWindow.resx index 29dcb1b..b92c163 100644 --- a/ScreenDimmer/OsdWindow.resx +++ b/ScreenDimmer/OsdWindow.resx @@ -1,17 +1,17 @@  - diff --git a/ScreenDimmer/Overlay.cs b/ScreenDimmer/Overlay.cs new file mode 100644 index 0000000..7e2b3a8 --- /dev/null +++ b/ScreenDimmer/Overlay.cs @@ -0,0 +1,42 @@ +using HiveMQtt.MQTT5.Types; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.Xml; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using System.Xml; + +namespace Augustine.ScreenDimmer +{ + public class Overlay : Form + { + public HAAvailability mqReference; + public CheckboxButton cbReference; + + public Overlay() + { + mqReference = new HAAvailability(); + } + + public Overlay Init() + { + var scr = this.Tag as ScreenExtended; + var deviceName = scr.DeviceName; + mqReference.name = deviceName.Trim('\\').Trim('.').Trim('\\'); + + return this; + } + + public void UpdateMqtt() + { + if (MQTTService.client!=null) + { + var topic = $"ScreenDimmer/{mqReference.device.name}/{mqReference.cmd_t.Trim('~')}"; + MQTTService.client.PublishAsync(topic, cbReference.Checked ? MQTTService.HASwitchOn : MQTTService.HASwitchOff); + } + } + } +} diff --git a/ScreenDimmer/Overlay.resx b/ScreenDimmer/Overlay.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/ScreenDimmer/Overlay.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + \ No newline at end of file diff --git a/ScreenDimmer/Properties/AssemblyInfo.cs b/ScreenDimmer/Properties/AssemblyInfo.cs deleted file mode 100644 index 4122fba..0000000 --- a/ScreenDimmer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Screen Dimmer Free (Enhanced version for Monash CoC)")] -[assembly: AssemblyDescription( -@"As the minimum brightness of a monitor is sometimes still too bright for you to work at night, the original purpose of Screen Dimmer was to simply render a black layer on top of it to even lower the brightness of your screen. - -Screen Dimmer allows you to set the brightness level easily and quickly by using hotkeys. You can also change the color of the overlay layer (e.g. to yellow) to use Screen Dimmer as a blue-light filter to protect your precious eyes. - -Plus, if you works with multiple screens, Screen Dimmer gives you the capablity of dimming the one that you want, with hotkeys! This can be handy when you are giving presentation and want to mute the secondary screen without any accesses in hand. - -Home page: https://github.com/datbnh/ScreenDimmer -Source code (GPL): https://github.com/datbnh/ScreenDimmer -")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Augustine's Software")] -[assembly: AssemblyProduct("Screen Dimmer Free (Enhanced version for Monash CoC)")] -[assembly: AssemblyCopyright("Copyleft (ↄ) Augustine's Software 2015 - 2017")] -[assembly: AssemblyTrademark("Screen Dimmer - Augustine's Software")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("edbe1475-dca5-43d3-8b09-7073d8786a93")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("3.3.*")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ScreenDimmer/Properties/Resources.Designer.cs b/ScreenDimmer/Properties/Resources.Designer.cs index 66a9667..211c9bf 100644 --- a/ScreenDimmer/Properties/Resources.Designer.cs +++ b/ScreenDimmer/Properties/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace Augustine.ScreenDimmer.Properties { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { diff --git a/ScreenDimmer/Properties/Settings.Designer.cs b/ScreenDimmer/Properties/Settings.Designer.cs index da43b4d..9d7c5bc 100644 --- a/ScreenDimmer/Properties/Settings.Designer.cs +++ b/ScreenDimmer/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace Augustine.ScreenDimmer.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "12.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/ScreenDimmer/ScreenDimmer.Designer.cs b/ScreenDimmer/ScreenDimmer.Designer.cs index 377b570..d852a86 100644 --- a/ScreenDimmer/ScreenDimmer.Designer.cs +++ b/ScreenDimmer/ScreenDimmer.Designer.cs @@ -1,6 +1,6 @@ namespace Augustine.ScreenDimmer { - internal partial class ScreenDimmer + public partial class ScreenDimmer { /// /// Required designer variable. @@ -28,486 +28,438 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.components = new System.ComponentModel.Container(); - this.toolTipHint = new System.Windows.Forms.ToolTip(this.components); - this.buttonDim = new System.Windows.Forms.Button(); - this.contextMenuStrip2 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.colorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.labelScreen = new System.Windows.Forms.Label(); - this.labelBrightness = new System.Windows.Forms.Label(); - this.labelExpandCollapse = new System.Windows.Forms.Label(); - this.labelHelp = new System.Windows.Forms.Label(); - this.labelBug = new System.Windows.Forms.Label(); - this.labelAbout = new System.Windows.Forms.Label(); - this.buttonBright = new System.Windows.Forms.Button(); - this.checkBoxZeroBrightness = new System.Windows.Forms.CheckBox(); - this.comboBoxScreens = new System.Windows.Forms.ComboBox(); - this.checkBoxDebug = new System.Windows.Forms.CheckBox(); - this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components); - this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components); - this.controlPanelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); - this.exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); - this.timerEnforceOnTop = new System.Windows.Forms.Timer(this.components); - this.timerFade = new System.Windows.Forms.Timer(this.components); - this.trackBarBrightness = new System.Windows.Forms.TrackBar(); - this.checkBoxEnforceOnTop = new System.Windows.Forms.CheckBox(); - this.label1 = new System.Windows.Forms.Label(); - this.colorDialog1 = new System.Windows.Forms.ColorDialog(); - this.numericUpDown1 = new System.Windows.Forms.NumericUpDown(); - this.toolTipWarning = new System.Windows.Forms.ToolTip(this.components); - this.checkBoxAllowTransition = new System.Windows.Forms.CheckBox(); - this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); - this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); - this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); - this.tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); - this.contextMenuStrip2.SuspendLayout(); - this.contextMenuStrip1.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.trackBarBrightness)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit(); - this.tableLayoutPanel1.SuspendLayout(); - this.tableLayoutPanel2.SuspendLayout(); - this.tableLayoutPanel3.SuspendLayout(); - this.tableLayoutPanel4.SuspendLayout(); - this.SuspendLayout(); + components = new System.ComponentModel.Container(); + toolTipHint = new System.Windows.Forms.ToolTip(components); + buttonDim = new System.Windows.Forms.Button(); + contextMenuStrip2 = new System.Windows.Forms.ContextMenuStrip(components); + colorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + labelBrightness = new System.Windows.Forms.Label(); + labelExpandCollapse = new System.Windows.Forms.Label(); + labelHelp = new System.Windows.Forms.Label(); + labelBug = new System.Windows.Forms.Label(); + labelAbout = new System.Windows.Forms.Label(); + buttonBright = new System.Windows.Forms.Button(); + checkBoxZeroBrightness = new System.Windows.Forms.CheckBox(); + checkBoxDebug = new System.Windows.Forms.CheckBox(); + notifyIcon1 = new System.Windows.Forms.NotifyIcon(components); + contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(components); + controlPanelToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + exitToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + timerEnforceOnTop = new System.Windows.Forms.Timer(components); + timerFade = new System.Windows.Forms.Timer(components); + trackBarBrightness = new System.Windows.Forms.TrackBar(); + checkBoxEnforceOnTop = new System.Windows.Forms.CheckBox(); + label1 = new System.Windows.Forms.Label(); + colorDialog1 = new System.Windows.Forms.ColorDialog(); + numericUpDown1 = new System.Windows.Forms.NumericUpDown(); + toolTipWarning = new System.Windows.Forms.ToolTip(components); + checkBoxAllowTransition = new System.Windows.Forms.CheckBox(); + tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + tableLayoutPanel4 = new System.Windows.Forms.TableLayoutPanel(); + contextMenuStrip2.SuspendLayout(); + contextMenuStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)trackBarBrightness).BeginInit(); + ((System.ComponentModel.ISupportInitialize)numericUpDown1).BeginInit(); + tableLayoutPanel1.SuspendLayout(); + tableLayoutPanel2.SuspendLayout(); + tableLayoutPanel3.SuspendLayout(); + tableLayoutPanel4.SuspendLayout(); + SuspendLayout(); // // toolTipHint // - this.toolTipHint.ShowAlways = true; + toolTipHint.ShowAlways = true; // // buttonDim // - this.buttonDim.AutoSize = true; - this.buttonDim.BackColor = System.Drawing.Color.Black; - this.buttonDim.ContextMenuStrip = this.contextMenuStrip2; - this.buttonDim.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonDim.Dock = System.Windows.Forms.DockStyle.Fill; - this.buttonDim.FlatAppearance.BorderColor = System.Drawing.Color.Gray; - this.buttonDim.FlatAppearance.BorderSize = 0; - this.buttonDim.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.buttonDim.Font = new System.Drawing.Font("Segoe UI Symbol", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.buttonDim.ForeColor = System.Drawing.Color.Gray; - this.buttonDim.Location = new System.Drawing.Point(3, 3); - this.buttonDim.Name = "buttonDim"; - this.buttonDim.Size = new System.Drawing.Size(85, 31); - this.buttonDim.TabIndex = 46; - this.buttonDim.Text = "Dim "; - this.toolTipHint.SetToolTip(this.buttonDim, "Apply minimum brightness.\r\nRight click to change color."); - this.buttonDim.UseVisualStyleBackColor = false; - this.buttonDim.Click += new System.EventHandler(this.buttonDim_Click); + buttonDim.AutoSize = true; + buttonDim.BackColor = System.Drawing.Color.Black; + buttonDim.ContextMenuStrip = contextMenuStrip2; + buttonDim.DialogResult = System.Windows.Forms.DialogResult.Cancel; + buttonDim.Dock = System.Windows.Forms.DockStyle.Fill; + buttonDim.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + buttonDim.FlatAppearance.BorderSize = 0; + buttonDim.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + buttonDim.Font = new System.Drawing.Font("Segoe UI Symbol", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + buttonDim.ForeColor = System.Drawing.Color.Gray; + buttonDim.Location = new System.Drawing.Point(3, 3); + buttonDim.Name = "buttonDim"; + buttonDim.Size = new System.Drawing.Size(116, 35); + buttonDim.TabIndex = 46; + buttonDim.Text = "Dim "; + toolTipHint.SetToolTip(buttonDim, "Apply minimum brightness.\r\nRight click to change color."); + buttonDim.UseVisualStyleBackColor = false; + buttonDim.Click += buttonDim_Click; // // contextMenuStrip2 // - this.contextMenuStrip2.ImageScalingSize = new System.Drawing.Size(20, 20); - this.contextMenuStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.colorToolStripMenuItem}); - this.contextMenuStrip2.Name = "contextMenuStrip2"; - this.contextMenuStrip2.Size = new System.Drawing.Size(113, 26); + contextMenuStrip2.ImageScalingSize = new System.Drawing.Size(20, 20); + contextMenuStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { colorToolStripMenuItem }); + contextMenuStrip2.Name = "contextMenuStrip2"; + contextMenuStrip2.Size = new System.Drawing.Size(140, 36); // // colorToolStripMenuItem // - this.colorToolStripMenuItem.Name = "colorToolStripMenuItem"; - this.colorToolStripMenuItem.Size = new System.Drawing.Size(112, 22); - this.colorToolStripMenuItem.Text = "Color..."; - this.colorToolStripMenuItem.Click += new System.EventHandler(this.colorToolStripMenuItem_Click); - // - // labelScreen - // - this.labelScreen.AutoSize = true; - this.labelScreen.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelScreen.Location = new System.Drawing.Point(3, 32); - this.labelScreen.Name = "labelScreen"; - this.labelScreen.Size = new System.Drawing.Size(22, 27); - this.labelScreen.TabIndex = 44; - this.labelScreen.Text = "📺"; - this.labelScreen.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.toolTipHint.SetToolTip(this.labelScreen, "Screen"); + colorToolStripMenuItem.Name = "colorToolStripMenuItem"; + colorToolStripMenuItem.Size = new System.Drawing.Size(139, 32); + colorToolStripMenuItem.Text = "Color..."; + colorToolStripMenuItem.Click += colorToolStripMenuItem_Click; // // labelBrightness // - this.labelBrightness.AutoSize = true; - this.labelBrightness.Dock = System.Windows.Forms.DockStyle.Fill; - this.labelBrightness.Font = new System.Drawing.Font("Segoe UI Symbol", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelBrightness.Location = new System.Drawing.Point(3, 0); - this.labelBrightness.Name = "labelBrightness"; - this.labelBrightness.Size = new System.Drawing.Size(22, 32); - this.labelBrightness.TabIndex = 1; - this.labelBrightness.Text = ""; - this.labelBrightness.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; - this.toolTipHint.SetToolTip(this.labelBrightness, "Brightness"); + labelBrightness.AutoSize = true; + labelBrightness.Dock = System.Windows.Forms.DockStyle.Fill; + labelBrightness.Font = new System.Drawing.Font("Segoe UI Symbol", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + labelBrightness.Location = new System.Drawing.Point(3, 0); + labelBrightness.Name = "labelBrightness"; + labelBrightness.Size = new System.Drawing.Size(33, 32); + labelBrightness.TabIndex = 1; + labelBrightness.Text = ""; + labelBrightness.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; + toolTipHint.SetToolTip(labelBrightness, "Brightness"); // // labelExpandCollapse // - this.labelExpandCollapse.AutoSize = true; - this.labelExpandCollapse.Cursor = System.Windows.Forms.Cursors.Hand; - this.labelExpandCollapse.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelExpandCollapse.Location = new System.Drawing.Point(166, 102); - this.labelExpandCollapse.Margin = new System.Windows.Forms.Padding(0); - this.labelExpandCollapse.Name = "labelExpandCollapse"; - this.labelExpandCollapse.Size = new System.Drawing.Size(22, 20); - this.labelExpandCollapse.TabIndex = 54; - this.labelExpandCollapse.Text = "▷"; - this.toolTipHint.SetToolTip(this.labelExpandCollapse, "More..."); - this.labelExpandCollapse.Click += new System.EventHandler(this.labelExpandCollapse_Click); + labelExpandCollapse.AutoSize = true; + labelExpandCollapse.Cursor = System.Windows.Forms.Cursors.Hand; + labelExpandCollapse.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + labelExpandCollapse.Location = new System.Drawing.Point(216, 79); + labelExpandCollapse.Margin = new System.Windows.Forms.Padding(0); + labelExpandCollapse.Name = "labelExpandCollapse"; + labelExpandCollapse.Size = new System.Drawing.Size(34, 31); + labelExpandCollapse.TabIndex = 54; + labelExpandCollapse.Text = "▷"; + toolTipHint.SetToolTip(labelExpandCollapse, "More..."); + labelExpandCollapse.Click += labelExpandCollapse_Click; // // labelHelp // - this.labelHelp.AutoSize = true; - this.labelHelp.Cursor = System.Windows.Forms.Cursors.Hand; - this.labelHelp.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelHelp.Location = new System.Drawing.Point(142, 102); - this.labelHelp.Margin = new System.Windows.Forms.Padding(0); - this.labelHelp.Name = "labelHelp"; - this.labelHelp.Size = new System.Drawing.Size(24, 20); - this.labelHelp.TabIndex = 55; - this.labelHelp.Text = "❔"; - this.toolTipHint.SetToolTip(this.labelHelp, "Hotkeys..."); - this.labelHelp.Click += new System.EventHandler(this.labelHelp_Click); + labelHelp.AutoSize = true; + labelHelp.Cursor = System.Windows.Forms.Cursors.Hand; + labelHelp.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + labelHelp.Location = new System.Drawing.Point(170, 79); + labelHelp.Margin = new System.Windows.Forms.Padding(0); + labelHelp.Name = "labelHelp"; + labelHelp.Size = new System.Drawing.Size(46, 31); + labelHelp.TabIndex = 55; + labelHelp.Text = "❔"; + toolTipHint.SetToolTip(labelHelp, "Hotkeys..."); + labelHelp.Click += labelHelp_Click; // // labelBug // - this.labelBug.AutoSize = true; - this.labelBug.Cursor = System.Windows.Forms.Cursors.Hand; - this.labelBug.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelBug.ForeColor = System.Drawing.Color.Maroon; - this.labelBug.Location = new System.Drawing.Point(155, 97); - this.labelBug.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); - this.labelBug.Name = "labelBug"; - this.labelBug.Size = new System.Drawing.Size(24, 20); - this.labelBug.TabIndex = 56; - this.labelBug.Text = "🐞"; - this.toolTipHint.SetToolTip(this.labelBug, "View..."); - this.labelBug.Visible = false; - this.labelBug.Click += new System.EventHandler(this.labelBug_Click); + labelBug.AutoSize = true; + labelBug.Cursor = System.Windows.Forms.Cursors.Hand; + labelBug.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + labelBug.ForeColor = System.Drawing.Color.Maroon; + labelBug.Location = new System.Drawing.Point(221, 134); + labelBug.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); + labelBug.Name = "labelBug"; + labelBug.Size = new System.Drawing.Size(46, 31); + labelBug.TabIndex = 56; + labelBug.Text = "🐞"; + toolTipHint.SetToolTip(labelBug, "View..."); + labelBug.Visible = false; + labelBug.Click += labelBug_Click; // // labelAbout // - this.labelAbout.AutoSize = true; - this.labelAbout.Cursor = System.Windows.Forms.Cursors.Hand; - this.labelAbout.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.labelAbout.Location = new System.Drawing.Point(0, 102); - this.labelAbout.Margin = new System.Windows.Forms.Padding(0); - this.labelAbout.Name = "labelAbout"; - this.labelAbout.Size = new System.Drawing.Size(22, 20); - this.labelAbout.TabIndex = 42; - this.labelAbout.Text = "ⓘ"; - this.labelAbout.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - this.toolTipHint.SetToolTip(this.labelAbout, "About..."); - this.labelAbout.Click += new System.EventHandler(this.labelAbout_Click); + labelAbout.AutoSize = true; + labelAbout.Cursor = System.Windows.Forms.Cursors.Hand; + labelAbout.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + labelAbout.Location = new System.Drawing.Point(0, 79); + labelAbout.Margin = new System.Windows.Forms.Padding(0); + labelAbout.Name = "labelAbout"; + labelAbout.Size = new System.Drawing.Size(34, 31); + labelAbout.TabIndex = 42; + labelAbout.Text = "ⓘ"; + labelAbout.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + toolTipHint.SetToolTip(labelAbout, "About..."); + labelAbout.Click += labelAbout_Click; // // buttonBright // - this.buttonBright.AutoSize = true; - this.buttonBright.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.buttonBright.Dock = System.Windows.Forms.DockStyle.Fill; - this.buttonBright.FlatAppearance.BorderColor = System.Drawing.Color.Gray; - this.buttonBright.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.buttonBright.Font = new System.Drawing.Font("Segoe UI Symbol", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.buttonBright.ForeColor = System.Drawing.Color.Gray; - this.buttonBright.Location = new System.Drawing.Point(94, 3); - this.buttonBright.Name = "buttonBright"; - this.buttonBright.Size = new System.Drawing.Size(85, 31); - this.buttonBright.TabIndex = 45; - this.buttonBright.Text = "Brighten "; - this.toolTipHint.SetToolTip(this.buttonBright, "Apply maximum brightness."); - this.buttonBright.UseVisualStyleBackColor = true; - this.buttonBright.Click += new System.EventHandler(this.buttonBright_Click); + buttonBright.AutoSize = true; + buttonBright.DialogResult = System.Windows.Forms.DialogResult.Cancel; + buttonBright.Dock = System.Windows.Forms.DockStyle.Fill; + buttonBright.FlatAppearance.BorderColor = System.Drawing.Color.Gray; + buttonBright.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + buttonBright.Font = new System.Drawing.Font("Segoe UI Symbol", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + buttonBright.ForeColor = System.Drawing.Color.Gray; + buttonBright.Location = new System.Drawing.Point(125, 3); + buttonBright.Name = "buttonBright"; + buttonBright.Size = new System.Drawing.Size(116, 35); + buttonBright.TabIndex = 45; + buttonBright.Text = "Brighten "; + toolTipHint.SetToolTip(buttonBright, "Apply maximum brightness."); + buttonBright.UseVisualStyleBackColor = true; + buttonBright.Click += buttonBright_Click; // // checkBoxZeroBrightness // - this.checkBoxZeroBrightness.AutoSize = true; - this.tableLayoutPanel3.SetColumnSpan(this.checkBoxZeroBrightness, 2); - this.checkBoxZeroBrightness.Location = new System.Drawing.Point(3, 3); - this.checkBoxZeroBrightness.Name = "checkBoxZeroBrightness"; - this.checkBoxZeroBrightness.Size = new System.Drawing.Size(139, 17); - this.checkBoxZeroBrightness.TabIndex = 47; - this.checkBoxZeroBrightness.Text = "Allow Zero Brightness"; - this.toolTipWarning.SetToolTip(this.checkBoxZeroBrightness, "When setting brightness to zero, the screen will be completely dimmed with select" + - "ed color!"); - this.checkBoxZeroBrightness.UseVisualStyleBackColor = true; - this.checkBoxZeroBrightness.CheckedChanged += new System.EventHandler(this.checkBoxZeroBrightness_CheckedChanged); - // - // comboBoxScreens - // - this.comboBoxScreens.BackColor = System.Drawing.SystemColors.Menu; - this.tableLayoutPanel1.SetColumnSpan(this.comboBoxScreens, 3); - this.comboBoxScreens.Dock = System.Windows.Forms.DockStyle.Top; - this.comboBoxScreens.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; - this.comboBoxScreens.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.comboBoxScreens.Location = new System.Drawing.Point(31, 35); - this.comboBoxScreens.Name = "comboBoxScreens"; - this.comboBoxScreens.Size = new System.Drawing.Size(154, 21); - this.comboBoxScreens.TabIndex = 43; - this.comboBoxScreens.DropDown += new System.EventHandler(this.comboBoxScreens_DropDown); - this.comboBoxScreens.SelectedIndexChanged += new System.EventHandler(this.comboBoxScreens_SelectedIndexChanged); + checkBoxZeroBrightness.AutoSize = true; + tableLayoutPanel3.SetColumnSpan(checkBoxZeroBrightness, 2); + checkBoxZeroBrightness.Location = new System.Drawing.Point(3, 3); + checkBoxZeroBrightness.Name = "checkBoxZeroBrightness"; + checkBoxZeroBrightness.Size = new System.Drawing.Size(201, 27); + checkBoxZeroBrightness.TabIndex = 47; + checkBoxZeroBrightness.Text = "Allow Zero Brightness"; + toolTipWarning.SetToolTip(checkBoxZeroBrightness, "When setting brightness to zero, the screen will be completely dimmed with selected color!"); + checkBoxZeroBrightness.UseVisualStyleBackColor = true; + checkBoxZeroBrightness.CheckedChanged += checkBoxZeroBrightness_CheckedChanged; // // checkBoxDebug // - this.checkBoxDebug.AutoSize = true; - this.checkBoxDebug.Location = new System.Drawing.Point(3, 100); - this.checkBoxDebug.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); - this.checkBoxDebug.Name = "checkBoxDebug"; - this.checkBoxDebug.Size = new System.Drawing.Size(107, 17); - this.checkBoxDebug.TabIndex = 41; - this.checkBoxDebug.Text = "Log Debug Info"; - this.checkBoxDebug.UseVisualStyleBackColor = true; - this.checkBoxDebug.Visible = false; + checkBoxDebug.AutoSize = true; + checkBoxDebug.Location = new System.Drawing.Point(3, 137); + checkBoxDebug.Margin = new System.Windows.Forms.Padding(3, 3, 0, 3); + checkBoxDebug.Name = "checkBoxDebug"; + checkBoxDebug.Size = new System.Drawing.Size(155, 27); + checkBoxDebug.TabIndex = 41; + checkBoxDebug.Text = "Log Debug Info"; + checkBoxDebug.UseVisualStyleBackColor = true; + checkBoxDebug.Visible = false; // // notifyIcon1 // - this.notifyIcon1.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info; - this.notifyIcon1.BalloonTipText = "Screen Dimmer is Running Here!"; - this.notifyIcon1.BalloonTipTitle = "Screen Dimmer"; - this.notifyIcon1.ContextMenuStrip = this.contextMenuStrip1; - this.notifyIcon1.Text = "Screen Dimmer"; - this.notifyIcon1.Visible = true; - this.notifyIcon1.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon1_MouseDoubleClick); + notifyIcon1.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info; + notifyIcon1.BalloonTipText = "Screen Dimmer is Running Here!"; + notifyIcon1.BalloonTipTitle = "Screen Dimmer"; + notifyIcon1.ContextMenuStrip = contextMenuStrip1; + notifyIcon1.Text = "Screen Dimmer"; + notifyIcon1.Visible = true; + notifyIcon1.MouseDoubleClick += notifyIcon1_MouseDoubleClick; // // contextMenuStrip1 // - this.contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); - this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.controlPanelToolStripMenuItem, - this.toolStripSeparator1, - this.exitToolStripMenuItem}); - this.contextMenuStrip1.Name = "contextMenuStrip1"; - this.contextMenuStrip1.Size = new System.Drawing.Size(147, 54); + contextMenuStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); + contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { controlPanelToolStripMenuItem, toolStripSeparator1, exitToolStripMenuItem }); + contextMenuStrip1.Name = "contextMenuStrip1"; + contextMenuStrip1.Size = new System.Drawing.Size(190, 74); // // controlPanelToolStripMenuItem // - this.controlPanelToolStripMenuItem.Name = "controlPanelToolStripMenuItem"; - this.controlPanelToolStripMenuItem.Size = new System.Drawing.Size(146, 22); - this.controlPanelToolStripMenuItem.Text = "Control Panel"; - this.controlPanelToolStripMenuItem.Click += new System.EventHandler(this.controlPanelToolStripMenuItem_Click); + controlPanelToolStripMenuItem.Name = "controlPanelToolStripMenuItem"; + controlPanelToolStripMenuItem.Size = new System.Drawing.Size(189, 32); + controlPanelToolStripMenuItem.Text = "Control Panel"; + controlPanelToolStripMenuItem.Click += controlPanelToolStripMenuItem_Click; // // toolStripSeparator1 // - this.toolStripSeparator1.Name = "toolStripSeparator1"; - this.toolStripSeparator1.Size = new System.Drawing.Size(143, 6); + toolStripSeparator1.Name = "toolStripSeparator1"; + toolStripSeparator1.Size = new System.Drawing.Size(186, 6); // // exitToolStripMenuItem // - this.exitToolStripMenuItem.Name = "exitToolStripMenuItem"; - this.exitToolStripMenuItem.Size = new System.Drawing.Size(146, 22); - this.exitToolStripMenuItem.Text = "Exit"; - this.exitToolStripMenuItem.Click += new System.EventHandler(this.exitToolStripMenuItem_Click); + exitToolStripMenuItem.Name = "exitToolStripMenuItem"; + exitToolStripMenuItem.Size = new System.Drawing.Size(189, 32); + exitToolStripMenuItem.Text = "Exit"; + exitToolStripMenuItem.Click += exitToolStripMenuItem_Click; // // timerEnforceOnTop // - this.timerEnforceOnTop.Interval = 30000; - this.timerEnforceOnTop.Tick += new System.EventHandler(this.timerEnforceOnTop_Tick); + timerEnforceOnTop.Interval = 30000; + timerEnforceOnTop.Tick += timerEnforceOnTop_Tick; // // timerFade // - this.timerFade.Interval = 40; - this.timerFade.Tick += new System.EventHandler(this.timerFade_Tick); + timerFade.Interval = 40; + timerFade.Tick += timerFade_Tick; // // trackBarBrightness // - this.trackBarBrightness.AutoSize = false; - this.tableLayoutPanel1.SetColumnSpan(this.trackBarBrightness, 3); - this.trackBarBrightness.Dock = System.Windows.Forms.DockStyle.Top; - this.trackBarBrightness.LargeChange = 20; - this.trackBarBrightness.Location = new System.Drawing.Point(31, 3); - this.trackBarBrightness.Maximum = 100; - this.trackBarBrightness.Minimum = 20; - this.trackBarBrightness.Name = "trackBarBrightness"; - this.trackBarBrightness.Size = new System.Drawing.Size(154, 26); - this.trackBarBrightness.SmallChange = 10; - this.trackBarBrightness.TabIndex = 30; - this.trackBarBrightness.TickFrequency = 10; - this.trackBarBrightness.Value = 45; - this.trackBarBrightness.ValueChanged += new System.EventHandler(this.trackBarBrightness_ValueChanged); + trackBarBrightness.AutoSize = false; + tableLayoutPanel1.SetColumnSpan(trackBarBrightness, 3); + trackBarBrightness.Dock = System.Windows.Forms.DockStyle.Top; + trackBarBrightness.LargeChange = 20; + trackBarBrightness.Location = new System.Drawing.Point(42, 3); + trackBarBrightness.Maximum = 100; + trackBarBrightness.Minimum = 20; + trackBarBrightness.Name = "trackBarBrightness"; + trackBarBrightness.Size = new System.Drawing.Size(205, 26); + trackBarBrightness.SmallChange = 10; + trackBarBrightness.TabIndex = 30; + trackBarBrightness.TickFrequency = 10; + trackBarBrightness.Value = 45; + trackBarBrightness.ValueChanged += trackBarBrightness_ValueChanged; // // checkBoxEnforceOnTop // - this.checkBoxEnforceOnTop.AutoSize = true; - this.checkBoxEnforceOnTop.Location = new System.Drawing.Point(3, 26); - this.checkBoxEnforceOnTop.Name = "checkBoxEnforceOnTop"; - this.checkBoxEnforceOnTop.Size = new System.Drawing.Size(149, 17); - this.checkBoxEnforceOnTop.TabIndex = 49; - this.checkBoxEnforceOnTop.Text = "Force on Top of Taskbar"; - this.checkBoxEnforceOnTop.UseVisualStyleBackColor = true; - this.checkBoxEnforceOnTop.CheckedChanged += new System.EventHandler(this.checkBoxEnforceOnTop_CheckedChanged); + checkBoxEnforceOnTop.AutoSize = true; + checkBoxEnforceOnTop.Location = new System.Drawing.Point(3, 36); + checkBoxEnforceOnTop.Name = "checkBoxEnforceOnTop"; + checkBoxEnforceOnTop.Size = new System.Drawing.Size(215, 27); + checkBoxEnforceOnTop.TabIndex = 49; + checkBoxEnforceOnTop.Text = "Force on Top of Taskbar"; + checkBoxEnforceOnTop.UseVisualStyleBackColor = true; + checkBoxEnforceOnTop.CheckedChanged += checkBoxEnforceOnTop_CheckedChanged; // // label1 // - this.label1.AutoSize = true; - this.label1.Dock = System.Windows.Forms.DockStyle.Right; - this.label1.Enabled = false; - this.label1.Location = new System.Drawing.Point(5, 46); - this.label1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 6); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(147, 22); - this.label1.TabIndex = 51; - this.label1.Text = "Enforcing Period [seconds]:"; - this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + label1.AutoSize = true; + label1.Dock = System.Windows.Forms.DockStyle.Right; + label1.Enabled = false; + label1.Location = new System.Drawing.Point(3, 66); + label1.Margin = new System.Windows.Forms.Padding(3, 0, 3, 6); + label1.Name = "label1"; + label1.Size = new System.Drawing.Size(215, 29); + label1.TabIndex = 51; + label1.Text = "Enforcing Period [seconds]:"; + label1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; // // colorDialog1 // - this.colorDialog1.FullOpen = true; - this.colorDialog1.SolidColorOnly = true; + colorDialog1.FullOpen = true; + colorDialog1.SolidColorOnly = true; // // numericUpDown1 // - this.numericUpDown1.AutoSize = true; - this.numericUpDown1.Enabled = false; - this.numericUpDown1.Location = new System.Drawing.Point(158, 49); - this.numericUpDown1.Maximum = new decimal(new int[] { - 1800, - 0, - 0, - 0}); - this.numericUpDown1.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.numericUpDown1.Name = "numericUpDown1"; - this.numericUpDown1.Size = new System.Drawing.Size(47, 22); - this.numericUpDown1.TabIndex = 53; - this.numericUpDown1.Value = new decimal(new int[] { - 30, - 0, - 0, - 0}); - this.numericUpDown1.ValueChanged += new System.EventHandler(this.numericUpDown1_ValueChanged); + numericUpDown1.AutoSize = true; + numericUpDown1.Enabled = false; + numericUpDown1.Location = new System.Drawing.Point(224, 69); + numericUpDown1.Maximum = new decimal(new int[] { 1800, 0, 0, 0 }); + numericUpDown1.Minimum = new decimal(new int[] { 1, 0, 0, 0 }); + numericUpDown1.Name = "numericUpDown1"; + numericUpDown1.Size = new System.Drawing.Size(70, 29); + numericUpDown1.TabIndex = 53; + numericUpDown1.Value = new decimal(new int[] { 30, 0, 0, 0 }); + numericUpDown1.ValueChanged += numericUpDown1_ValueChanged; // // toolTipWarning // - this.toolTipWarning.ForeColor = System.Drawing.Color.Maroon; - this.toolTipWarning.ShowAlways = true; - this.toolTipWarning.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Warning; - this.toolTipWarning.ToolTipTitle = "Caution"; + toolTipWarning.ForeColor = System.Drawing.Color.Maroon; + toolTipWarning.ShowAlways = true; + toolTipWarning.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Warning; + toolTipWarning.ToolTipTitle = "Caution"; // // checkBoxAllowTransition // - this.checkBoxAllowTransition.AutoSize = true; - this.tableLayoutPanel3.SetColumnSpan(this.checkBoxAllowTransition, 2); - this.checkBoxAllowTransition.Location = new System.Drawing.Point(3, 77); - this.checkBoxAllowTransition.Name = "checkBoxAllowTransition"; - this.checkBoxAllowTransition.Size = new System.Drawing.Size(115, 17); - this.checkBoxAllowTransition.TabIndex = 57; - this.checkBoxAllowTransition.Text = "Enable Transition"; - this.checkBoxAllowTransition.UseVisualStyleBackColor = true; + checkBoxAllowTransition.AutoSize = true; + tableLayoutPanel3.SetColumnSpan(checkBoxAllowTransition, 2); + checkBoxAllowTransition.Location = new System.Drawing.Point(3, 104); + checkBoxAllowTransition.Name = "checkBoxAllowTransition"; + checkBoxAllowTransition.Size = new System.Drawing.Size(166, 27); + checkBoxAllowTransition.TabIndex = 57; + checkBoxAllowTransition.Text = "Enable Transition"; + checkBoxAllowTransition.UseVisualStyleBackColor = true; // // tableLayoutPanel1 // - this.tableLayoutPanel1.AutoSize = true; - this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.tableLayoutPanel1.ColumnCount = 4; - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel1.Controls.Add(this.tableLayoutPanel2, 0, 2); - this.tableLayoutPanel1.Controls.Add(this.labelBrightness, 0, 0); - this.tableLayoutPanel1.Controls.Add(this.labelScreen, 0, 1); - this.tableLayoutPanel1.Controls.Add(this.trackBarBrightness, 1, 0); - this.tableLayoutPanel1.Controls.Add(this.comboBoxScreens, 1, 1); - this.tableLayoutPanel1.Controls.Add(this.labelExpandCollapse, 3, 3); - this.tableLayoutPanel1.Controls.Add(this.labelHelp, 2, 3); - this.tableLayoutPanel1.Controls.Add(this.labelAbout, 0, 3); - this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); - this.tableLayoutPanel1.Name = "tableLayoutPanel1"; - this.tableLayoutPanel1.RowCount = 4; - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel1.Size = new System.Drawing.Size(188, 122); - this.tableLayoutPanel1.TabIndex = 58; + tableLayoutPanel1.AutoSize = true; + tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + tableLayoutPanel1.ColumnCount = 4; + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel1.Controls.Add(tableLayoutPanel2, 0, 2); + tableLayoutPanel1.Controls.Add(labelBrightness, 0, 0); + tableLayoutPanel1.Controls.Add(trackBarBrightness, 1, 0); + tableLayoutPanel1.Controls.Add(labelExpandCollapse, 3, 3); + tableLayoutPanel1.Controls.Add(labelHelp, 2, 3); + tableLayoutPanel1.Controls.Add(labelAbout, 0, 3); + tableLayoutPanel1.Location = new System.Drawing.Point(3, 3); + tableLayoutPanel1.Name = "tableLayoutPanel1"; + tableLayoutPanel1.RowCount = 4; + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel1.Size = new System.Drawing.Size(250, 110); + tableLayoutPanel1.TabIndex = 58; // // tableLayoutPanel2 // - this.tableLayoutPanel2.AutoSize = true; - this.tableLayoutPanel2.ColumnCount = 2; - this.tableLayoutPanel1.SetColumnSpan(this.tableLayoutPanel2, 4); - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); - this.tableLayoutPanel2.Controls.Add(this.buttonDim, 0, 0); - this.tableLayoutPanel2.Controls.Add(this.buttonBright, 1, 0); - this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; - this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 62); - this.tableLayoutPanel2.Name = "tableLayoutPanel2"; - this.tableLayoutPanel2.RowCount = 1; - this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel2.Size = new System.Drawing.Size(182, 37); - this.tableLayoutPanel2.TabIndex = 59; + tableLayoutPanel2.AutoSize = true; + tableLayoutPanel2.ColumnCount = 2; + tableLayoutPanel1.SetColumnSpan(tableLayoutPanel2, 4); + tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + tableLayoutPanel2.Controls.Add(buttonDim, 0, 0); + tableLayoutPanel2.Controls.Add(buttonBright, 1, 0); + tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + tableLayoutPanel2.Location = new System.Drawing.Point(3, 35); + tableLayoutPanel2.Name = "tableLayoutPanel2"; + tableLayoutPanel2.RowCount = 1; + tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel2.Size = new System.Drawing.Size(244, 41); + tableLayoutPanel2.TabIndex = 59; // // tableLayoutPanel3 // - this.tableLayoutPanel3.AutoSize = true; - this.tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.tableLayoutPanel3.ColumnCount = 2; - this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel3.Controls.Add(this.checkBoxZeroBrightness, 0, 0); - this.tableLayoutPanel3.Controls.Add(this.checkBoxEnforceOnTop, 0, 1); - this.tableLayoutPanel3.Controls.Add(this.numericUpDown1, 1, 2); - this.tableLayoutPanel3.Controls.Add(this.labelBug, 1, 4); - this.tableLayoutPanel3.Controls.Add(this.checkBoxAllowTransition, 0, 3); - this.tableLayoutPanel3.Controls.Add(this.checkBoxDebug, 0, 4); - this.tableLayoutPanel3.Controls.Add(this.label1, 0, 2); - this.tableLayoutPanel3.Location = new System.Drawing.Point(197, 3); - this.tableLayoutPanel3.Name = "tableLayoutPanel3"; - this.tableLayoutPanel3.RowCount = 5; - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); - this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel3.Size = new System.Drawing.Size(208, 120); - this.tableLayoutPanel3.TabIndex = 59; - this.tableLayoutPanel3.Visible = false; + tableLayoutPanel3.AutoSize = true; + tableLayoutPanel3.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + tableLayoutPanel3.ColumnCount = 2; + tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel3.Controls.Add(checkBoxZeroBrightness, 0, 0); + tableLayoutPanel3.Controls.Add(checkBoxEnforceOnTop, 0, 1); + tableLayoutPanel3.Controls.Add(numericUpDown1, 1, 2); + tableLayoutPanel3.Controls.Add(labelBug, 1, 4); + tableLayoutPanel3.Controls.Add(checkBoxAllowTransition, 0, 3); + tableLayoutPanel3.Controls.Add(checkBoxDebug, 0, 4); + tableLayoutPanel3.Controls.Add(label1, 0, 2); + tableLayoutPanel3.Location = new System.Drawing.Point(259, 3); + tableLayoutPanel3.Name = "tableLayoutPanel3"; + tableLayoutPanel3.RowCount = 5; + tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle()); + tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + tableLayoutPanel3.Size = new System.Drawing.Size(297, 167); + tableLayoutPanel3.TabIndex = 59; + tableLayoutPanel3.Visible = false; // // tableLayoutPanel4 // - this.tableLayoutPanel4.AutoSize = true; - this.tableLayoutPanel4.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.tableLayoutPanel4.ColumnCount = 2; - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); - this.tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); - this.tableLayoutPanel4.Controls.Add(this.tableLayoutPanel1, 0, 0); - this.tableLayoutPanel4.Controls.Add(this.tableLayoutPanel3, 1, 0); - this.tableLayoutPanel4.Location = new System.Drawing.Point(3, 3); - this.tableLayoutPanel4.Name = "tableLayoutPanel4"; - this.tableLayoutPanel4.RowCount = 1; - this.tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); - this.tableLayoutPanel4.Size = new System.Drawing.Size(408, 128); - this.tableLayoutPanel4.TabIndex = 60; + tableLayoutPanel4.AutoSize = true; + tableLayoutPanel4.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + tableLayoutPanel4.ColumnCount = 2; + tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + tableLayoutPanel4.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + tableLayoutPanel4.Controls.Add(tableLayoutPanel1, 0, 0); + tableLayoutPanel4.Controls.Add(tableLayoutPanel3, 1, 0); + tableLayoutPanel4.Location = new System.Drawing.Point(3, 3); + tableLayoutPanel4.Name = "tableLayoutPanel4"; + tableLayoutPanel4.RowCount = 1; + tableLayoutPanel4.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + tableLayoutPanel4.Size = new System.Drawing.Size(559, 173); + tableLayoutPanel4.TabIndex = 60; // // ScreenDimmer // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.AutoSize = true; - this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; - this.BackColor = System.Drawing.Color.White; - this.ClientSize = new System.Drawing.Size(430, 153); - this.Controls.Add(this.tableLayoutPanel4); - this.Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; - this.Name = "ScreenDimmer"; - this.Text = "Form1"; - this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.screenDimmer_FormClosing); - this.contextMenuStrip2.ResumeLayout(false); - this.contextMenuStrip1.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.trackBarBrightness)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit(); - this.tableLayoutPanel1.ResumeLayout(false); - this.tableLayoutPanel1.PerformLayout(); - this.tableLayoutPanel2.ResumeLayout(false); - this.tableLayoutPanel2.PerformLayout(); - this.tableLayoutPanel3.ResumeLayout(false); - this.tableLayoutPanel3.PerformLayout(); - this.tableLayoutPanel4.ResumeLayout(false); - this.tableLayoutPanel4.PerformLayout(); - this.ResumeLayout(false); - this.PerformLayout(); - + AutoScaleDimensions = new System.Drawing.SizeF(9F, 23F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + AutoSize = true; + AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + BackColor = System.Drawing.Color.White; + ClientSize = new System.Drawing.Size(430, 153); + Controls.Add(tableLayoutPanel4); + Font = new System.Drawing.Font("Segoe UI", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0); + FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + Name = "ScreenDimmer"; + Text = "Form1"; + FormClosing += screenDimmer_FormClosing; + contextMenuStrip2.ResumeLayout(false); + contextMenuStrip1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)trackBarBrightness).EndInit(); + ((System.ComponentModel.ISupportInitialize)numericUpDown1).EndInit(); + tableLayoutPanel1.ResumeLayout(false); + tableLayoutPanel1.PerformLayout(); + tableLayoutPanel2.ResumeLayout(false); + tableLayoutPanel2.PerformLayout(); + tableLayoutPanel3.ResumeLayout(false); + tableLayoutPanel3.PerformLayout(); + tableLayoutPanel4.ResumeLayout(false); + tableLayoutPanel4.PerformLayout(); + ResumeLayout(false); + PerformLayout(); } #endregion @@ -515,8 +467,6 @@ private void InitializeComponent() private System.Windows.Forms.ToolTip toolTipHint; private System.Windows.Forms.CheckBox checkBoxZeroBrightness; private System.Windows.Forms.Button buttonDim; - private System.Windows.Forms.Label labelScreen; - private System.Windows.Forms.ComboBox comboBoxScreens; private System.Windows.Forms.Label labelAbout; private System.Windows.Forms.CheckBox checkBoxDebug; private System.Windows.Forms.NotifyIcon notifyIcon1; diff --git a/ScreenDimmer/ScreenDimmer.cs b/ScreenDimmer/ScreenDimmer.cs index 3fed4cf..41b0f58 100644 --- a/ScreenDimmer/ScreenDimmer.cs +++ b/ScreenDimmer/ScreenDimmer.cs @@ -1,19 +1,26 @@ -using System; +using HiveMQtt.MQTT5.Types; +using Newtonsoft.Json; +using NLog.LayoutRenderers.Wrappers; +using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Linq; +using System.Management; using System.Reflection; using System.Runtime.InteropServices; +using System.Security.Cryptography.Xml; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using static System.Windows.Forms.VisualStyles.VisualStyleElement.Button; namespace Augustine.ScreenDimmer { - internal partial class ScreenDimmer : Form + public partial class ScreenDimmer : Form { #region private properties /// @@ -25,11 +32,12 @@ internal partial class ScreenDimmer : Form /// /// The overlay window. /// - private Form overlayWindow; + //private Form overlayWindow; + public Dictionary overlayWindows; /// /// The about box. /// - private AboutBox1 aboutBox; + private AboutBox aboutBox; /// /// The help window ("show hotkeys" window). /// @@ -37,7 +45,8 @@ internal partial class ScreenDimmer : Form /// /// The brightness OSD. /// - private OsdWindow osdWindow; + //private OsdWindow osdWindow; + private Dictionary osdWindows; /// /// Contains all the settings. @@ -60,7 +69,7 @@ internal partial class ScreenDimmer : Form /// State variable to decide to refresh the screen list or not. /// private int numberOfScreens = -1; - + // transition effect /// /// The total change in brightness track bar value. @@ -75,7 +84,7 @@ internal partial class ScreenDimmer : Form /// private DateTime fadeStartTime; #endregion - + #region static members /// /// Icon to use in system tray. @@ -87,24 +96,78 @@ internal partial class ScreenDimmer : Form public static readonly Icon IconMediumBright32x32 = TextIcon.CreateTextIcon("\uE286", Color.White, "", 32); #endregion + public float GetCurrentBrightness() => configuration.CurrentBrightness; + public void SetCurrentBrightness(float brightness) { + var managed = Math.Min(trackBarBrightness.Maximum, Math.Max(trackBarBrightness.Minimum, (decimal)brightness)); + this.trackBarBrightness.Value = (int)managed; + } + public ScreenDimmer() { InitializeComponent(); initOverlayWindow(); - - aboutBox = new AboutBox1(); + + + aboutBox = new AboutBox(); helpWindow = new HelpWindow(); configuration = new Configuration(); - osdWindow = new OsdWindow(); + osdWindows = ScreenExtended.AllScreens.ToDictionary(k=>k.DeviceName, v=>new OsdWindow(v)); + // has to be in this order! - populateScreenList(); + initScreenOptions(); loadConfiguration(); hookKeys(); notifyIcon1.Icon = IconMediumBright; Icon = IconMediumBright32x32; - Text = string.Format("Screen Dimmer {0}", Assembly.GetExecutingAssembly().GetName().Version.ToString()); + Text = string.Format("ScreenDimmer-MultiScreen {0}", AboutBox.version.ToString()); + + setBrightness(trackBarBrightness.Value); + + MQTTService.Connect(this); + } + + /// + /// Creates checkboxes for each screen, allows users to only dim certain screens. + /// + /// + public Panel checkboxPanel = new Panel(); + private void initScreenOptions() + { + tableLayoutPanel2.Controls.Add(checkboxPanel); + var top = 10; + var left = 10; + var checkboxSize = 40; + var ratio = 0.03f; + foreach (var screen in ScreenExtended.AllScreens) + { + var checkbox = new CheckboxButton() + { + Tag = screen + }; + checkbox.CheckedChanged += (object sender, EventArgs e) => + { + var cb = sender as CheckboxButton; + var scr = cb.Tag as ScreenExtended; + var screens = getEnabledScreenList(); + overlayWindows[scr.DeviceName].Visible = screens.Contains(scr.DeviceName); + setBrightness(trackBarBrightness.Value); + + overlayWindows[scr.DeviceName].UpdateMqtt(); + }; + + overlayWindows[screen.DeviceName].cbReference = checkbox; + + checkbox.BackColor = Color.Transparent; + + + checkbox.Top = screen.CheckboxBounds.Y; + checkbox.Left = screen.CheckboxBounds.X; + checkbox.Width = screen.CheckboxBounds.Width; + checkbox.Height = screen.CheckboxBounds.Height; + checkboxPanel.Controls.Add(checkbox); + } } /// @@ -112,25 +175,48 @@ public ScreenDimmer() /// private void initOverlayWindow() { - overlayWindow = new Form(); - overlayWindow.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; - overlayWindow.ShowInTaskbar = false; - overlayWindow.Show(); - overlayWindow.WindowState = FormWindowState.Maximized; - enforceOnTop(); - NativeMethods.SetWindowLong(overlayWindow.Handle, NativeMethods.GWL_EXSTYLE, - // get current GWL_EXSTYLE - NativeMethods.GetWindowLong(overlayWindow.Handle, NativeMethods.GWL_EXSTYLE) - // click-through. Need to be combined with see-through. - // Need to recalled if opacity changed by setting Form.Cpacity. - // Using SetLayeredWindowAttributes will not require to recall this. - | (int)ExtendedWindowStyles.WS_EX_LAYERED - // see-through - | (int)ExtendedWindowStyles.WS_EX_TRANSPARENT - // alt+tab invisible, need to set ShowInTaskbar to false. - | (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW); - //NativeMethods.SetLayeredWindowAttributes(overlayWindow.Handle, 0, 192, - // (int)LayeredWindowAttributeFlags.LWA_ALPHA); + overlayWindows = ScreenExtended.AllScreens.ToDictionary(k => k.DeviceName, + (v) => { + + return (new Overlay() + { + FormBorderStyle = System.Windows.Forms.FormBorderStyle.None, + ShowInTaskbar = false, + Visible = false, + Tag = v, + }).Init(); + } + ); + + foreach (var window in overlayWindows) + { + window.Value.Load += (object sender, EventArgs e) => { + var overlay = (sender as Form); + var screen = overlay.Tag as ScreenExtended; + overlay.Top = screen.Bounds.Top; + overlay.Left = screen.Bounds.Left; + overlay.Width = screen.Bounds.Width; + overlay.Height = screen.Bounds.Height; + overlay.WindowState = FormWindowState.Maximized; + overlay.TopMost = true; + }; + window.Value.Show(); + NativeMethods.SetWindowLong(window.Value.Handle, NativeMethods.GWL_EXSTYLE, + // get current GWL_EXSTYLE + NativeMethods.GetWindowLong(window.Value.Handle, NativeMethods.GWL_EXSTYLE) + // click-through. Need to be combined with see-through. + // Need to recalled if opacity changed by setting Form.Cpacity. + // Using SetLayeredWindowAttributes will not require to recall this. + | (int)ExtendedWindowStyles.WS_EX_LAYERED + // see-through + | (int)ExtendedWindowStyles.WS_EX_TRANSPARENT + // alt+tab invisible, need to set ShowInTaskbar to false. + | (int)ExtendedWindowStyles.WS_EX_TOOLWINDOW); + //NativeMethods.SetLayeredWindowAttributes(overlayWindow.Handle, 0, 192, + // (int)LayeredWindowAttributeFlags.LWA_ALPHA); + } + + TopMost = true; } #region hotkey management @@ -138,21 +224,25 @@ private void initOverlayWindow() /// Tries to register all the global hotkeys. /// (!) Has to be called after loading configuration (when the hotkeys are defined). /// - private void hookKeys() - { - StringBuilder sb = new StringBuilder(); - bool success = true; - success &= tryHookKeyAppendError(configuration.HotKeyIncreaseBrightness, ref sb); - success &= tryHookKeyAppendError(configuration.HotKeyDecreaseBrightness, ref sb); - success &= tryHookKeyAppendError(configuration.HotKeyBrighten, ref sb); - success &= tryHookKeyAppendError(configuration.HotKeyDim, ref sb); - success &= tryHookKeyAppendError(configuration.HotKeyForceOnTop, ref sb); - success &= tryHookKeyAppendError(configuration.HotKeyHalt, ref sb); - if (!success) - { - notifyIcon1.ShowBalloonTip(0, "Cannot register one or more hotkeys.", sb.ToString(), ToolTipIcon.Warning); - } - } + private void hookKeys() + { + StringBuilder sb = new StringBuilder(); + bool success = true; + success &= tryHookKeysAppendError(new[] + { + configuration.HotKeyIncreaseBrightness, + configuration.HotKeyDecreaseBrightness, + configuration.HotKeyBrighten, + configuration.HotKeyDim, + configuration.HotKeyForceOnTop, + configuration.HotKeyHalt + }, ref sb); + success &= tryHookKeysAppendError(configuration.ScreenToggleHotKeys, ref sb); + if (!success) + { + notifyIcon1.ShowBalloonTip(0, "Cannot register one or more hotkeys.", sb.ToString(), ToolTipIcon.Warning); + } + } /// /// Pupulates the hotkeys on to the help window. @@ -162,11 +252,15 @@ private void populateHotkeys() helpWindow.ResetHotkeyPanel(); helpWindow.AddHotKey(configuration.HotKeyDim); helpWindow.AddHotKey(configuration.HotKeyBrighten); - helpWindow.AddHotKey(configuration.HotKeyIncreaseBrightness); - helpWindow.AddHotKey(configuration.HotKeyDecreaseBrightness); - helpWindow.AddHotKey(configuration.HotKeyForceOnTop); - helpWindow.AddHotKey(configuration.HotKeyHalt); - } + helpWindow.AddHotKey(configuration.HotKeyIncreaseBrightness); + helpWindow.AddHotKey(configuration.HotKeyDecreaseBrightness); + helpWindow.AddHotKey(configuration.HotKeyForceOnTop); + helpWindow.AddHotKey(configuration.HotKeyHalt); + foreach (var hotkey in configuration.ScreenToggleHotKeys) + { + helpWindow.AddHotKey(hotkey); + } + } /// /// Tries to register one hotkey and handle the error message if there are any. @@ -174,19 +268,39 @@ private void populateHotkeys() /// /// /// true if successfully register the hotkey - private bool tryHookKeyAppendError(GlobalHotKey hotkey, ref StringBuilder sb) - { - try - { - hotkey.Register(Handle); - return true; - } + private bool tryHookKeyAppendError(GlobalHotKey hotkey, ref StringBuilder sb) + { + if (hotkey == null) + { + return false; + } + + try + { + hotkey.Register(Handle); + return true; + } catch (Exception e) { sb.AppendLine(e.Message); - } - return false; - } + } + return false; + } + + private bool tryHookKeysAppendError(IEnumerable hotkeys, ref StringBuilder sb) + { + if (hotkeys == null) + { + return true; + } + + bool success = true; + foreach (var hotkey in hotkeys) + { + success &= tryHookKeyAppendError(hotkey, ref sb); + } + return success; + } /// /// WndProc message listener. @@ -230,16 +344,24 @@ protected override void WndProc(ref Message m) { enforceOnTop(); } - else if (hotkeyId == configuration.HotKeyHalt.Id) - { - isContextClose = true; - Close(); - } - break; - } - base.WndProc(ref m); - } - #endregion + else if (hotkeyId == configuration.HotKeyHalt.Id) + { + isContextClose = true; + Close(); + } + else + { + var screenIndex = configuration.ScreenToggleHotKeys.FindIndex(o => o.Id == hotkeyId); + if (screenIndex >= 0) + { + toggleScreenByIndex(screenIndex); + } + } + break; + } + base.WndProc(ref m); + } + #endregion #region color management /// @@ -249,7 +371,8 @@ protected override void WndProc(ref Message m) /// private void colorToolStripMenuItem_Click(object sender, EventArgs e) { - colorDialog1.Color = overlayWindow.BackColor; + foreach (var window in overlayWindows) + colorDialog1.Color = window.Value.BackColor; if (colorDialog1.ShowDialog() == DialogResult.OK) { setDimColor(colorDialog1.Color); @@ -262,16 +385,20 @@ private void colorToolStripMenuItem_Click(object sender, EventArgs e) /// private void setDimColor(Color color) { - buttonDim.BackColor = color; - overlayWindow.BackColor = color; + buttonDim.BackColor = color; + foreach (var window in overlayWindows) + window.Value.BackColor = color; } /// /// Gets the current color of the overlay window. /// /// - private Color getDimColor() { - return overlayWindow.BackColor; + private Color getDimColor() + { + foreach (var window in overlayWindows) //return first for now + return window.Value.BackColor; + return Color.White; } #endregion @@ -304,8 +431,22 @@ private void setTrackBarBrightnessMinimum(int minimum) private void setBrightness(int brightness) { toolTipHint.SetToolTip(trackBarBrightness, string.Format("{0}%", brightness)); - NativeMethods.SetLayeredWindowAttributes(overlayWindow.Handle, 0, (byte)(255 - (brightness / 100f) * 255), - (int)LayeredWindowAttributeFlags.LWA_ALPHA); + + var enabledScreenList = getEnabledScreenList(); + foreach (var window in overlayWindows) + { + var scr = window.Value.Tag as ScreenExtended; + if (enabledScreenList.Contains(scr.DeviceName)) + { + NativeMethods.SetLayeredWindowAttributes(window.Value.Handle, 0, (byte)(255 - (brightness / 100f) * 255), + (int)LayeredWindowAttributeFlags.LWA_ALPHA); + window.Value.Name = "tng"; + } + else + { + window.Value.Visible = false; + } + } } /// @@ -436,78 +577,60 @@ private void buttonBright_Click(object sender, EventArgs e) private void trackBarBrightness_ValueChanged(object sender, EventArgs e) { setBrightness(((TrackBar)sender).Value); - if (!Visible) + var enabledScreenList = getEnabledScreenList(); + + foreach (var osdWindow in osdWindows) { - osdWindow.Display(((TrackBar)sender).Value.ToString() + "%", new Font("Segeo UI", 32), Color.Black, Color.White, 20, 20, 255, 100, 1000, 1000); + if (enabledScreenList.Contains(osdWindow.Key)) + { + osdWindow.Value.Display($"({osdWindow.Key}) {((TrackBar)sender).Value}%", new Font("Segeo UI", 32), Color.Black, Color.White, 255, 100, 1000, 1000); + } } } #endregion - #region screen management - /// - /// Sets the size and position of the form to cover the desired screen. - /// Does nothing if the desired screen index is invalid. - /// + #region screen management + private void toggleScreenByIndex(int screenIndex) + { + if (screenIndex < 0 || screenIndex >= ScreenExtended.AllScreens.Count || screenIndex >= 12) + { + return; + } + + var targetScreen = ScreenExtended.AllScreens[screenIndex]; + foreach (var control in checkboxPanel.Controls) + { + if (control is CheckboxButton cb && cb.Tag is ScreenExtended screen && screen.DeviceName == targetScreen.DeviceName) + { + cb.Toggle(); + return; + } + } + } + + /// + /// Sets the size and position of the form to cover the desired screen. + /// Does nothing if the desired screen index is invalid. + /// /// /// - private void setScreen(Form form, int screenIndex) + private void setScreen(Form form, Screen screen) { - if (Screen.AllScreens.Length - 1 < screenIndex) - { - return; // invalid index - } FormWindowState currentState = form.WindowState; if (currentState != FormWindowState.Normal) { form.WindowState = FormWindowState.Normal; } - form.Location = Screen.AllScreens[screenIndex].WorkingArea.Location; + form.Location = screen.WorkingArea.Location; form.WindowState = currentState; } - - /// - /// Pupulates the sceen list into the combo box. - /// - private void populateScreenList() - { - Screen[] screens = Screen.AllScreens; - if (numberOfScreens != screens.Length) - { - numberOfScreens = screens.Length; - List screensNames = new List(); - foreach (Screen item in screens) - { - screensNames.Add(item.DeviceName); - } - int currentSelected = comboBoxScreens.SelectedIndex; - comboBoxScreens.Items.Clear(); - comboBoxScreens.Items.AddRange(screensNames.ToArray()); - if (currentSelected < numberOfScreens) - { - comboBoxScreens.SelectedIndex = currentSelected; - } - else - { - comboBoxScreens.SelectedIndex = 0; - } - } - } - - private void comboBoxScreens_SelectedIndexChanged(object sender, EventArgs e) - { - setScreen(overlayWindow, ((ComboBox)sender).SelectedIndex); - } - - private void comboBoxScreens_DropDown(object sender, EventArgs e) - { - populateScreenList(); - } #endregion #region configuration management private void saveConfiguration() { uiToConfig(); + saveBrightnesstoMqtt(); configuration.SaveToFile(confFile); } @@ -536,7 +659,7 @@ private void uiToConfig() configuration.IsEnforceOnTop = checkBoxEnforceOnTop.Checked; configuration.IsTransition = checkBoxAllowTransition.Checked; configuration.IsZeroBrightness = checkBoxZeroBrightness.Checked; - configuration.MonitorIndex = (byte) comboBoxScreens.SelectedIndex; + configuration.EnabledScreens = getEnabledScreenList(); } private void configToUi() @@ -566,22 +689,48 @@ private void configToUi() { numericUpDown1.Value = configuration.EnforcingPeriod; } - - if (comboBoxScreens.Items.Count > configuration.MonitorIndex) - { - comboBoxScreens.SelectedIndex = configuration.MonitorIndex; - } - else - { - comboBoxScreens.SelectedIndex = 0; - } setDimColor(configuration.DimColor); checkBoxEnforceOnTop.Checked = configuration.IsEnforceOnTop; checkBoxZeroBrightness.Checked = configuration.IsZeroBrightness; checkBoxDebug.Checked = configuration.IsDebug; checkBoxAllowTransition.Checked = configuration.IsTransition; + + + var EnabledScreens = new List(); + foreach (var control in checkboxPanel.Controls) + { + var cb = control as CheckboxButton; + if (cb != null && cb.Enabled) + { + var scr = cb.Tag as ScreenExtended; + if (configuration.EnabledScreens?.Contains(scr.DeviceName)==true) + { + cb.SetEnable(); + } + } + } + + MQTTService.ConfigHost = configuration.MQTTHostName; + MQTTService.ConfigUserName = configuration.MQTTUsername; + MQTTService.ConfigPassword = configuration.MQTTPassword; + } + + private List getEnabledScreenList() + { + var EnabledScreens = new List(); + foreach (var control in checkboxPanel.Controls) + { + var cb = control as CheckboxButton; + if (cb != null && cb.Checked) + { + var scr = cb.Tag as ScreenExtended; + EnabledScreens.Add(scr.DeviceName); + } + } + return EnabledScreens; } + #endregion #region other UI callbacks @@ -615,7 +764,7 @@ private void timerEnforceOnTop_Tick(object sender, EventArgs e) /// private void enforceOnTop() { - overlayWindow.TopMost = true; // overlay window is set to top most + //overlayWindow.TopMost = true; // overlay window is set to top most TopMost = true; // main form has to be on top of overlay window } @@ -636,7 +785,7 @@ private void numericUpDown1_ValueChanged(object sender, EventArgs e) /// private void checkBoxEnforceOnTop_CheckedChanged(object sender, EventArgs e) { - bool isEnabled = ((CheckBox)sender).Checked; + bool isEnabled = ((System.Windows.Forms.CheckBox)sender).Checked; numericUpDown1.Enabled = isEnabled; label1.Enabled = isEnabled; if (isEnabled) @@ -698,5 +847,29 @@ private void exitToolStripMenuItem_Click(object sender, EventArgs e) Close(); } #endregion + + private void button1_Click(object sender, EventArgs e) + { + foreach (var window in overlayWindows) + { + var screen = window.Value.Tag as ScreenExtended; + window.Value.Top = screen.Bounds.Top; + window.Value.Left = screen.Bounds.Left; + window.Value.Width = screen.Bounds.Width; + window.Value.Height = screen.Bounds.Height; + } + } + + public void saveBrightnesstoMqtt() + { + var brightnessSensor = new HAValue() + { + brightness = GetCurrentBrightness() + }; + + var topic = $"{MQTTService.AppBase}/{brightnessSensor.device.name}/{brightnessSensor.cmd_t.Trim('~')}"; + + var publishResult = MQTTService.client.PublishAsync(topic, JsonConvert.SerializeObject(brightnessSensor.brightness)); + } } } diff --git a/ScreenDimmer/ScreenDimmer.csproj b/ScreenDimmer/ScreenDimmer.csproj index 2053ca1..36e2724 100644 --- a/ScreenDimmer/ScreenDimmer.csproj +++ b/ScreenDimmer/ScreenDimmer.csproj @@ -1,127 +1,40 @@ - - - + - Debug - AnyCPU - {D4C8496F-0990-44B6-A60D-5BB154045873} + net8.0-windows WinExe - Properties Augustine.ScreenDimmer - ScreenDimmer - v4.5 - 512 + false + true + true + 1.0.0.0 + 1.0.0.0 + 1.0.0 - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 + + False - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - true + + False - - - - - - - - - - - + + + + + + - - Form - - - AboutBox1.cs - - - - - - Form - - - HelpWindow.cs - - - Form - - - OsdWindow.cs - - - Form - - - ScreenDimmer.cs - - - - - - - - - AboutBox1.cs - - - HelpWindow.cs - - - OsdWindow.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - ScreenDimmer.cs - - - SettingsSingleFileGenerator - Settings.Designer.cs - - + + True True Settings.settings - True - + + SettingsSingleFileGenerator + Settings.Designer.cs + - - \ No newline at end of file diff --git a/ScreenDimmer/ScreenDimmer.csproj.user b/ScreenDimmer/ScreenDimmer.csproj.user new file mode 100644 index 0000000..df4288d --- /dev/null +++ b/ScreenDimmer/ScreenDimmer.csproj.user @@ -0,0 +1,24 @@ + + + + + + Form + + + Component + + + Form + + + Form + + + Form + + + Form + + + \ No newline at end of file diff --git a/ScreenDimmer/ScreenDimmer.resx b/ScreenDimmer/ScreenDimmer.resx index 03a4859..dea91bc 100644 --- a/ScreenDimmer/ScreenDimmer.resx +++ b/ScreenDimmer/ScreenDimmer.resx @@ -1,17 +1,17 @@  - @@ -141,4 +141,7 @@ 175, 17 + + 278, 56 + \ No newline at end of file diff --git a/ScreenDimmer/ScreenDimmer.sln b/ScreenDimmer/ScreenDimmer.sln new file mode 100644 index 0000000..05ee3d9 --- /dev/null +++ b/ScreenDimmer/ScreenDimmer.sln @@ -0,0 +1,24 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScreenDimmer", "ScreenDimmer.csproj", "{04993518-A056-EA78-E0A9-BDC91D38C393}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {04993518-A056-EA78-E0A9-BDC91D38C393}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {04993518-A056-EA78-E0A9-BDC91D38C393}.Debug|Any CPU.Build.0 = Debug|Any CPU + {04993518-A056-EA78-E0A9-BDC91D38C393}.Release|Any CPU.ActiveCfg = Release|Any CPU + {04993518-A056-EA78-E0A9-BDC91D38C393}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2FF5D9BC-AE49-49F0-95D2-0B46EDCE00C2} + EndGlobalSection +EndGlobal diff --git a/ScreenDimmer/ScreenExtended.cs b/ScreenDimmer/ScreenExtended.cs new file mode 100644 index 0000000..90eb6bf --- /dev/null +++ b/ScreenDimmer/ScreenExtended.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Management; +using System.Text; +using System.Windows.Forms; + +namespace Augustine.ScreenDimmer +{ + public class ScreenExtended + { + private static List ScreenList; + + // Store a reference to the wrapped Screen object + public Screen Screen { get; private set; } + + public string MOName { get; set; } + + public string MODeviceID { get; set; } + + public string MOPNPDeviceID { get; set; } + + public VBounds CheckboxBounds { get; set; } = new VBounds(); + + // Constructor takes a Screen object as a parameter + public ScreenExtended(Screen screen) + { + Screen = screen ?? throw new ArgumentNullException(nameof(screen)); + } + + public static List GetScreenExtendeds() + { + ManagementScope scope = new ManagementScope($"\\\\localhost\\root\\WMI"); + scope.Connect(); // Connect to the specified computer + ObjectQuery query = new ObjectQuery("SELECT * FROM WMIMonitorID"); + ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query); + + var screenList = new List(); + + var ts = SystemInformation.MonitorCount; + + List logs = new List(); + + var index = 0; + foreach (var monitor in searcher.Get()) + { + var uint16Array = monitor["SerialNumberID"] as UInt16[]; + var byteArray = new byte[uint16Array.Length * 2]; + Buffer.BlockCopy(uint16Array, 0, byteArray, 0, byteArray.Length); + var SerialNumberID = byteArray != null ? Encoding.Unicode.GetString(byteArray).Trim('\0') : ""; + var InstanceName = monitor["InstanceName"].ToString(); + logs.Add($"{SerialNumberID}, {InstanceName}"); + var screen = Screen.AllScreens[index]; + + screenList.Add(new ScreenExtended(screen) + { + MOPNPDeviceID = SerialNumberID, + MODeviceID = InstanceName, + MOName = InstanceName + }); + index++; + } + + return screenList; + } + + public string DeviceName => $"DSP_{CheckboxBounds.GridX}x{CheckboxBounds.GridY}"; + + public System.Drawing.Rectangle Bounds => Screen.Bounds; + + public static List AllScreens { + get { + if (ScreenList == null) + ScreenList = CalculateCheckboxPosition(GetScreenExtendeds()); + return ScreenList; + } + } + public static List CalculateCheckboxPosition(List screens) + { + if (screens == null || screens.Count == 0) + return screens; + + var minWidth = screens.Min(s => s.Screen.Bounds.Width); + var minHeight = screens.Min(s => s.Screen.Bounds.Height); + + var minWidthHalf = minWidth * 0.5;/// 2.0f; + var minHeightHalf = minHeight * 0.5;// / 2.0f; + + + int checkboxSize = CheckboxButton.DefaultSize; + + //put in basic grid + foreach (var w in screens) + { + var center = w.CenterPoint(); + var xcell = (float)(center.X) / (float)minWidth; + var ycell = (float)(center.Y) / (float)minHeight; + + w.CheckboxBounds.GridX = (int)xcell; + w.CheckboxBounds.GridY = (int)ycell; + } + + //move grid to positive side + var minX = screens.Min(s => s.CheckboxBounds.GridX); + var minY = screens.Min(s => s.CheckboxBounds.GridY); + foreach (var w in screens) + { + w.CheckboxBounds.GridX -= minX; + w.CheckboxBounds.GridY -= minY; + } + + //remove "blank" columns and rows + var maxX = screens.Max(s => s.CheckboxBounds.GridX); + var maxY = screens.Max(s => s.CheckboxBounds.GridY); + + for(int i = maxX; i > 0; i--) + { + var blankColumns = screens.Any(o => o.CheckboxBounds.GridX == i); + if (!blankColumns) + { + foreach (var scr in screens.Where(o => o.CheckboxBounds.GridX > i)) + scr.CheckboxBounds.GridX -= 1;//remove + } + } + + for (int i = maxY; i > 0; i--) + { + var blankRows = screens.Any(o => o.CheckboxBounds.GridY == i); + if (!blankRows) + { + foreach (var scr in screens.Where(o => o.CheckboxBounds.GridY > i)) + scr.CheckboxBounds.GridY -= 1;//remove + } + } + + foreach (var scr in screens) + { + scr.CheckboxBounds.X = (int)(scr.CheckboxBounds.GridX * checkboxSize); + scr.CheckboxBounds.Y = (int)(scr.CheckboxBounds.GridY * checkboxSize); //rowIndex * checkboxSize; + scr.CheckboxBounds.Width = checkboxSize; + scr.CheckboxBounds.Height = checkboxSize; + } + + return screens + .OrderBy(s => s.CheckboxBounds.GridY) + .ThenBy(s => s.CheckboxBounds.GridX) + .ThenBy(s => s.Bounds.X) + .ThenBy(s => s.Bounds.Y) + .ThenBy(s => s.Bounds.Width) + .ThenBy(s => s.Bounds.Height) + .ThenBy(s => s.MODeviceID ?? string.Empty) + .ToList(); + } + public override string ToString() + { + return $"{CheckboxBounds.X},{CheckboxBounds.Y}"; + } + + public Point CenterPoint() + { + var rect = Bounds; + int centerX = rect.X; + int centerY = rect.Y; + return new Point(centerX, centerY); + } + + public class VBounds + { + public int X; + public int Y; + public int Width; + public int Height; + + public int GridX; + public int GridY; + + public override string ToString() + { + return $"{X},{Y}"; + } + } + + + } +} diff --git a/ScreenDimmer/Serializer.cs b/ScreenDimmer/Serializer.cs index b4c3c43..8682277 100644 --- a/ScreenDimmer/Serializer.cs +++ b/ScreenDimmer/Serializer.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -18,16 +19,8 @@ public static void SerializeObject(T serializableObject, string fileName) try { - XmlDocument xmlDocument = new XmlDocument(); - DataContractSerializer serializer = new DataContractSerializer(serializableObject.GetType()); - using (MemoryStream stream = new MemoryStream()) - { - serializer.WriteObject(stream, serializableObject); - stream.Position = 0; - xmlDocument.Load(stream); - xmlDocument.Save(fileName); - stream.Close(); - } + var data = JsonConvert.SerializeObject(serializableObject, Newtonsoft.Json.Formatting.Indented); + File.WriteAllText($"{fileName}.json", data); } catch (Exception ex) { @@ -39,32 +32,15 @@ public static T DeSerializeObject(string fileName) { if (string.IsNullOrEmpty(fileName)) { return default(T); } - T objectOut = default(T); - try { - XmlDocument xmlDocument = new XmlDocument(); - xmlDocument.Load(fileName); - string xmlString = xmlDocument.OuterXml; - - using (StringReader read = new StringReader(xmlString)) - { - DataContractSerializer serializer = new DataContractSerializer(typeof(T)); - using (XmlReader reader = new XmlTextReader(read)) - { - objectOut = (T)serializer.ReadObject(reader); - reader.Close(); - } - - read.Close(); - } + var data = File.ReadAllText($"{fileName}.json"); + return JsonConvert.DeserializeObject(data); } catch (Exception ex) { - throw ex; + return default(T); } - - return objectOut; } } } diff --git a/Screenshots/BlueLight Filter.png b/Screenshots/BlueLight Filter.png deleted file mode 100644 index 092b409..0000000 Binary files a/Screenshots/BlueLight Filter.png and /dev/null differ diff --git a/Screenshots/FullBrightness.png b/Screenshots/FullBrightness.png deleted file mode 100644 index 4c9762e..0000000 Binary files a/Screenshots/FullBrightness.png and /dev/null differ diff --git a/Screenshots/Home Assistant Integration.jpg b/Screenshots/Home Assistant Integration.jpg new file mode 100644 index 0000000..197a397 Binary files /dev/null and b/Screenshots/Home Assistant Integration.jpg differ diff --git a/Screenshots/Hotkeys.png b/Screenshots/Hotkeys.png deleted file mode 100644 index 54b4f60..0000000 Binary files a/Screenshots/Hotkeys.png and /dev/null differ diff --git a/Screenshots/Main UI 2.png b/Screenshots/Main UI 2.png deleted file mode 100644 index 7c299ef..0000000 Binary files a/Screenshots/Main UI 2.png and /dev/null differ diff --git a/Screenshots/Main UI.png b/Screenshots/Main UI.png deleted file mode 100644 index cf5537a..0000000 Binary files a/Screenshots/Main UI.png and /dev/null differ diff --git a/Screenshots/OSD.png b/Screenshots/OSD.png deleted file mode 100644 index 048ecc7..0000000 Binary files a/Screenshots/OSD.png and /dev/null differ diff --git a/Screenshots/Screen Layout.jpg b/Screenshots/Screen Layout.jpg new file mode 100644 index 0000000..694cb6b Binary files /dev/null and b/Screenshots/Screen Layout.jpg differ