Community
    • Login

    Darkmode doesn't stylize all plugin controls on docked window (groupbox, panel, labels etc)

    Scheduled Pinned Locked Moved Notepad++ & Plugin Development
    14 Posts 4 Posters 1.1k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Bas de ReuverB
      Bas de Reuver
      last edited by

      A while ago the generic darkmode for plug-in dock panels was added, also see this thread.

      But afaik it doesn’t apply darkmode colors to all wincontrols, for example groupbox, panel and labels, see screenshot below.

      plugin dialog in darkmode example

      It’s done by this function autoSubclassAndThemeChildControls but it doesn’t seem to call the EnumChildWindows recursively for container-type controls, so for example Panel, GroupBox, SplitContainer etc. From what I could find these are called REBARCLASSNAME controls, and they are container controls which can themselfes contain textboxes, buttons etc.

      Is it possible to have Notepad++ apply darkmode colors also to labels and the container controls with its childcontrols?

      Alan KilbornA rdipardoR 2 Replies Last reply Reply Quote 1
      • Bas de ReuverB
        Bas de Reuver
        last edited by Bas de Reuver

        Btw also, it would be nice to be able to somehow call the autoSubclassAndThemeChildControls from within the plugin, is that possible at the moment? I couldn’t find any API calls. That way the plugin can use the default Notepad++ functions to apply darkmode colors to all its dialogs.

        Currently most plugins display any dialogs in normal/lightmode colors even when Notepad++ is set to darkmode. I know there is DWS_USEOWNDARKMODE but for simple Settings/About forms when there are no special controls or anything, it would imho be better to just let Notepad++ uniformly change these to darkmode. See an example plug-in dialog and a mockup dialog below.

        csvquery_example_dialog.png

        notepad_plugin_darkmode.png

        1 Reply Last reply Reply Quote 2
        • Alan KilbornA
          Alan Kilborn @Bas de Reuver
          last edited by Alan Kilborn

          @Bas-de-Reuver said in Darkmode doesn’t stylize all plugin controls on docked window (groupbox, panel, labels etc):

          Is it possible to have Notepad++ apply darkmode colors also to labels and the container controls with its childcontrols?

          I think it would be very reasonable for you to open an official issue on github concerning this. See HERE.

          If you do that, you will likely have very much luck if you put @ozone10 in your issue text so that he for sure doesn’t miss your issue. He is the one that added dark mode support to N++ and would be very interested in – and probably quick to action on – such an issue (IMO).

          1 Reply Last reply Reply Quote 3
          • Bas de ReuverB
            Bas de Reuver
            last edited by

            @Alan-Kilborn Okay I’ve submitted them as two separate issues here 13572 and 13574

            Alan KilbornA 1 Reply Last reply Reply Quote 2
            • Alan KilbornA
              Alan Kilborn @Bas de Reuver
              last edited by

              @Bas-de-Reuver

              I tried my own quick test using the N++ plugin demo, found HERE.

              I created a groupbox and an edit control on the docking dialog. I ran it and both were “dark” in dark mode (so good so far). Then in the code, I changed the parent of the edit control to be the groupbox. Rerunning that, the edit control ended up not being “dark”.

              So, not much new to add, but basically I can confirm/duplicate your results…

              1 Reply Last reply Reply Quote 2
              • Mark OlsonM
                Mark Olson
                last edited by Mark Olson

                FWIW, I worked on recursively applying dark mode styling to all my forms in JsonTools a while back, just using C# code in the tree view controls.

                I was able to do it, but I came to the conclusion that while docking forms like my JSON tree and the CSV Lint window look much better when they have the same styling as the editor window, non-docking forms like the find/replace form don’t necessarily look better.

                So I’d cast a weak tentative vote in favor of allowing people to opt out of this, although I recognize that adding yet another knob that people can turn has downsides.

                Alan KilbornA 1 Reply Last reply Reply Quote 1
                • Alan KilbornA
                  Alan Kilborn @Mark Olson
                  last edited by

                  @Mark-Olson said in Darkmode doesn’t stylize all plugin controls on docked window (groupbox, panel, labels etc):

                  …don’t necessarily look better

                  Do you have a specific example you can show?

                  Mark OlsonM 1 Reply Last reply Reply Quote 0
                  • Mark OlsonM
                    Mark Olson @Alan Kilborn
                    last edited by

                    @Alan-Kilborn
                    No, I never took pictures and I reverted the code to get rid of the recursive application of Notepad++ theme to anything other than my tree viewer. I just decided in my purely subjective opinion that while the tree view looked better sharing the NPP theme, the non-docking forms didn’t.

                    Admittedly the not-so-great result might have been mainly due to my hand-coded attempt to make the controls look similar to Notepad++, and this proposal might look better. I won’t stand in the way of progress.

                    Bas de ReuverB 1 Reply Last reply Reply Quote 0
                    • Bas de ReuverB
                      Bas de Reuver @Mark Olson
                      last edited by

                      @Mark-Olson I wouldn’t want to bother the user with unnecessary extra options for something like this, imho it should either be all in lightmode or all in darkmode. Wether it looks better or not is subjective and up to the enduser.

                      As far as I’m concerned it’s just a matter of consistency. So making the plug-in look seemlessly integrated with Notepad++. As it is now, when a user is working with Notepad++ in darkmode, the sudden lightmode dialogs from the plug-in just look out of place.

                      Alan KilbornA 1 Reply Last reply Reply Quote 1
                      • Alan KilbornA
                        Alan Kilborn @Bas de Reuver
                        last edited by Alan Kilborn

                        @Bas-de-Reuver said in Darkmode doesn’t stylize all plugin controls on docked window (groupbox, panel, labels etc):

                        … it should either be all in lightmode or all in darkmode…As far as I’m concerned it’s just a matter of consistency.

                        I agree.

                        Even for my simple test:

                        …I changed the parent of the edit control to be the groupbox. Rerunning that, the edit control ended up not being “dark”.

                        It was ridiculous to see the white edit box on the otherwise dark dialog.

                        1 Reply Last reply Reply Quote 0
                        • rdipardoR
                          rdipardo @Bas de Reuver
                          last edited by

                          This will probably have to be implemented on the plugin’s end. The minimum required infrastructure would be, roughly:

                          • definitions for the Npp API messages added in v8.4.1, i.e.:

                             NPPM_ISDARKMODEENABLED
                             NPPM_GETDARKMODECOLORS
                             NPPN_DARKMODECHANGED
                            
                          • a type equivalent to the NppDarkMode::Colors structure, for collecting the active palette of dark mode styles

                          • a method implementing the NPPM_GETDARKMODECOLORS API, taking a pointer to the ersatz NppDarkMode::Colors struct and filling each member with the corresponding color for the active theme (black, cyan, olive, etc.)

                          • a callback inside beNotified that hooks NPPN_DARKMODECHANGED, where the plugin calls the NPPM_GETDARKMODECOLORS method, iterates the form’s components, and changes their color to whatever the NppDarkMode::Colors instance was initialized with

                          Of course none of these features are provided by the still-popular .NET plugin template, and most likely never will be, until somebody with lots of spare time makes an updated fork.

                          Some components (e.g. scroll bars) may not be customizable without hacking into the WM_NCPAINT message or, in the case of buttons, using style flags like BS_OWNERDRAW. All of which is at least possible in C#, if you don’t mind getting your hands dirty.

                          1 Reply Last reply Reply Quote 5
                          • rdipardoR
                            rdipardo
                            last edited by rdipardo

                            This will probably have to be implemented on the plugin’s end.

                            From what @ozone10 says here and here, looks like I was on the right track.

                            @Bas-de-Reuver, here’s a quick patch you can build your own proof-of-concept from. It doesn’t touch the form components, but it’s just a matter of exposing the controls and setting the colors however you want.

                            The NPPN_DARKMODECHANGED hook I added to Main.OnNotification is where you collect the currently active dark mode colors. Notice how the RGB values change when switching tones to red, blue, cyan, etc.

                            csvlint-nppn_darkmodechanged-hook


                            WIP: Integrate Npp’s dark mode API
                            diff --git a/CSVLintNppPlugin/CsvLintNppPlugin.csproj b/CSVLintNppPlugin/CsvLintNppPlugin.csproj
                            index 2a169a6..f81bebc 100644
                            --- a/CSVLintNppPlugin/CsvLintNppPlugin.csproj
                            +++ b/CSVLintNppPlugin/CsvLintNppPlugin.csproj
                            @@ -139,6 +139,7 @@
                                 <Compile Include="PluginInfrastructure\ScintillaStreams.cs" />
                                 <Compile Include="PluginInfrastructure\Win32.cs" />
                                 <Compile Include="Main.cs" />
                            +    <Compile Include="PluginInfrastructure\DarkMode.cs" />    
                                 <Compile Include="PluginInfrastructure\GatewayDomain.cs" />
                                 <Compile Include="PluginInfrastructure\NotepadPPGateway.cs" />
                                 <Compile Include="PluginInfrastructure\ScintillaGateway.cs" />
                            diff --git a/CSVLintNppPlugin/Main.cs b/CSVLintNppPlugin/Main.cs
                            index 9f97846..1efd612 100644
                            --- a/CSVLintNppPlugin/Main.cs
                            +++ b/CSVLintNppPlugin/Main.cs
                            @@ -124,6 +124,31 @@ public static void OnNotification(ScNotification notification)
                                             Main.RemoveCSVdef(notification.Header.IdFrom);
                                         }
                             
                            +            // dark mode (de-)activated
                            +            if (code == (uint)NppMsg.NPPN_DARKMODECHANGED)
                            +            {
                            +                NotepadPPGateway notepad = new NotepadPPGateway();
                            +                if (notepad.IsDarkModeEnabled())
                            +                {
                            +                    IntPtr theme_ptr = notepad.GetDarkModeColors();
                            +                    if (theme_ptr != IntPtr.Zero)
                            +                    {
                            +                        DarkModeColors theme = (DarkModeColors)Marshal.PtrToStructure(theme_ptr, typeof(DarkModeColors));
                            +                        // TODO: set component colors to `theme.Background`, `theme.SofterBackground`, etc.
                            +#if DEBUG
                            +                        // show the active palette's RBG values
                            +                        var msg = new StringBuilder();
                            +                        foreach (var style in typeof(DarkModeColors).GetFields(BindingFlags.Instance |BindingFlags.Public))
                            +                        {
                            +                            msg.AppendLine($"{style.Name}: 0x{style.GetValue(theme):X6}");
                            +                        }
                            +                        System.Windows.Forms.MessageBox.Show($"{msg}");
                            +#endif
                            +                    }
                            +                    Marshal.FreeHGlobal(theme_ptr);
                            +                }
                            +            }
                            +
                                         if (code > int.MaxValue) // windows messages
                                         {
                                             int wm = -(int)code;
                            diff --git a/CSVLintNppPlugin/PluginInfrastructure/DarkMode.cs b/CSVLintNppPlugin/PluginInfrastructure/DarkMode.cs
                            new file mode 100644
                            index 0000000..70e54d3
                            --- /dev/null
                            +++ b/CSVLintNppPlugin/PluginInfrastructure/DarkMode.cs
                            @@ -0,0 +1,46 @@
                            +// Types, methods for interacing with Npp's dark mode API
                            +using System;
                            +using System.Runtime.InteropServices;
                            +
                            +namespace Kbg.NppPluginNET.PluginInfrastructure
                            +{
                            +    /// <see href "https://github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/NppDarkMode.h"/>
                            +    [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;
                            +    }
                            +
                            +    /// <summary>
                            +    /// Implements dark mode APIs for plugins.
                            +    /// </summary>
                            +    public partial class NotepadPPGateway : INotepadPPGateway
                            +    {
                            +        /// Returns a pointer so that callees can deallocate it.
                            +        public IntPtr GetDarkModeColors()
                            +       {
                            +            DarkModeColors darkModeColors = new DarkModeColors();
                            +            IntPtr _size = new IntPtr(Marshal.SizeOf(darkModeColors));
                            +            IntPtr _ptrDarkModeColors = Marshal.AllocHGlobal(_size);
                            +           Win32.SendMessage(PluginBase.nppData._nppHandle, (uint) NppMsg.NPPM_GETDARKMODECOLORS, _size, _ptrDarkModeColors);
                            +            return _ptrDarkModeColors;
                            +        }
                            +
                            +        public bool IsDarkModeEnabled()
                            +        {
                            +            IntPtr result = Win32.SendMessage(PluginBase.nppData._nppHandle, (uint) NppMsg.NPPM_ISDARKMODEENABLED, Unused, Unused);
                            +            return ((int)result == 1);
                            +       }
                            +    }
                            +}
                            diff --git a/CSVLintNppPlugin/PluginInfrastructure/Msgs_h.cs b/CSVLintNppPlugin/PluginInfrastructure/Msgs_h.cs
                            index 3319ce2..4363fa1 100644
                            --- a/CSVLintNppPlugin/PluginInfrastructure/Msgs_h.cs
                            +++ b/CSVLintNppPlugin/PluginInfrastructure/Msgs_h.cs
                            @@ -565,6 +565,45 @@ public enum NppMsg : uint
                                     /// </summary>
                                     NPPM_ADDTOOLBARICON_FORDARKMODE = Constants.NPPMSG + 101,
                             
                            +        /// <summary>
                            +        /// bool NPPM_ISDARKMODEENABLED(0, 0)
                            +        /// Returns true when Notepad++ Dark Mode is enable, false when it is not.
                            +        /// <see href="https://github.com/notepad-plus-plus/notepad-plus-plus/commit/1eb5b10e41d7ab92b60aa32b28d4fe7739d15b53"/>
                            +        /// </summary>
                            +        NPPM_ISDARKMODEENABLED = (Constants.NPPMSG + 107),
                            +
                            +        /// <summary>
                            +        /// 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.
                            +        /// You need to uncomment the following code to use NppDarkMode::Colors structure:
                            +        /// <code>
                            +        /// namespace NppDarkMode
                            +        /// {
                            +        ///  struct Colors
                            +        ///  {
                            +        ///    COLORREF background = 0;
                            +        ///    COLORREF softerBackground = 0;
                            +        ///    COLORREF hotBackground = 0;
                            +        ///    COLORREF pureBackground = 0;
                            +        ///    COLORREF errorBackground = 0;
                            +        ///    COLORREF text = 0;
                            +        ///    COLORREF darkerText = 0;
                            +        ///    COLORREF disabledText = 0;
                            +        ///    COLORREF linkText = 0;
                            +        ///    COLORREF edge = 0;
                            +        ///    COLORREF hotEdge = 0;
                            +        ///    COLORREF disabledEdge = 0;
                            +        ///  };
                            +        /// }
                            +        /// </code>
                            +        /// Note: in the case of calling failure ("false" is returned), you may need to change NppDarkMode::Colors structure to:
                            +        /// https:///github.com/notepad-plus-plus/notepad-plus-plus/blob/master/PowerEditor/src/NppDarkMode.h#L32
                            +        /// <see href="https://github.com/notepad-plus-plus/notepad-plus-plus/commit/1eb5b10e41d7ab92b60aa32b28d4fe7739d15b53"/>
                            +        /// </summary>
                            +        NPPM_GETDARKMODECOLORS = (Constants.NPPMSG + 108),
                            +
                                     RUNCOMMAND_USER = Constants.WM_USER + 3000,
                                     NPPM_GETFULLCURRENTPATH = RUNCOMMAND_USER + FULL_CURRENT_PATH,
                                     NPPM_GETCURRENTDIRECTORY = RUNCOMMAND_USER + CURRENT_DIRECTORY,
                            @@ -810,6 +849,14 @@ public enum NppMsg : uint
                                     /// </summary>
                                     NPPN_FILEDELETED = NPPN_FIRST + 26,
                             
                            +        /// <summary>
                            +        /// To notify plugins that Dark Mode was enabled/disabled
                            +        /// scnNotification->nmhdr.code = NPPN_DARKMODECHANGED;
                            +        /// scnNotification->nmhdr.hwndFrom = hwndNpp;
                            +        /// scnNotification->nmhdr.idFrom = 0;
                            +        /// </summary>
                            +        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/CSVLintNppPlugin/PluginInfrastructure/NotepadPPGateway.cs b/CSVLintNppPlugin/PluginInfrastructure/NotepadPPGateway.cs
                            index 7b599a0..d3e0467 100644
                            --- a/CSVLintNppPlugin/PluginInfrastructure/NotepadPPGateway.cs
                            +++ b/CSVLintNppPlugin/PluginInfrastructure/NotepadPPGateway.cs
                            @@ -18,7 +18,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.
                             	/// </summary>
                            -	public class NotepadPPGateway : INotepadPPGateway
                            +	public partial class NotepadPPGateway : INotepadPPGateway
                             	{
                             		private const int Unused = 0;
                             
                            
                            rdipardoR 1 Reply Last reply Reply Quote 4
                            • rdipardoR
                              rdipardo @rdipardo
                              last edited by

                              Submitted my implementation upstream, with a real usage example: https://github.com/kbilsted/NotepadPlusPlusPluginPack.Net/pull/104

                              Mark OlsonM 1 Reply Last reply Reply Quote 4
                              • Mark OlsonM
                                Mark Olson @rdipardo
                                last edited by

                                @rdipardo
                                Cool! I’m going to run with your example and see about writing something that just automatically applies good dark mode styling to all the controls in any arbitrary WinForm rather than having to specify which controls get which colors.

                                1 Reply Last reply Reply Quote 3
                                • First post
                                  Last post
                                The Community of users of the Notepad++ text editor.
                                Powered by NodeBB | Contributors