Skip to content

Commit

Permalink
Implement toolbar icons for light and dark mode
Browse files Browse the repository at this point in the history
  • Loading branch information
rdipardo committed Jan 26, 2025
1 parent 5f5cfd0 commit fad3f54
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 34 deletions.
2 changes: 2 additions & 0 deletions WebEdit/IniFiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace WebEdit
{
class IniFile(string fileName)
{
public static readonly char ValueStringDelimiter = ';';

private readonly char _keyValueSeparator = '=';
private readonly Regex _iniFileComment = new(@"^[;#]\s?");

Expand Down
119 changes: 108 additions & 11 deletions WebEdit/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@
using System.Text.RegularExpressions;
using WebEdit.Properties;
using static Npp.DotNet.Plugin.Win32;
using static Npp.DotNet.Plugin.Winforms.WinGDI;
using static Npp.DotNet.Plugin.Winforms.WinUser;

namespace WebEdit {
partial class Main : DotNetPlugin {
internal const string PluginName = "WebEdit";
private const string MenuCmdPrefix = $"{PluginName} -";
private const string IniFileName = PluginName + ".ini";
private const string Version = "2.1";
private const string MsgBoxCaption = PluginName + " " + Version;
Expand All @@ -29,6 +32,20 @@ partial class Main : DotNetPlugin {

public override void OnBeNotified(ScNotification notification)
{
if (notification.Header.HwndFrom == PluginData.NppData.NppHandle)
{
uint code = notification.Header.Code;
switch ((NppMsg)code)
{
case NppMsg.NPPN_TBMODIFICATION:
PluginData.FuncItems.RefreshItems();
AddToolbarIcons();
break;
case NppMsg.NPPN_SHUTDOWN:
PluginCleanUp();
break;
}
}
}

/// <summary>
Expand All @@ -53,7 +70,7 @@ public override void OnSetInfo()
break;

Utils.SetCommand(
key,
$"{MenuCmdPrefix} {key}",
methodInfo);
}
Utils.SetCommand(
Expand Down Expand Up @@ -108,27 +125,46 @@ internal static void About()
/// Add the toolbar icons for the menu items that have the configured
/// bitmap files in the iniDirectory folder.
/// </summary>
#pragma warning disable CS0618 // Dark mode unaware icons are deprecated since Npp v8.0
internal static void AddToolbarIcons()
{
var npp = new NotepadPPGateway();
ToolbarIcon _tbIcons = default;
ToolbarIconDarkMode tbIcons = default;
bool hasDarkMode = NppUtils.NppVersionAtLeast8;
var ini = new IniFile(iniFilePath);
foreach (string key in ini.GetKeys("Toolbar"))
try {
npp.AddToolbarIcon(
Convert.ToInt32(key) - 1,
new Bitmap(
Path.Combine(
iniDirectory,
ini.Get("Toolbar", key).Replace("\0", ""))));
} catch {
var actions = new Actions(ini);
var icons = ini.GetKeys("Toolbar");
for (int i = 0; i < actions.iniKeys.Length && i < icons.Length; ++i)
{
try
{
if (actions.GetCommand(i) == null)
continue;
MenuItemToToolbar(ini.Get("Toolbar", icons[i]).Replace("\0", ""), ref tbIcons);
// The dark mode API requires at least one ICO, or else nothing will display
if (hasDarkMode && tbIcons.HToolbarIcon != NULL)
NppUtils.Notepad.AddToolbarIcon(i, tbIcons);
else
{
_tbIcons.HToolbarBmp = tbIcons.HToolbarBmp;
_tbIcons.HToolbarIcon = tbIcons.HToolbarIcon;
NppUtils.Notepad.AddToolbarIcon(i, _tbIcons);
}
}
catch
{
// Ignore any errors like missing or corrupt bitmap files, or
// incorrect command index values.
}
}
}
#pragma warning restore CS0618

internal static void PluginCleanUp()
{
// This method is called when the plugin is notified about Npp shutdown.
PluginData.PluginNamePtr = NULL;
PluginData.FuncItems.Dispose();
}

/// <summary>
Expand Down Expand Up @@ -197,5 +233,66 @@ private static string TransformTags(string value)
value = value.Replace("\\i", " ");
return value;
}

/// <summary>
/// Parse a delimited string of 1-3 icon file names, load the icon files
/// and assign their handles to the given <paramref name="tbIcons"/> instance.
/// </summary>
private static void MenuItemToToolbar(string iniValueString, ref ToolbarIconDarkMode tbIcons)
{
string[] icons = iniValueString.Split(IniFile.ValueStringDelimiter, StringSplitOptions.RemoveEmptyEntries);
for (int i = 0; i < icons.Length; ++i)
{
string iconFileName = icons[i]?.Trim().ToLowerInvariant();
string iconExt = Path.GetExtension(iconFileName)?.ToLowerInvariant();
if (iconExt == ".bmp")
LoadToolbarIcon(LoadImageType.IMAGE_BITMAP, GetIconPath(iconFileName), out tbIcons.HToolbarBmp);
else if (iconExt == ".ico")
{
if (i == 1)
{
LoadToolbarIcon(LoadImageType.IMAGE_ICON, GetIconPath(iconFileName), out tbIcons.HToolbarIcon);
if (icons.Length < 3)
tbIcons.HToolbarIconDarkMode = tbIcons.HToolbarIcon;
}
if (i == 2)
LoadToolbarIcon(LoadImageType.IMAGE_ICON, GetIconPath(iconFileName), out tbIcons.HToolbarIconDarkMode);
}
}
}

/// <summary>
/// Load a bitmap or icon from the given file name and return the handle.
/// </summary>
private static void LoadToolbarIcon(LoadImageType imgType, string iconFile, out IntPtr hImg)
{
var loadFlags = LoadImageFlag.LR_LOADFROMFILE;
switch (imgType)
{
case LoadImageType.IMAGE_BITMAP:
(int bmpX, int bmpY) = GetLogicalPixels(16, 16);
hImg = LoadImage(NULL, iconFile, imgType, bmpX, bmpY, loadFlags | LoadImageFlag.LR_LOADMAP3DCOLORS);
break;
case LoadImageType.IMAGE_ICON:
(int icoX, int icoY) = GetLogicalPixels(32, 32);
hImg = LoadImage(NULL, iconFile, imgType, icoX, icoY, loadFlags | LoadImageFlag.LR_LOADTRANSPARENT);
break;
default:
hImg = NULL;
break;
}
}

/// <summary>
/// Return the absolute path to an icon file. The user's config directory
/// is tried first; then the plugin's installation folder.
/// </summary>
private static string GetIconPath(string icon)
{
string path = Path.Combine(NppUtils.Notepad.GetPluginConfigPath(), PluginName, icon);
if (!File.Exists(path))
path = Path.Combine(NppUtils.Notepad.GetPluginsHomePath(), PluginName, "Config", icon);
return path;
}
}
}
45 changes: 23 additions & 22 deletions WebEdit/Resources/WebEdit.ini
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,30 @@ T&r=<tr>|</tr>
; Free accelerators: bfghjkmqvwxz0789

[Toolbar]
; Syntax: <slot number>=<fileName>.bmp
; The bitmap files should be in the plugins\Config\WebEdit folder.
; Syntax: <slot number>=<fileName>.bmp;<light-mode-icon-fileName>.ico;<dark-mode-icon-fileName>.ico
; Files are loaded from the plugins\Config\WebEdit folder, if found;
; otherwise default icons installed with WebEdit.dll will be used
; Example:
1=a.bmp
2=dc.bmp
3=di.bmp
4=em.bmp
5=h1.bmp
6=h2.bmp
7=h3.bmp
8=h4.bmp
9=h5.bmp
10=h6.bmp
11=li.bmp
12=ol.bmp
13=p.bmp
14=sp.bmp
15=s.bmp
16=st.bmp
17=t.bmp
18=td.bmp
19=tr.bmp
20=ul.bmp
1=a.bmp;a.ico;a-dm.ico
2=dc.bmp;dc.ico;dc-dm.ico
3=di.bmp;di.ico;di-dm.ico
4=em.bmp;em.ico;em-dm.ico
5=h1.bmp;h1.ico;h1-dm.ico
6=h2.bmp;h2.ico;h2-dm.ico
7=h3.bmp;h3.ico;h3-dm.ico
8=h4.bmp;h4.ico;h4-dm.ico
9=h5.bmp;h5.ico;h5-dm.ico
10=h6.bmp;h6.ico;h6-dm.ico
11=li.bmp;li.ico;li-dm.ico
12=ol.bmp;ol.ico;ol-dm.ico
13=p.bmp;p.ico;p-dm.ico
14=sp.bmp;sp.ico;sp-dm.ico
15=s.bmp;s.ico;s-dm.ico
16=st.bmp;st.ico;st-dm.ico
17=t.bmp;t.ico;t-dm.ico
18=td.bmp;td.ico;td-dm.ico
19=tr.bmp;tr.ico;tr-dm.ico
20=ul.bmp;ul.ico;ul-dm.ico

[Tags]
; Tags are replaced with their Replacement when you select the
Expand Down
2 changes: 1 addition & 1 deletion WebEdit/WebEdit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Npp.DotNet.Plugin" Version="0.0.1-alpha" />
<PackageReference Include="Npp.DotNet.Plugin" Version="0.1.0-alpha.1" />
</ItemGroup>

<ItemGroup>
Expand Down

0 comments on commit fad3f54

Please sign in to comment.