Community
    • Login

    Slight issue with plugin's toolbar bitmap when switching light/dark mode

    Scheduled Pinned Locked Moved Notepad++ & Plugin Development
    8 Posts 3 Posters 322 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.
    • K
      klaus101
      last edited by klaus101

      Minor cosmetic thing with my plugin using, with Lazarus, rdipardos Notepad++ Plugin Template for Delphi & Lazarus.
      A toolbar icon (better: bitmap; i checked a .bmp file will be used in fact) looks not so good in dark mode (light gray background. Somehow acceptable, but not perfect).

      As a kind of reference i checked against a C++ written plugin (funap’s explorer plugin: https://github.com/funap/npp-explorer-plugin), where it’s behaving better when switching between light and dark, and picked up, for test, the icons and bitmaps from there, especially “explore.bmp” from the “res”-subfolder.

      I made a copy of explore.bmp -> explore_dark.bmp, spent it a dark background and added it to the plugin’s resource file:

      TB_BMP BITMAP "Resources\\explore.bmp"
      TB_DM_BMP BITMAP "Resources\\explore_dark.bmp"
      

      Then i adapted rdipardo’s code as follows:
      Original:
      https://bitbucket.org/rdipardo/delphiplugintemplate/src/default/Source/Units/HelloWorldPlugin.pas

      See the test changes via “// **** Added”:

      procedure THelloWorldPlugin.DoNppnToolbarModification;
      var
        tb: TToolbarIcons;
        tbDark: TTbIconsDarkMode;
        HTbBmp: HBITMAP;
        HTIcon: HICON;
        hHDC: HDC;
        bmpX, bmpY, icoX, icoY: Integer;
      begin
        tb := Default (TToolbarIcons);
        tbDark := Default (TTbIconsDarkMode);
        hHDC := 0;
        try
          hHDC := GetDC(THandle(Nil));
          bmpX := MulDiv(16, GetDeviceCaps(hHDC, LOGPIXELSX), 96);
          bmpY := MulDiv(16, GetDeviceCaps(hHDC, LOGPIXELSY), 96);
          icoX := MulDiv(32, GetDeviceCaps(hHDC, LOGPIXELSX), 96);
          icoY := MulDiv(32, GetDeviceCaps(hHDC, LOGPIXELSY), 96);
        finally
          ReleaseDC(THandle(Nil), hHDC);
        end;
        // **** A change is done here:
        if self.IsDarkModeEnabled then    // **** Added, for to assure to load a more appropriate bitmap for the toolbar for dark mode (without gray background)
           HTbBmp := LoadImage(Hinstance, 'TB_DM_BMP', IMAGE_BITMAP, bmpX, bmpY, 0)   // **** Added
        else  // **** Added
           HTbBmp := LoadImage(Hinstance, 'TB_BMP', IMAGE_BITMAP, bmpX, bmpY, 0);
      
        HTIcon := LoadImage(Hinstance, 'TB_ICON', IMAGE_ICON, icoX, icoY,
          (LR_DEFAULTSIZE or LR_LOADMAP3DCOLORS));
        tb.ToolbarBmp := HTbBmp;
        tb.ToolbarIcon := HTIcon;
        tbDark.ToolbarBmp := HTbBmp;
        tbDark.ToolbarIcon := HTIcon;
      
        if self.SupportsDarkMode then
        begin
          tbDark.ToolbarIconDarkMode := LoadImage(Hinstance, 'TB_DM_ICON', IMAGE_ICON,
            icoX, icoY, (LR_DEFAULTSIZE or LR_LOADMAP3DCOLORS));
          SendNppMessage(NPPM_ADDTOOLBARICON_FORDARKMODE, CmdIdFromDlgId(DlgMenuId), @tbDark);
        end
        else
          SendNppMessage(NPPM_ADDTOOLBARICON_DEPRECATED, CmdIdFromDlgId(DlgMenuId), @tb);
      end;
      

      That works fine now so far when restarting NPP either in dark or in light mode.
      But when switching the mode during a session - using Settings > Options > Dark mode - it has no effect (until i restart).
      Because THelloWorldPlugin.DoNppnToolbarModification; won’t be called when doing this mode switch.

      So i added another change: explicitely triggering DoNppnToolbarModification when NPPN_DARKMODECHANGED notification happens:

      procedure THelloWorldPlugin.BeNotified(sn: PSciNotification);
      begin
        inherited BeNotified(sn);
        if HWND(sn^.nmhdr.hwndFrom) = self.NppData.NppHandle then begin
          case sn.nmhdr.code of
            NPPN_DARKMODECHANGED: begin
      
              Self.DoNppnToolbarModification;  // **** Added, for to assure that each the appropriate bitmap for the toolbar will be loaded when the mode is switched
      
              if Assigned(HelloWorldDockingForm) then begin
                HelloWorldDockingForm.ToggleDarkMode;
              end;
      

      DoNppnToolbarModification will be called now when a session’s mode switch happens, the correct bitmap will be loaded (‘TB_BMP’ for light mode, ‘TB_DM_BMP’ for dark mode) … but the change cannot be seen in the toolbar itself (until i restart).

      What might i miss ??
      Attached the both bitmaps i used for test.
      ![explore.bmp](Input file contains unsupported image format) ![explore_dark.bmp](Input file contains unsupported image format)

      PeterJonesP rdipardoR 2 Replies Last reply Reply Quote 1
      • PeterJonesP
        PeterJones @klaus101
        last edited by

        @klaus101 ,

        @rdipardo comes here reasonably often, so if no one else has any ideas, hopefully he’ll be able to chime in soon. (I know nothing about Delphi & Lazarus, so I cannot help with that. I replied so that I could add the @-mention to hopefully catch @rdipardo’s attention.)

        1 Reply Last reply Reply Quote 0
        • rdipardoR
          rdipardo @klaus101
          last edited by

          @klaus101 said in Slight issue with plugin's toolbar bitmap when switching light/dark mode:

          DoNppnToolbarModification will be called now when a session’s mode switch happens…

          Plugins have just one opportunity to register toolbar icons when NPPN_TBMODIFICATION fires at application startup, so every icon resource handle must be provided in the body of DoNppnToolbarModification, regardless of the user’s active theme setting.

          DoNppnToolbarModification is called implicitly by the ancestor class; you simply have to implement it. The internal theme switching logic of Notepad++ will select the appropriate icon by itself.

          There’s some updated documentation to look at also.

          K 1 Reply Last reply Reply Quote 3
          • K
            klaus101 @rdipardo
            last edited by klaus101

            @rdipardo
            thanks for the reply! Btw, for not to be misunderstood, i don’t think of a bug, i think i’m missing something general, so my post here.

            DoNppnToolbarModification is called implicitly by the ancestor class ; you simply have to implement it.

            Yes of course, that’s given, called by TNppPlugin.BeNotified:

            case sn.nmhdr.code of
                   NPPN_TBMODIFICATION: begin
                     self.DoNppnToolbarModification;
            

            and implemented just equivalently to the demo, as shown above.

            every icon resource handle must be provided in the body of DoNppnToolbarModification, regardless of the user’s active theme setting.

            My first thought had been to do exactly that, via something like (which appears to be very obvious):

            HTbBmp := LoadImage(Hinstance, 'TB_BMP', IMAGE_BITMAP, bmpX, bmpY, 0);
            HTbBmpDark := LoadImage(Hinstance, 'TB_DM_BMP', IMAGE_BITMAP, bmpX, bmpY, 0);   // Separate variable here
             ...
            tb.ToolbarBmp := HTbBmp;
            tbDark.ToolbarBmp := HTbBmpDark;
            

            Just analoguesly as it’s done in funap’s explorer plugin (Explorer.cpp), shortened:

            g_explorerIcons.hToolbarBmp            = (HBITMAP)  ::LoadImage(g_hInst, MAKEINTRESOURCE(IDB_TB_EXPLORER),                  IMAGE_BITMAP,   smallIconSize.cx, smallIconSize.cy, LR_LOADMAP3DCOLORS);
            g_explorerIcons.hToolbarIconDarkMode   = (HICON)    ::LoadImage(g_hInst, MAKEINTRESOURCE(IDI_TB_FLUENT_EXPLORER_DARKMODE),  IMAGE_ICON,     smallIconSize.cx, smallIconSize.cy, LR_LOADMAP3DCOLORS);
            ::SendMessage(g_nppData._nppHandle, NPPM_ADDTOOLBARICON_DEPRECATED, (WPARAM)funcItem[DOCKABLE_EXPLORER_INDEX]._cmdID, (LPARAM)&g_explorerIcons);
            

            (but here it can be seen that for dark mode a ‘fluent’ item is loaded. A different story).

            But it simply does not work as expected. We’ll see the darkened bitmap in dark as well as in light mode. and i don’t understand why not.

            So my second approach as show in the OP.

            In short, i think it sums up to the general question: is it possible to define separate toolbar bitmaps for dark and light as small standard symbols, and will they re-picked by a settings mode switch?

            K 1 Reply Last reply Reply Quote 0
            • K
              klaus101 @klaus101
              last edited by

              @rdipardo , @PeterJones ,
              Don’t know if this question can be answered. But besides that i was wondering, why at all - as underlying reason for the question itself - the rendering of the same toolbar bitmap looked so different: in funap’s explorer plugin fine, in my test project being grayed backgrounded in dark mode.

              After some thoughts & trials i found the solution:

              // -- Replace:
                HTbBmp := LoadImage(Hinstance, 'TB_BMP', IMAGE_BITMAP, bmpX, bmpY, 0)
              // --  by:
                HTbBmp := LoadImage(Hinstance, 'TB_BMP', IMAGE_BITMAP, bmpX, bmpY, LR_LOADMAP3DCOLORS);
              

              No more need for to provide two different bitmaps …

              (There’s still a difference between both: in my case the bitmap shows a kind of ‘focus rectangle’ around when the plugin is active, whereas the other has not. But i don’t find it disturbing at all, and it’s presumably by a different setting. But maybe anybody knows why, simply for understanding).

              rdipardoR 1 Reply Last reply Reply Quote 1
              • rdipardoR
                rdipardo @klaus101
                last edited by

                @klaus101 said in Slight issue with plugin's toolbar bitmap when switching light/dark mode:

                [I]n my case the bitmap shows a kind of ‘focus rectangle’ around when the plugin is active, whereas the other has not.

                Do you mean the way a toolbar icon “glows” when its menu ID has been sent with NPPM_SETMENUITEMCHECK, as illustrated below?

                nppFSIPlugin-tb-icon-highlight.png

                If so, the flag you want is LR_LOADTRANSPARENT:

                If fuLoad includes both the LR_LOADTRANSPARENT and LR_LOADMAP3DCOLORS values, LR_LOADTRANSPARENT takes precedence. However, the color table entry is replaced with COLOR_3DFACE rather than COLOR_WINDOW.

                Also keep in mind that — as explained here — BMP icons are only displayed in the old-fashioned “standard” icon style, whereas by default the dark mode setting activates the “Fluent UI” style, which uses ICO resources.

                I’m not sure, but I suspect the “glow” effect only applies to ICOs (i.e., when the Fluent UI style is active). It also seems to depend on the operating system’s version. Windows 10 will only draw a translucent border (like the “focus rectangle” you described?); Windows 11 will brighten the entire icon, as shown above, perhaps by swapping the image with its “light mode” variant.

                K 1 Reply Last reply Reply Quote 1
                • K
                  klaus101 @rdipardo
                  last edited by klaus101

                  @rdipardo
                  many thanks for your response!
                  In fact it is so that now, where i repeated the steps for to make an illustrative image, i have to notice that i was pretty sure to have (following the windows docs) tried
                  LoadImage(… , LR_LOADMAP3DCOLORS) as well as LoadImage(… , LR_LOADTRANSPARENT) as well as LoadImage(… , LR_LOADMAP3DCOLORS or LR_LOADTRANSPARENT),
                  but something must have been wrong here, because indeed the latter version does remove this ‘glow’ also.

                  HTbBmp := LoadImage(Hinstance, 'TB_BMP', IMAGE_BITMAP, bmpX, bmpY, LR_LOADMAP3DCOLORS or LR_LOADTRANSPARENT);
                  

                  The illustration:

                  • the left image shows the example bitmap from the reference plugin, without regard if the plugin is loaded/active or not
                  • the correction using LR_LOADMAP3DCOLORS looks fully identical. But only if my plugin is not loaded. If loaded,
                    it looks somehow like ‘focused’ (but not exactly the same) -> image in the middle.
                  • the right image shows how it would look only using LR_LOADTRANSPARENT.
                    With ‘LR_LOADMAP3DCOLORS or LR_LOADTRANSPARENT’ it looks again exactly like in the left image, without regard if the plugin is loaded or not; it’s all ok.
                    Please note, the reference plugin does use this combination only for the ICOs … Not for the BMPs.
                    Illustration.jpg

                  To my interpretaton the ‘fluent’ images are an independent story, but i may be wrong here.
                  What i see is that for the plugin’s toolbar image the BMP is used, without regard of light or dark.
                  When being within Settings > preferences > general > standard icons: small.
                  The ‘fluent’ images (based on each an ICO for dark and light) come into play (imo) only when chosing the fluent UI items within this preferences, if i see right.

                  Edit: i missed to add an image for the original rendering, which had motivated this thread:
                  original_rendering.jpg

                  1 Reply Last reply Reply Quote 0
                  • K
                    klaus101
                    last edited by klaus101

                    And now - whilst i was a bit irritated why i should not have seen during my tests that indeed ‘LR_LOADMAP3DCOLORS or LR_LOADTRANSPARENT’ would remove the ‘looks like focusing’ effect too, i repeated the steps for a check. And what do i see? Hello again, the ‘focusing effect’ is back:
                    marked_active.jpg

                    Crazy & curious … and not severe, indeed. But not understandable neither …
                    as i only became aware of this because this did NOT happen with other plugins, eg. the explorer plugin.
                    But meanwhile i think it’s ‘normal’ for an active (loaded) plugin to show up with a kind of ‘active’ marker.
                    Is it as such, and i simply was misleaded by, eg., the explorers bitmap rendering?
                    At least others like JSONViewer or the HelloWorldPlugin itself use the active indicator too:
                    HelloWorld_active.jpg
                    So, maybe a simple misunderstanding … but is the marker done from the NPP core itself, or by a statement from a plugin?

                    Btw: yes, NPPM_SETMENUITEMCHECK had been called indeed (in the plugin’s “FormDock” procedure).
                    But it doesn’t make a difference if i either omit this call, or use ‘false’ for the “doCheck” parameter:

                    SafeSendMessage(self.Npp.NppData.NppHandle, NPPM_SETMENUITEMCHECK, self.CmdID, 0);
                    
                    1 Reply Last reply Reply Quote 1
                    • First post
                      Last post
                    The Community of users of the Notepad++ text editor.
                    Powered by NodeBB | Contributors