From 39bd4b8d6661870f8b765103bea8482e9b2cf044 Mon Sep 17 00:00:00 2001 From: molsonkiko <46202915+molsonkiko@users.noreply.github.com> Date: Fri, 28 Apr 2023 12:50:45 -0700 Subject: [PATCH] apply dark mode to all forms automatically Based on https://github.com/kbilsted/NotepadPlusPlusPluginPack.Net/pull/104 Rdipardo did all the hard work here, this is just a refinement. This makes it easy for plugin makers to apply dark mode to all forms. Rather than having to individually select themes to apply for each control, sensible defaults are applied based on each control's type. This PR also allows the color changes to propagate recursively to a form's child forms, if it has any. --- Demo Plugin/NppManagedPluginDemo/Demo.cs | 111 +++++++- .../Forms/DarkModeTestForm.Designer.cs | 236 ++++++++++++++++++ .../Forms/DarkModeTestForm.cs | 28 +++ .../Forms/DarkModeTestForm.resx | 177 +++++++++++++ .../NppManagedPluginDemo/Forms/frmGoToLine.cs | 17 ++ .../Forms/frmGoToLine.designer.cs | 132 +++++----- .../Forms/frmGoToLine.resx | 4 +- .../$projectname$.csproj | 1 + .../PluginInfrastructure/DarkMode.cs | 56 +++++ .../PluginInfrastructure/Docking_h.cs | 1 + .../PluginInfrastructure/Msgs_h.cs | 23 ++ .../PluginInfrastructure/NotepadPPGateway.cs | 4 +- 12 files changed, 728 insertions(+), 62 deletions(-) create mode 100644 Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.Designer.cs create mode 100644 Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.cs create mode 100644 Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.resx create mode 100644 Visual Studio Project Template C#/PluginInfrastructure/DarkMode.cs diff --git a/Demo Plugin/NppManagedPluginDemo/Demo.cs b/Demo Plugin/NppManagedPluginDemo/Demo.cs index 382d0fe..c975eb4 100644 --- a/Demo Plugin/NppManagedPluginDemo/Demo.cs +++ b/Demo Plugin/NppManagedPluginDemo/Demo.cs @@ -2,7 +2,9 @@ using System; using System.IO; using System.Text; +using System.Collections.Generic; using System.Drawing; +using System.Reflection; using System.Threading; using System.Windows.Forms; using System.Drawing.Imaging; @@ -38,7 +40,13 @@ public static void OnNotification(ScNotification notification) { if (notification.Header.Code == (uint)SciMsg.SCN_CHARADDED) { - Kbg.Demo.Namespace.Main.doInsertHtmlCloseTag((char)notification.Character); + Demo.Namespace.Main.doInsertHtmlCloseTag((char)notification.Character); + } + // dark mode (de-)activated + if (notification.Header.Code == (uint)NppMsg.NPPN_DARKMODECHANGED) + { + INotepadPPGateway notepad = new NotepadPPGateway(); + Demo.Namespace.Main.ToggleDarkMode(Demo.Namespace.Main.frmGoToLine, notepad.IsDarkModeEnabled()); } } @@ -57,7 +65,7 @@ class Main static string keyName = "doCloseTag"; static bool doCloseTag = false; static string sessionFilePath = @"C:\text.session"; - static frmGoToLine frmGoToLine = null; + static internal frmGoToLine frmGoToLine = null; static internal int idFrmGotToLine = -1; // toolbar icons @@ -179,6 +187,104 @@ static internal void PluginCleanUp() { Win32.WritePrivateProfileString(sectionName, keyName, doCloseTag ? "1" : "0", iniFilePath); } + + /// + /// Apply dark mode (or re-apply light mode) to the controls of any form.

+ /// This method currently supports colorizing the following types of controls:

+ /// - Buttons

+ /// - Labels

+ /// - LinkLabels

+ /// - ComboBoxes

+ /// - CheckBoxes

+ /// - ListBoxes

+ /// - TreeViews

+ /// Feel free to add more as needed.

+ /// TODO: Figure out best way to customize border colors of controls. + /// https://stackoverflow.com/questions/1445472/how-to-change-the-form-border-color-c + /// may be a lead. + ///
+ /// a Windows Form + /// is Notepad++ dark mode on? + static internal void ToggleDarkMode(Form form, bool isDark) + { + if (form == null) + return; + IntPtr themePtr = notepad.GetDarkModeColors(); + if (isDark && themePtr == IntPtr.Zero) + return; + var theme = (DarkModeColors)Marshal.PtrToStructure(themePtr, typeof(DarkModeColors)); + foreach (Form childForm in form.OwnedForms) + { + // allow possibility that some forms will have other child forms + // JsonTools does this in a couple of places + ToggleDarkMode(childForm, isDark); + } + if (isDark) + { + form.BackColor = NppDarkMode.BGRToColor(theme.Background); + form.ForeColor = NppDarkMode.BGRToColor(theme.Text); + } + else + { + form.ResetForeColor(); + form.ResetBackColor(); + } + foreach (Control ctrl in form.Controls) + { + if (isDark) + { + // this doesn't actually make disabled controls have different colors + // windows forms don't make it easy for the user to choose the + // color of a disabled control. See https://stackoverflow.com/questions/136129/windows-forms-how-do-you-change-the-font-color-for-a-disabled-label + var textTheme = ctrl.Enabled ? theme.Text : theme.DisabledText; + if (ctrl is Button btn) + { + btn.BackColor = NppDarkMode.BGRToColor(theme.SofterBackground); + btn.ForeColor = NppDarkMode.BGRToColor(textTheme); + } + else if (ctrl is LinkLabel llbl) + { + llbl.BackColor = NppDarkMode.BGRToColor(theme.ErrorBackground); + llbl.ForeColor = NppDarkMode.BGRToColor(theme.DarkerText); + llbl.LinkColor = NppDarkMode.BGRToColor(theme.LinkText); + llbl.ActiveLinkColor = NppDarkMode.BGRToColor(theme.Text); + llbl.VisitedLinkColor = NppDarkMode.BGRToColor(theme.DarkerText); + } + // other common text-based controls + else if (ctrl is TextBox + || ctrl is Label + || ctrl is ListBox + || ctrl is ComboBox) + { + ctrl.BackColor = NppDarkMode.BGRToColor(theme.PureBackground); + ctrl.ForeColor = NppDarkMode.BGRToColor(textTheme); + } + else if (ctrl is TreeView tv) + { + tv.BackColor = NppDarkMode.BGRToColor(theme.HotBackground); + tv.ForeColor = NppDarkMode.BGRToColor(textTheme); + } + else + { + // other controls I haven't thought of yet + ctrl.BackColor = NppDarkMode.BGRToColor(theme.SofterBackground); + ctrl.ForeColor = NppDarkMode.BGRToColor(textTheme); + } + } + else // normal light mode + { + ctrl.ResetForeColor(); + ctrl.ResetBackColor(); + if (ctrl is LinkLabel llbl) + { + llbl.LinkColor = Color.Blue; + llbl.ActiveLinkColor = Color.Red; + llbl.VisitedLinkColor = Color.Purple; + } + } + } + Marshal.FreeHGlobal(themePtr); + } #endregion #region " Menu functions " @@ -443,6 +549,7 @@ static void DockableDlgDemo() Win32.SendMessage(PluginBase.nppData._nppHandle, (uint) NppMsg.NPPM_SETMENUITEMCHECK, PluginBase._funcItems.Items[idFrmGotToLine]._cmdID, 0); } } + ToggleDarkMode(frmGoToLine, notepad.IsDarkModeEnabled()); frmGoToLine.textBox1.Focus(); } diff --git a/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.Designer.cs b/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.Designer.cs new file mode 100644 index 0000000..e223178 --- /dev/null +++ b/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.Designer.cs @@ -0,0 +1,236 @@ +namespace Kbg.Demo.Namespace +{ + partial class DarkModeTestForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + System.Windows.Forms.TreeNode treeNode8 = new System.Windows.Forms.TreeNode("Node6"); + System.Windows.Forms.TreeNode treeNode9 = new System.Windows.Forms.TreeNode("Node4", new System.Windows.Forms.TreeNode[] { + treeNode8}); + System.Windows.Forms.TreeNode treeNode10 = new System.Windows.Forms.TreeNode("Node5", 2, 2); + System.Windows.Forms.TreeNode treeNode11 = new System.Windows.Forms.TreeNode("Node1", 1, 1, new System.Windows.Forms.TreeNode[] { + treeNode9, + treeNode10}); + System.Windows.Forms.TreeNode treeNode12 = new System.Windows.Forms.TreeNode("Node3", 2, 2); + System.Windows.Forms.TreeNode treeNode13 = new System.Windows.Forms.TreeNode("Node2", 1, 1, new System.Windows.Forms.TreeNode[] { + treeNode12}); + System.Windows.Forms.TreeNode treeNode14 = new System.Windows.Forms.TreeNode("TreeView example", new System.Windows.Forms.TreeNode[] { + treeNode11, + treeNode13}); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DarkModeTestForm)); + this.button1 = new System.Windows.Forms.Button(); + this.treeView1 = new System.Windows.Forms.TreeView(); + this.listBox1 = new System.Windows.Forms.ListBox(); + this.Title = new System.Windows.Forms.Label(); + this.comboBox1 = new System.Windows.Forms.ComboBox(); + this.linkLabel1 = new System.Windows.Forms.LinkLabel(); + this.label1 = new System.Windows.Forms.Label(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.textBox2 = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // button1 + // + this.button1.Location = new System.Drawing.Point(217, 301); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 0; + this.button1.Text = "button1"; + this.button1.UseVisualStyleBackColor = true; + // + // treeView1 + // + this.treeView1.ImageIndex = 0; + this.treeView1.ImageList = this.imageList1; + this.treeView1.Location = new System.Drawing.Point(12, 100); + this.treeView1.Name = "treeView1"; + treeNode8.Name = "Node6"; + treeNode8.Text = "Node6"; + treeNode9.Name = "Node4"; + treeNode9.Text = "Node4"; + treeNode10.ImageIndex = 2; + treeNode10.Name = "Node5"; + treeNode10.SelectedImageIndex = 2; + treeNode10.Text = "Node5"; + treeNode11.ImageIndex = 1; + treeNode11.Name = "Node1"; + treeNode11.SelectedImageIndex = 1; + treeNode11.Text = "Node1"; + treeNode12.ImageIndex = 2; + treeNode12.Name = "Node3"; + treeNode12.SelectedImageIndex = 2; + treeNode12.Text = "Node3"; + treeNode13.ImageIndex = 1; + treeNode13.Name = "Node2"; + treeNode13.SelectedImageIndex = 1; + treeNode13.Text = "Node2"; + treeNode14.Name = "TreeViewRoot"; + treeNode14.Text = "TreeView example"; + this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { + treeNode14}); + this.treeView1.SelectedImageIndex = 0; + this.treeView1.Size = new System.Drawing.Size(178, 135); + this.treeView1.TabIndex = 1; + // + // listBox1 + // + this.listBox1.FormattingEnabled = true; + this.listBox1.ItemHeight = 16; + this.listBox1.Items.AddRange(new object[] { + "listBox1", + "this", + "is", + "a", + "listBox"}); + this.listBox1.Location = new System.Drawing.Point(362, 100); + this.listBox1.Name = "listBox1"; + this.listBox1.SelectionMode = System.Windows.Forms.SelectionMode.MultiSimple; + this.listBox1.Size = new System.Drawing.Size(120, 132); + this.listBox1.TabIndex = 2; + // + // Title + // + this.Title.AutoSize = true; + this.Title.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, ((System.Drawing.FontStyle)((System.Drawing.FontStyle.Bold | System.Drawing.FontStyle.Italic))), System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.Title.Location = new System.Drawing.Point(112, 33); + this.Title.Name = "Title"; + this.Title.Size = new System.Drawing.Size(323, 18); + this.Title.TabIndex = 3; + this.Title.Text = "Each control in this form should look nice"; + // + // comboBox1 + // + this.comboBox1.FormattingEnabled = true; + this.comboBox1.Items.AddRange(new object[] { + "comboBox1", + "this", + "is", + "a", + "comboBox"}); + this.comboBox1.Location = new System.Drawing.Point(217, 98); + this.comboBox1.Name = "comboBox1"; + this.comboBox1.Size = new System.Drawing.Size(121, 24); + this.comboBox1.TabIndex = 4; + // + // linkLabel1 + // + this.linkLabel1.AutoSize = true; + this.linkLabel1.LinkArea = new System.Windows.Forms.LinkArea(0, 10); + this.linkLabel1.Location = new System.Drawing.Point(376, 275); + this.linkLabel1.Name = "linkLabel1"; + this.linkLabel1.Size = new System.Drawing.Size(145, 49); + this.linkLabel1.TabIndex = 5; + this.linkLabel1.TabStop = true; + this.linkLabel1.Text = "linkLabel1\r\nuses ErrorBackground\r\nand DarkerText"; + this.linkLabel1.UseCompatibleTextRendering = true; + this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabel_LinkClicked); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(36, 308); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(105, 16); + this.label1.TabIndex = 6; + this.label1.Text = "A non-bold label"; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Location = new System.Drawing.Point(179, 265); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(173, 20); + this.checkBox1.TabIndex = 7; + this.checkBox1.Text = "checkBox1 looks good?"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // imageList1 + // + this.imageList1.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imageList1.ImageStream"))); + this.imageList1.TransparentColor = System.Drawing.Color.Transparent; + this.imageList1.Images.SetKeyName(0, "star.png"); + this.imageList1.Images.SetKeyName(1, "star_black.ico"); + this.imageList1.Images.SetKeyName(2, "star_white.ico"); + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(217, 190); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(121, 23); + this.textBox1.TabIndex = 8; + this.textBox1.Text = "textBox1"; + // + // textBox2 + // + this.textBox2.Enabled = false; + this.textBox2.Location = new System.Drawing.Point(217, 144); + this.textBox2.Name = "textBox2"; + this.textBox2.Size = new System.Drawing.Size(121, 22); + this.textBox2.TabIndex = 9; + this.textBox2.Text = "disabled textbox"; + // + // DarkModeTestForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(577, 358); + this.Controls.Add(this.textBox2); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.checkBox1); + this.Controls.Add(this.label1); + this.Controls.Add(this.linkLabel1); + this.Controls.Add(this.comboBox1); + this.Controls.Add(this.Title); + this.Controls.Add(this.listBox1); + this.Controls.Add(this.treeView1); + this.Controls.Add(this.button1); + this.Name = "DarkModeTestForm"; + this.Text = "DarkModeTestForm"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button button1; + private System.Windows.Forms.TreeView treeView1; + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.Label Title; + private System.Windows.Forms.ComboBox comboBox1; + private System.Windows.Forms.LinkLabel linkLabel1; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.CheckBox checkBox1; + private System.Windows.Forms.ImageList imageList1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.TextBox textBox2; + } +} \ No newline at end of file diff --git a/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.cs b/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.cs new file mode 100644 index 0000000..a0aeb39 --- /dev/null +++ b/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.cs @@ -0,0 +1,28 @@ +using Kbg.NppPluginNET.PluginInfrastructure; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace Kbg.Demo.Namespace +{ + public partial class DarkModeTestForm : Form + { + public DarkModeTestForm() + { + InitializeComponent(); + var notepad = new NotepadPPGateway(); + Main.ToggleDarkMode(this, notepad.IsDarkModeEnabled()); + comboBox1.SelectedIndex = 0; + } + + private void LinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + linkLabel1.LinkVisited = !linkLabel1.LinkVisited; + } + } +} diff --git a/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.resx b/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.resx new file mode 100644 index 0000000..811e322 --- /dev/null +++ b/Demo Plugin/NppManagedPluginDemo/Forms/DarkModeTestForm.resx @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + + + 17, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w + LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 + ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAADw + CgAAAk1TRnQBSQFMAgEBAwEAAQgBAAEIAQABEAEAARABAAT/AQkBAAj/AUIBTQE2AQQGAAE2AQQCAAEo + AwABQAMAARADAAEBAQABCAYAAQQYAAGAAgABgAMAAoABAAGAAwABgAEAAYABAAKAAgADwAEAAcAB3AHA + AQAB8AHKAaYBAAEzBQABMwEAATMBAAEzAQACMwIAAxYBAAMcAQADIgEAAykBAANVAQADTQEAA0IBAAM5 + AQABgAF8Af8BAAJQAf8BAAGTAQAB1gEAAf8B7AHMAQABxgHWAe8BAAHWAucBAAGQAakBrQIAAf8BMwMA + AWYDAAGZAwABzAIAATMDAAIzAgABMwFmAgABMwGZAgABMwHMAgABMwH/AgABZgMAAWYBMwIAAmYCAAFm + AZkCAAFmAcwCAAFmAf8CAAGZAwABmQEzAgABmQFmAgACmQIAAZkBzAIAAZkB/wIAAcwDAAHMATMCAAHM + AWYCAAHMAZkCAALMAgABzAH/AgAB/wFmAgAB/wGZAgAB/wHMAQABMwH/AgAB/wEAATMBAAEzAQABZgEA + ATMBAAGZAQABMwEAAcwBAAEzAQAB/wEAAf8BMwIAAzMBAAIzAWYBAAIzAZkBAAIzAcwBAAIzAf8BAAEz + AWYCAAEzAWYBMwEAATMCZgEAATMBZgGZAQABMwFmAcwBAAEzAWYB/wEAATMBmQIAATMBmQEzAQABMwGZ + AWYBAAEzApkBAAEzAZkBzAEAATMBmQH/AQABMwHMAgABMwHMATMBAAEzAcwBZgEAATMBzAGZAQABMwLM + AQABMwHMAf8BAAEzAf8BMwEAATMB/wFmAQABMwH/AZkBAAEzAf8BzAEAATMC/wEAAWYDAAFmAQABMwEA + AWYBAAFmAQABZgEAAZkBAAFmAQABzAEAAWYBAAH/AQABZgEzAgABZgIzAQABZgEzAWYBAAFmATMBmQEA + AWYBMwHMAQABZgEzAf8BAAJmAgACZgEzAQADZgEAAmYBmQEAAmYBzAEAAWYBmQIAAWYBmQEzAQABZgGZ + AWYBAAFmApkBAAFmAZkBzAEAAWYBmQH/AQABZgHMAgABZgHMATMBAAFmAcwBmQEAAWYCzAEAAWYBzAH/ + AQABZgH/AgABZgH/ATMBAAFmAf8BmQEAAWYB/wHMAQABzAEAAf8BAAH/AQABzAEAApkCAAGZATMBmQEA + AZkBAAGZAQABmQEAAcwBAAGZAwABmQIzAQABmQEAAWYBAAGZATMBzAEAAZkBAAH/AQABmQFmAgABmQFm + ATMBAAGZATMBZgEAAZkBZgGZAQABmQFmAcwBAAGZATMB/wEAApkBMwEAApkBZgEAA5kBAAKZAcwBAAKZ + Af8BAAGZAcwCAAGZAcwBMwEAAWYBzAFmAQABmQHMAZkBAAGZAswBAAGZAcwB/wEAAZkB/wIAAZkB/wEz + AQABmQHMAWYBAAGZAf8BmQEAAZkB/wHMAQABmQL/AQABzAMAAZkBAAEzAQABzAEAAWYBAAHMAQABmQEA + AcwBAAHMAQABmQEzAgABzAIzAQABzAEzAWYBAAHMATMBmQEAAcwBMwHMAQABzAEzAf8BAAHMAWYCAAHM + AWYBMwEAAZkCZgEAAcwBZgGZAQABzAFmAcwBAAGZAWYB/wEAAcwBmQIAAcwBmQEzAQABzAGZAWYBAAHM + ApkBAAHMAZkBzAEAAcwBmQH/AQACzAIAAswBMwEAAswBZgEAAswBmQEAA8wBAALMAf8BAAHMAf8CAAHM + Af8BMwEAAZkB/wFmAQABzAH/AZkBAAHMAf8BzAEAAcwC/wEAAcwBAAEzAQAB/wEAAWYBAAH/AQABmQEA + AcwBMwIAAf8CMwEAAf8BMwFmAQAB/wEzAZkBAAH/ATMBzAEAAf8BMwH/AQAB/wFmAgAB/wFmATMBAAHM + AmYBAAH/AWYBmQEAAf8BZgHMAQABzAFmAf8BAAH/AZkCAAH/AZkBMwEAAf8BmQFmAQAB/wKZAQAB/wGZ + AcwBAAH/AZkB/wEAAf8BzAIAAf8BzAEzAQAB/wHMAWYBAAH/AcwBmQEAAf8CzAEAAf8BzAH/AQAC/wEz + AQABzAH/AWYBAAL/AZkBAAL/AcwBAAJmAf8BAAFmAf8BZgEAAWYC/wEAAf8CZgEAAf8BZgH/AQAC/wFm + AQABIQEAAaUBAANfAQADdwEAA4YBAAOWAQADywEAA7IBAAPXAQAD3QEAA+MBAAPqAQAD8QEAA/gBAAHw + AfsB/wEAAaQCoAEAA4ADAAH/AgAB/wMAAv8BAAH/AwAB/wEAAf8BAAL/AgAD/wUAAfQBkwFMAUYBJQFM + AZMB9AgAAfQBDgUAAewIAAH0BvEB8hcAAZMBRgclAXQGAAEVAQAB9AUAAe0BAAH0BQAC8QH/BQAB8gHx + AfQTAAH/AW8BRgIlASQEJQEkASUBTAH/AwABDwHrCAAB/wEAAfQDAALyCAAB/wHxAfQSAAGTAUYCJQGU + AUUCJAFGAZkBJAIlAXQCAAGSARQCAAEOAW0CAAH0AQABvAEAAf8DAALyAgAB8QHyAgAB/wHxAfMBAAH/ + AfERAAH0AUwDJQEbAf8BdAGTAf8BGgEkAyUB9AUAARMB8QEAAewBEAEAARACAAHtAewBAAHxAwAB8QH0 + AfEB8gHxAQAB8QIAAvIQAAGTAUYDJQEaBP8BmQEkAyUBdAG8AW0FAAH/AbwBAAEHAfEEAAHzAfIDAAHx + AQAB/wHzAQAB8wH0AwAB8RAAAXQEJQGTBP8BkwEkAyUBTAETAfMDAAFtAf8DAAEOBQAB8gH0AwAB8gH/ + AwAB8QQAAfEQAAFvAyUBbwb/AW8BJAMlAQAB/wIAAeoBbQQAAfQBAAH0AwAB8QH/AgAC8gQAAf8B8QH/ + AgAB8RAAAW8CJQFvCP8BbwIlAUYBDgH/AQABFQHxBwABDgMAAfEB/wEAAfIB9AcAAfEB/wEAAfEQAAF0 + AiUBTAEWAZMBGwL/ARsBkwEWAUwCJQFMAewBBwEAAQcDAAH/AQABDwYAAfIB8wEAAfMD8QH/AQAB8gPx + AgAB8RAAAZMBRgQlAUYC/wFFBSUBdAH/BQAB9AHsBgAB9AEOAf8B8QQAAf8B8gEAAfEEAAH/AfEQAAH0 + AW8FJQIaBSUBRgH0AgAB8wUAAfABvAUAAfQBAAHxAfQEAAHxAvMEAAHxAfQRAAGZAUwEJQJMBCUBRgGT + AgAB/wEAAf8DAAHwARAEAAHrARUCAAH/AfEB/wMAAfMB8gQAAfIB8RIAAf8BdAFMCCUBRgFvAf8DAAHz + AQAB8wcAARQBDwQAAfQB8QH0BwAC8hUAAZkBbwFGBCUBRgFMAZMGAAH/AgABBwL/AfMBbQEAAZIGAAH/ + AvEB8wL/AfQB8gHxAfIXAAH0AZkBdAJvAXQBkwH0CQAB/wHsAQ4BAAETAbwKAAH/AfIC8QHyAfMVAAFC + AU0BPgcAAT4DAAEoAwABQAMAARADAAEBAQABAQUAAYAXAAP/AQAB8AEPAfABDwHwAQ8CAAHgAQcE4wIA + AYABAQHPAfEBzwHxAgABgAEBAZkBiQGZAYkEAAG4ASwBuAEsBAABOgFOAToBTgQAATkB3gE5Ad4EAAEz + AcYBMwHGBAABJwH2AScB8gQAASABhgEgAYYEAAE8AbwBPAG8BAABngE8AZ4BPAIAAYABAQGOAXkBjgF5 + AgABgAEBAccB8wHHAfMCAAHgAQcB4AEHAeABBwIAAfABDwH4AR8B+AEfAgAL + + + \ No newline at end of file diff --git a/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.cs b/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.cs index ba75d36..47d0fc5 100644 --- a/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.cs +++ b/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.cs @@ -8,11 +8,13 @@ namespace Kbg.Demo.Namespace partial class frmGoToLine : Form { private readonly IScintillaGateway editor; + public DarkModeTestForm darkModeTestForm; public frmGoToLine(IScintillaGateway editor) { this.editor = editor; InitializeComponent(); + darkModeTestForm = null; } private void button1_Click(object sender, EventArgs e) @@ -61,5 +63,20 @@ void FrmGoToLineVisibleChanged(object sender, EventArgs e) PluginBase._funcItems.Items[Main.idFrmGotToLine]._cmdID, 0); } } + + private void DarkModeTestFormButton_Click(object sender, EventArgs e) + { + if (darkModeTestForm != null && !darkModeTestForm.IsDisposed) + { + RemoveOwnedForm(darkModeTestForm); + darkModeTestForm.Dispose(); + } + // need to register this as an owned form + // so that Main.ToggleDarkMode can recursively apply dark mode + // to this form. + darkModeTestForm = new DarkModeTestForm(); + darkModeTestForm.Show(); + AddOwnedForm(darkModeTestForm); + } } } diff --git a/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.designer.cs b/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.designer.cs index 0caa768..d9efa89 100644 --- a/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.designer.cs +++ b/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.designer.cs @@ -17,6 +17,8 @@ protected override void Dispose(bool disposing) { components.Dispose(); } + if (darkModeTestForm != null && !darkModeTestForm.IsDisposed) + darkModeTestForm.Dispose(); base.Dispose(disposing); } @@ -28,58 +30,77 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - this.label1 = new System.Windows.Forms.Label(); - this.button1 = new System.Windows.Forms.Button(); - this.textBox1 = new System.Windows.Forms.TextBox(); - this.SuspendLayout(); - // - // label1 - // - this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(12, 9); - this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(55, 13); - this.label1.TabIndex = 0; - this.label1.Text = "Go to line:"; - // - // button1 - // - this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.button1.Location = new System.Drawing.Point(15, 32); - this.button1.Name = "button1"; - this.button1.Size = new System.Drawing.Size(107, 23); - this.button1.TabIndex = 2; - this.button1.Text = "&Go"; - this.button1.UseVisualStyleBackColor = true; - this.button1.Click += new System.EventHandler(this.button1_Click); - this.button1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.frmGoToLine_KeyDown); - // - // textBox1 - // - this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.textBox1.Location = new System.Drawing.Point(73, 6); - this.textBox1.Name = "textBox1"; - this.textBox1.Size = new System.Drawing.Size(49, 20); - this.textBox1.TabIndex = 1; - this.textBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.frmGoToLine_KeyDown); - this.textBox1.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress); - // - // frmGoToLine - // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(139, 70); - this.Controls.Add(this.textBox1); - this.Controls.Add(this.button1); - this.Controls.Add(this.label1); - this.Name = "frmGoToLine"; - this.Text = "NppDockableForm"; - this.VisibleChanged += new System.EventHandler(this.FrmGoToLineVisibleChanged); - this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.frmGoToLine_KeyDown); - this.ResumeLayout(false); - this.PerformLayout(); + this.label1 = new System.Windows.Forms.Label(); + this.button1 = new System.Windows.Forms.Button(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.DarkModeTestFormButton = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(16, 11); + this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(66, 16); + this.label1.TabIndex = 0; + this.label1.Text = "Go to line:"; + // + // button1 + // + this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.button1.Location = new System.Drawing.Point(20, 39); + this.button1.Margin = new System.Windows.Forms.Padding(4); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(143, 28); + this.button1.TabIndex = 2; + this.button1.Text = "&Go"; + this.button1.UseVisualStyleBackColor = true; + this.button1.Click += new System.EventHandler(this.button1_Click); + this.button1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.frmGoToLine_KeyDown); + // + // textBox1 + // + this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.textBox1.Location = new System.Drawing.Point(97, 7); + this.textBox1.Margin = new System.Windows.Forms.Padding(4); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(64, 22); + this.textBox1.TabIndex = 1; + this.textBox1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.frmGoToLine_KeyDown); + this.textBox1.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.textBox1_KeyPress); + // + // DarkModeTestFormButton + // + this.DarkModeTestFormButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.DarkModeTestFormButton.Location = new System.Drawing.Point(20, 84); + this.DarkModeTestFormButton.Name = "DarkModeTestFormButton"; + this.DarkModeTestFormButton.Size = new System.Drawing.Size(143, 32); + this.DarkModeTestFormButton.TabIndex = 3; + this.DarkModeTestFormButton.Text = "Dark mode test form"; + this.DarkModeTestFormButton.UseVisualStyleBackColor = true; + this.DarkModeTestFormButton.Click += new System.EventHandler(this.DarkModeTestFormButton_Click); + // + // frmGoToLine + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(197, 134); + this.Controls.Add(this.DarkModeTestFormButton); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.button1); + this.Controls.Add(this.label1); + this.Margin = new System.Windows.Forms.Padding(4); + this.Name = "frmGoToLine"; + this.Text = "NppDockableForm"; + this.VisibleChanged += new System.EventHandler(this.FrmGoToLineVisibleChanged); + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.frmGoToLine_KeyDown); + this.ResumeLayout(false); + this.PerformLayout(); + } #endregion @@ -87,9 +108,6 @@ private void InitializeComponent() private System.Windows.Forms.Label label1; private System.Windows.Forms.Button button1; internal System.Windows.Forms.TextBox textBox1; - - - - - } + private System.Windows.Forms.Button DarkModeTestFormButton; + } } \ No newline at end of file diff --git a/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.resx b/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.resx index 7080a7d..1af7de1 100644 --- a/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.resx +++ b/Demo Plugin/NppManagedPluginDemo/Forms/frmGoToLine.resx @@ -112,9 +112,9 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.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/Visual Studio Project Template C#/$projectname$.csproj b/Visual Studio Project Template C#/$projectname$.csproj index 974ba5c..2356549 100644 --- a/Visual Studio Project Template C#/$projectname$.csproj +++ b/Visual Studio Project Template C#/$projectname$.csproj @@ -73,6 +73,7 @@ + diff --git a/Visual Studio Project Template C#/PluginInfrastructure/DarkMode.cs b/Visual Studio Project Template C#/PluginInfrastructure/DarkMode.cs new file mode 100644 index 0000000..41354da --- /dev/null +++ b/Visual Studio Project Template C#/PluginInfrastructure/DarkMode.cs @@ -0,0 +1,56 @@ +using System; +using System.Drawing; +using System.Runtime.InteropServices; + +namespace Kbg.NppPluginNET.PluginInfrastructure +{ + /// + /// Holds the BGR values of the active dark mode theme. + /// + /// + [StructLayout(LayoutKind.Sequential)] + public struct DarkModeColors + { + public int Background; + public int SofterBackground; + public int HotBackground; + public int PureBackground; + public int ErrorBackground; + public int Text; + public int DarkerText; + public int DisabledText; + public int LinkText; + public int Edge; + public int HotEdge; + public int DisabledEdge; + } + + /// + /// Extends with methods implementing Npp's dark mode API. + /// + public partial class NotepadPPGateway : INotepadPPGateway + { + public IntPtr GetDarkModeColors() + { + DarkModeColors darkModeColors = new DarkModeColors(); + IntPtr _cbSize = new IntPtr(Marshal.SizeOf(darkModeColors)); + IntPtr _ptrDarkModeColors = Marshal.AllocHGlobal(_cbSize); + Win32.SendMessage(PluginBase.nppData._nppHandle, (uint) NppMsg.NPPM_GETDARKMODECOLORS, _cbSize, _ptrDarkModeColors); + return _ptrDarkModeColors; + } + + public bool IsDarkModeEnabled() + { + IntPtr result = Win32.SendMessage(PluginBase.nppData._nppHandle, (uint) NppMsg.NPPM_ISDARKMODEENABLED, Unused, Unused); + return ((int)result == 1); + } + } + + static class NppDarkMode + { + public static Color BGRToColor(int bgr) + { + return Color.FromArgb((bgr & 0xFF), ((bgr >> 8) & 0xFF), ((bgr >> 16) & 0xFF)); + } + } +} \ No newline at end of file diff --git a/Visual Studio Project Template C#/PluginInfrastructure/Docking_h.cs b/Visual Studio Project Template C#/PluginInfrastructure/Docking_h.cs index bb256da..dacdb9c 100644 --- a/Visual Studio Project Template C#/PluginInfrastructure/Docking_h.cs +++ b/Visual Studio Project Template C#/PluginInfrastructure/Docking_h.cs @@ -29,6 +29,7 @@ public enum NppTbMsg : uint DWS_ICONTAB = 0x00000001, // Icon for tabs are available DWS_ICONBAR = 0x00000002, // Icon for icon bar are available (currently not supported) DWS_ADDINFO = 0x00000004, // Additional information are in use + DWS_USEOWNDARKMODE = 0x00000008, // Use plugin's own dark mode DWS_PARAMSALL = (DWS_ICONTAB | DWS_ICONBAR | DWS_ADDINFO), // default docking values for first call of plugin diff --git a/Visual Studio Project Template C#/PluginInfrastructure/Msgs_h.cs b/Visual Studio Project Template C#/PluginInfrastructure/Msgs_h.cs index 214a73c..241ef45 100644 --- a/Visual Studio Project Template C#/PluginInfrastructure/Msgs_h.cs +++ b/Visual Studio Project Template C#/PluginInfrastructure/Msgs_h.cs @@ -560,6 +560,21 @@ public enum NppMsg : uint /// NPPM_ADDTOOLBARICON_FORDARKMODE = Constants.NPPMSG + 101, + /// + /// bool NPPM_ISDARKMODEENABLED(0, 0) + /// Returns true when Notepad++ Dark Mode is enabled, false when it is not. + /// + /// + NPPM_ISDARKMODEENABLED = (Constants.NPPMSG + 107), + + /// + /// bool NPPM_GETDARKMODECOLORS (size_t cbSize, NppDarkMode::Colors* returnColors) + /// - cbSize must be filled with sizeof(NppDarkMode::Colors). + /// - returnColors must be a pre-allocated NppDarkMode::Colors struct. + /// Returns true when successful, false otherwise. + /// + NPPM_GETDARKMODECOLORS = (Constants.NPPMSG + 108), + RUNCOMMAND_USER = Constants.WM_USER + 3000, NPPM_GETFULLCURRENTPATH = RUNCOMMAND_USER + FULL_CURRENT_PATH, NPPM_GETCURRENTDIRECTORY = RUNCOMMAND_USER + CURRENT_DIRECTORY, @@ -805,6 +820,14 @@ public enum NppMsg : uint /// NPPN_FILEDELETED = NPPN_FIRST + 26, + /// + /// To notify plugins that Dark Mode was enabled/disabled + /// scnNotification->nmhdr.code = NPPN_DARKMODECHANGED; + /// scnNotification->nmhdr.hwndFrom = hwndNpp; + /// scnNotification->nmhdr.idFrom = 0; + /// + NPPN_DARKMODECHANGED = (NPPN_FIRST + 27) + /* --Autogenerated -- end of section automatically generated from notepad-plus-plus\PowerEditor\src\MISC\PluginsManager\Notepad_plus_msgs.h * */ } } diff --git a/Visual Studio Project Template C#/PluginInfrastructure/NotepadPPGateway.cs b/Visual Studio Project Template C#/PluginInfrastructure/NotepadPPGateway.cs index ff11162..eb0ced6 100644 --- a/Visual Studio Project Template C#/PluginInfrastructure/NotepadPPGateway.cs +++ b/Visual Studio Project Template C#/PluginInfrastructure/NotepadPPGateway.cs @@ -13,6 +13,8 @@ public interface INotepadPPGateway void AddToolbarIcon(int funcItemsIndex, toolbarIcons icon); void AddToolbarIcon(int funcItemsIndex, Bitmap icon); + bool IsDarkModeEnabled(); + IntPtr GetDarkModeColors(); string GetNppPath(); string GetPluginConfigPath(); string GetCurrentFilePath(); @@ -25,7 +27,7 @@ public interface INotepadPPGateway /// This class holds helpers for sending messages defined in the Msgs_h.cs file. It is at the moment /// incomplete. Please help fill in the blanks. /// - public class NotepadPPGateway : INotepadPPGateway + public partial class NotepadPPGateway : INotepadPPGateway { private const int Unused = 0;