Community
    • Login

    C++ DarkMode dialogs -- not all controls inherit the mode

    Scheduled Pinned Locked Moved Notepad++ & Plugin Development
    9 Posts 3 Posters 321 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.
    • PeterJonesP
      PeterJones
      last edited by

      I’m using the official C++ template for my plugins.

      For my initial release on both, I pretended not to think about DarkMode compatibility, but I’m starting to work on that now that v1 is out on both of them.

      By following the NPPM_DARKMODESUBCLASSANDTHEME and the example of adding DarkMode to MIME Tools, I was able to get CollectionInterface’s About box to be nicely DarkMode in the darkMode branch:
      3988c17e-d2af-49f0-8954-7812ca149c34-image.png

      Unfrotunately, when I followed the same procedure on the “Download” dialog for the same plugin, I came across a snag:
      80ed709b-95c0-4dc9-a7f4-ee839691ab92-image.png
      … It uses a CONTROL ... "SysTabControl32" tab interface, which appears to not inherit the DarkMode when I use that message. Also, the CONTROL ... "msctls_progress32" progress bar, based on its background, appears to also not get the “magic” that the NPPM_DARKMODESUBCLASSANDTHEME is supposed to impart.

      For those who have more experience with such things than I do: Is that something I have to fix on my end – and if so, are there any instructions available, and/or examples of how? Or do I need to put in a feature request to improve NPPM_DARKMODESUBCLASSANDTHEME’s behavior?

      Secondarily: if I put the NPPM_DARKMODESUBCLASSANDTHEME “after controls initializations in WM_INITDIALOG” as recommended in the Manual (which was derived from Don’s instructions when the new message was added), then I can see the dialog initially draw itself in light-mode, then re-color at the end. If I move the message to the beginning of WM_INITDIALOG, then the dialog seems to be drawn dark initially (or changes color too fast for me to notice), which is what I’d prefer… but the scroll-bar disappears from the ListBox, and I can only scroll using arrow keys, not the bar:
      6d072691-5ae8-47c1-a924-3554bb9e4579-image.png
      Is there a way to get it to draw the dialog dark to begin with, without breaking the functionality of standard controls like the list-box’s scrollbar?

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

        I’m actually pretty proud of the algorithm NppCSharpPluginPack uses to keep its dialog colors in sync with Notepad++. What’s cool about this algorithm is that it follows light mode themes (e.g., a green/yellow palette for Mossylawn), not just dark mode/light mode.

        The basic algorithm is not that hard - choose a set of colors for various parts of each dialog by doing some arithmetic of the RBG values of the text color and background color, and then recursively style each child control of the dialog according to that color scheme. The main issue I had to overcome was figuring out how to derive a good color scheme from the NPP color scheme, and then figure out which controls should be assigned which colors.

        I have no idea how hard it would be to translate this to C++, but I can’t believe it would be too much work.

        PeterJonesP 1 Reply Last reply Reply Quote 2
        • PeterJonesP
          PeterJones @Mark Olson
          last edited by

          @Mark-Olson said in C++ DarkMode dialogs -- not all controls inherit the mode:

          I have no idea how hard it would be to translate this to C++, but I can’t believe it would be too much work.

          I doubt I’ll borrow the entire algorithm – I will probably just let it use the defaults for Light, and the colors that the NPPM_GETDARKMODECOLORS message supplies for Dark.

          But based on a quick reading of your code, the answer seems to be “manually set the foreground and background for any control [that’s not already set by the message], possibly requiring recursive navigation through the dialog”. I guess I’ll have to dig into how to do that color setting in the old-style C++ interface. I’ll have to see whether it’s better to do it manually for just that, or re-create the subclassing and messages that Notepad++ does with the message, but adding more controls to the case… Some more exploration coming, I guess.

          1 Reply Last reply Reply Quote 0
          • PeterJonesP
            PeterJones
            last edited by

            Unfortunately, “SysTabControl32” is a different beast than the others… I’ve been slowly piecing together the information, but it doesn’t have WM_CTLCOLORxyz like the static/label, buttons, edits, listboxes, comboboxes and the like (and doesn’t seem to trigger the original WM_CTLCOLOR that those more-specific messages replaced, either).

            I was able to find that if I set the control to TCS_OWNERDRAWFIXED, then I can handle WM_DRAWITEM, and with enough web searches, figured out how to manually fill out the tab labels that happen automatically when it’s not TCS_OWNERDRAWFIXED, and so while doing that, I can change the FG and BG colors for the text. Unfortunately, the outer tab wrapper is still staying the default gray background, no matter what I do.

            fa9b0420-6509-4d72-a5eb-c06e162975b3-image.png

            Has anyone made use of the “SysTabControl32” in C++ with DarkMode?

            I don’t know how long I’ll keep going down this road – I might just switch back to my original idea of doing the UDL/AutoCompletion/FunctionList/Theme selection as a combobox, which would get rid of the not-playing-nice tabbed-interface… but I won’t give up yet.

            CoisesC 1 Reply Last reply Reply Quote 1
            • CoisesC
              Coises @PeterJones
              last edited by

              @PeterJones A possible hint…

              Shortcut Mapper uses a SysTabControl32, and it honors dark mode.

              It looks like Notepad++ handles that as part of something it calls a BabyGridWrapper; I think the code that sets the colors might be here.

              That’s as far as I followed it.

              PeterJonesP 1 Reply Last reply Reply Quote 1
              • PeterJonesP
                PeterJones @Coises
                last edited by

                @Coises said in C++ DarkMode dialogs -- not all controls inherit the mode:

                @PeterJones A possible hint…

                Shortcut Mapper uses a SysTabControl32, and it honors dark mode.

                I really should have thought of that myself. I was too busy trying to find a plugin that both uses it and supports dark mode. :-)

                It looks like Notepad++ handles that as part of something it calls a BabyGridWrapper;

                Actually, you have fallen prey to one of the mental traps of tab-controls, and misinterpreted what’s inside the tab compared to the tab itself. In this case, the BabyGrid is the table/spreadsheet/grid of name/shortcut/category (column) vs command (row) which is inside the tab.

                But once you said that, I was able to look around and find where the app handles the actual tab-control, and I see it calls the method NppDarkMode::subclassTabControl() to subclasses the Tab interface for changing the color in Dark Mode… so it looks like I’ll have to duplicate that subclassing (because the message doesn’t call that separate subclassing)

                1 Reply Last reply Reply Quote 3
                • PeterJonesP
                  PeterJones
                  last edited by

                  Success.

                  So that other plugin authors can learn from my last couple of days, here is an example of what I did in order to get DarkMode to apply to the SysTabControl32 (I don’t know if it’s the best way; but it’s the way I was able to figure out):

                  In my header files, I have added a copy of some of the structures from N++ repo, including NppDarkMode.h’s struct Colors and struct Brushes and struct Pens from NppDarkMode.cpp, and then make instances of those objects as file-level globals (that’s what allows me to grab the colors using the NPPM_GETDARKMODECOLORS message, and then make sure I have the brushes/pens derived from those colors.)

                  NppDarkMode::Colors myColors = { 0 };
                  NppDarkMode::Brushes myBrushes(myColors);
                  NppDarkMode::Pens myPens(myColors);
                  

                  In WM_INITDIALOG, I add

                  			// determine dark mode
                  			g_IsDarkMode = (bool)::SendMessage(nppData._nppHandle, NPPM_ISDARKMODEENABLED, 0, 0);
                  			if (g_IsDarkMode) {
                  				::SendMessage(nppData._nppHandle, NPPM_GETDARKMODECOLORS, sizeof(NppDarkMode::Colors), reinterpret_cast<LPARAM>(&myColors));
                  				myBrushes.change(myColors);
                  				myPens.change(myColors);
                  
                  				// subclass the tab control, because NPPM_DARKMODESUBCLASSANDTHEME doesn't apply to SysTabControl32
                  				::SetWindowSubclass(GetDlgItem(g_hwndCIDlg, IDC_CI_TABCTRL), cbTabSubclass, g_ci_dark_subclass, 0);
                  
                  				// For the rest, follow Notpead++ DarkMode settings
                  				::SendMessage(nppData._nppHandle, NPPM_DARKMODESUBCLASSANDTHEME, static_cast<WPARAM>(NppDarkMode::dmfInit), reinterpret_cast<LPARAM>(g_hwndCIDlg));
                  			}
                  

                  Finally, I took a copy of the TabSubclass() callback in NppDarkMode.cpp, and adjusted it so it used my color/brush/pen instances rather than the methods, and other similar tweaks to get it to compile. (And it doesn’t apparently need the WM_PARENTNOTIFY, at least not with my four-tab interface)

                  With that, I can get the tabbed-interface part of the dialog to also follow DarkMode (including the various standard or customized tones.

                  CoisesC 1 Reply Last reply Reply Quote 4
                  • CoisesC
                    Coises @PeterJones
                    last edited by

                    @PeterJones said in C++ DarkMode dialogs -- not all controls inherit the mode:

                    Success.

                    Congratulations!

                    Do you think it’s possible that not including a call to subclassTabControl in autoSubclassAndThemeChildControls — which in turn is called by autoSubclassAndThemePlugin, which implements NPPM_DARKMODESUBCLASSANDTHEME — is an oversight? Would it be worth a feature request issue?

                    PeterJonesP 1 Reply Last reply Reply Quote 1
                    • PeterJonesP
                      PeterJones @Coises
                      last edited by PeterJones

                      @Coises said in C++ DarkMode dialogs -- not all controls inherit the mode:

                      is an oversight? Would it be worth a feature request issue?

                      Probably.

                      I just did an experimental build of N++, calling subclassTabControl from an "if WC_TABCONTROL, and it seems to work – in that, whether or not my plugin subclasses on its end, if I have that call in N++, it makes the tab control properly follow N++ DarkMode settings.

                      I’ll create an Issue (complete with making a branch of my plugin where I don’t manually subclass, so there can be easy steps-to-reproduce), and then submit a proposed PR to fix it.


                      update:

                      • Issue: https://github.com/notepad-plus-plus/notepad-plus-plus/issues/16668
                      • PR: https://github.com/notepad-plus-plus/notepad-plus-plus/pull/16669
                      1 Reply Last reply Reply Quote 4
                      • First post
                        Last post
                      The Community of users of the Notepad++ text editor.
                      Powered by NodeBB | Contributors