11#include < windows.h>
2+ #include < cstring>
23#include < functional>
34#include < iostream>
45#include < memory>
1314
1415namespace nativeapi {
1516
17+ HICON ImageToHICON (const Image* image, int width, int height);
18+
1619// Helper function to convert KeyboardAccelerator to Windows accelerator
1720std::pair<UINT, UINT> ConvertAccelerator (const KeyboardAccelerator& accelerator) {
1821 UINT key = 0 ;
@@ -95,6 +98,8 @@ class MenuItem::Impl {
9598 MenuItemType type_;
9699 std::optional<std::string> label_;
97100 std::shared_ptr<Image> image_;
101+ HICON menu_icon_; // Stored icon for menu item with transparency support
102+ HBITMAP menu_bitmap_; // Stored bitmap with icon drawn on menu background
98103 std::optional<std::string> tooltip_;
99104 KeyboardAccelerator accelerator_;
100105 bool has_accelerator_;
@@ -110,6 +115,8 @@ class MenuItem::Impl {
110115 : id_(id),
111116 parent_menu_ (parent_menu),
112117 type_(type),
118+ menu_icon_(nullptr ),
119+ menu_bitmap_(nullptr ),
113120 accelerator_(" " , KeyboardAccelerator::None),
114121 has_accelerator_(false ),
115122 state_(MenuItemState::Unchecked),
@@ -134,6 +141,18 @@ class MenuItem::Impl {
134141 submenu_closed_listener_id_ = 0 ;
135142 }
136143
144+ // Clean up menu icon
145+ if (menu_icon_) {
146+ DestroyIcon (menu_icon_);
147+ menu_icon_ = nullptr ;
148+ }
149+
150+ // Clean up menu bitmap
151+ if (menu_bitmap_) {
152+ DeleteObject (menu_bitmap_);
153+ menu_bitmap_ = nullptr ;
154+ }
155+
137156 // Windows menu items are automatically cleaned up when the menu is
138157 // destroyed
139158 }
@@ -225,9 +244,77 @@ std::optional<std::string> MenuItem::GetLabel() const {
225244}
226245
227246void MenuItem::SetIcon (std::shared_ptr<Image> image) {
247+ // Clean up previous resources
248+ if (pimpl_->menu_icon_ ) {
249+ DestroyIcon (pimpl_->menu_icon_ );
250+ pimpl_->menu_icon_ = nullptr ;
251+ }
252+ if (pimpl_->menu_bitmap_ ) {
253+ DeleteObject (pimpl_->menu_bitmap_ );
254+ pimpl_->menu_bitmap_ = nullptr ;
255+ }
256+
228257 pimpl_->image_ = image;
229- // Windows menu icons would require HBITMAP handling
230- // This is a placeholder implementation
258+
259+ if (image && pimpl_->parent_menu_ ) {
260+ // Use 32x32 for menu icons
261+ const int iconSize = 32 ;
262+
263+ // Convert image to HICON first for proper transparency support
264+ HICON hIcon = ImageToHICON (image.get (), iconSize, iconSize);
265+
266+ if (hIcon) {
267+ pimpl_->menu_icon_ = hIcon;
268+
269+ // Create a 32-bit ARGB bitmap
270+ HDC hdc = GetDC (nullptr );
271+
272+ // Create BITMAPINFO for 32-bit ARGB
273+ BITMAPINFO bmi = {};
274+ bmi.bmiHeader .biSize = sizeof (BITMAPINFOHEADER);
275+ bmi.bmiHeader .biWidth = iconSize;
276+ bmi.bmiHeader .biHeight = -iconSize; // Negative for top-down DIB
277+ bmi.bmiHeader .biPlanes = 1 ;
278+ bmi.bmiHeader .biBitCount = 32 ;
279+ bmi.bmiHeader .biCompression = BI_RGB;
280+
281+ void * pBits = nullptr ;
282+ HBITMAP hBmp = CreateDIBSection (hdc, &bmi, DIB_RGB_COLORS, &pBits, nullptr , 0 );
283+
284+ if (hBmp && pBits) {
285+ // Fill with system menu background color
286+ COLORREF bgColor = GetSysColor (COLOR_MENU);
287+ DWORD bgPixel = (0xFF << 24 ) | (GetRValue (bgColor) << 16 ) | (GetGValue (bgColor) << 8 ) | GetBValue (bgColor);
288+
289+ DWORD* pixels = static_cast <DWORD*>(pBits);
290+ for (int i = 0 ; i < iconSize * iconSize; i++) {
291+ pixels[i] = bgPixel; // System menu background color (ARGB)
292+ }
293+
294+ // Draw the icon on the bitmap
295+ HDC hdcMem = CreateCompatibleDC (hdc);
296+ HBITMAP hOldBmp = (HBITMAP)SelectObject (hdcMem, hBmp);
297+
298+ // Draw icon with proper blending
299+ DrawIconEx (hdcMem, 0 , 0 , hIcon, iconSize, iconSize, 0 , nullptr , DI_NORMAL);
300+
301+ SelectObject (hdcMem, hOldBmp);
302+ DeleteDC (hdcMem);
303+
304+ // Store the bitmap for cleanup
305+ pimpl_->menu_bitmap_ = hBmp;
306+
307+ // Set the bitmap on the menu item
308+ MENUITEMINFOW mii = {};
309+ mii.cbSize = sizeof (MENUITEMINFOW);
310+ mii.fMask = MIIM_BITMAP;
311+ mii.hbmpItem = hBmp;
312+ SetMenuItemInfoW (pimpl_->parent_menu_ , pimpl_->id_ , FALSE , &mii);
313+ }
314+
315+ ReleaseDC (nullptr , hdc);
316+ }
317+ }
231318}
232319
233320std::shared_ptr<Image> MenuItem::GetIcon () const {
0 commit comments