Slight issue with plugin's toolbar bitmap when switching light/dark mode
-
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.pasSee 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.
  -
-
@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 ofDoNppnToolbarModification
, 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.
-
@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?
-
@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).
-
@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?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.
-
@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.
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: