Moved various DLLs to dlls/
[wine] / dlls / shell32 / shlmenu.c
1 /*
2  * see www.geocities.com/SiliconValley/4942/filemenu.html
3  */
4 #include <assert.h>
5 #include <string.h>
6
7 #include "wine/obj_base.h"
8 #include "wine/obj_enumidlist.h"
9 #include "wine/obj_shellfolder.h"
10 #include "wine/undocshell.h"
11
12 #include "heap.h"
13 #include "debugtools.h"
14 #include "winversion.h"
15 #include "shell32_main.h"
16
17 #include "pidl.h"
18
19 BOOL WINAPI FileMenu_DeleteAllItems (HMENU hMenu);
20 BOOL WINAPI FileMenu_AppendItemA(HMENU hMenu, LPCSTR lpText, UINT uID, int icon, HMENU hMenuPopup, int nItemHeight);
21
22 typedef struct
23 {       BOOL            bInitialized;
24         BOOL            bIsMagic;
25
26         /* create */
27         COLORREF        crBorderColor;
28         int             nBorderWidth;
29         HBITMAP         hBorderBmp;
30
31         /* insert using pidl */
32         LPITEMIDLIST    pidl;
33         UINT            uID;
34         UINT            uFlags;
35         UINT            uEnumFlags;
36         LPFNFMCALLBACK lpfnCallback;
37 } FMINFO, *LPFMINFO;
38
39 typedef struct
40 {       int     cchItemText;
41         int     iIconIndex;
42         HMENU   hMenu;
43         char    szItemText[1];
44 } FMITEM, * LPFMITEM;
45
46 static BOOL bAbortInit;
47
48 #define CCH_MAXITEMTEXT 256
49
50 DEFAULT_DEBUG_CHANNEL(shell)
51
52 LPFMINFO FM_GetMenuInfo(HMENU hmenu)
53 {       MENUINFO        MenuInfo;
54         LPFMINFO        menudata;
55
56         MenuInfo.cbSize = sizeof(MENUINFO);
57         MenuInfo.fMask = MIM_MENUDATA;
58
59         if (! GetMenuInfo(hmenu, &MenuInfo))
60           return NULL;
61
62         menudata = (LPFMINFO)MenuInfo.dwMenuData;
63
64         assert ((menudata != 0) && (MenuInfo.cbSize == sizeof(MENUINFO)));
65         
66         return menudata;
67
68 }
69 /*************************************************************************
70  * FM_SetMenuParameter                          [internal]
71  *
72  */
73 static LPFMINFO FM_SetMenuParameter(
74         HMENU hmenu,
75         UINT uID,
76         LPCITEMIDLIST pidl,
77         UINT uFlags,
78         UINT uEnumFlags,
79         LPFNFMCALLBACK lpfnCallback)
80 {
81         LPFMINFO        menudata;
82
83         TRACE("\n");
84         
85         menudata = FM_GetMenuInfo(hmenu);
86         
87         if ( menudata->pidl)
88         { SHFree(menudata->pidl);
89         }
90         
91         menudata->uID = uID;
92         menudata->pidl = ILClone(pidl);
93         menudata->uFlags = uFlags;
94         menudata->uEnumFlags = uEnumFlags;
95         menudata->lpfnCallback = lpfnCallback;
96
97         return menudata;
98 }
99
100 /*************************************************************************
101  * FM_InitMenuPopup                             [internal]
102  *
103  */
104 static int FM_InitMenuPopup(HMENU hmenu, LPITEMIDLIST pAlternatePidl)
105 {       IShellFolder    *lpsf, *lpsf2;
106         ULONG           ulItemAttr;
107         UINT            uID, uFlags, uEnumFlags;
108         LPFNFMCALLBACK  lpfnCallback;
109         LPITEMIDLIST    pidl;
110         char            sTemp[MAX_PATH];
111         int             NumberOfItems = 0, iIcon;
112         MENUINFO        MenuInfo;
113         LPFMINFO        menudata;
114
115         TRACE("0x%04x %p\n", hmenu, pAlternatePidl);
116
117         MenuInfo.cbSize = sizeof(MENUINFO);
118         MenuInfo.fMask = MIM_MENUDATA;
119
120         if (! GetMenuInfo(hmenu, &MenuInfo))
121           return FALSE;
122
123         menudata = (LPFMINFO)MenuInfo.dwMenuData;
124         
125         assert ((menudata != 0) && (MenuInfo.cbSize == sizeof(MENUINFO)));
126         
127         if (menudata->bInitialized)
128           return 0;
129         
130         uID = menudata->uID;
131         pidl = ((pAlternatePidl) ? pAlternatePidl : menudata->pidl);
132         uFlags = menudata->uFlags;
133         uEnumFlags = menudata->uEnumFlags;
134         lpfnCallback = menudata->lpfnCallback;
135
136         menudata->bInitialized = FALSE;
137         SetMenuInfo(hmenu, &MenuInfo);
138         
139         if (SUCCEEDED (SHGetDesktopFolder(&lpsf)))
140         {
141           if (SUCCEEDED(IShellFolder_BindToObject(lpsf, pidl,0,(REFIID)&IID_IShellFolder,(LPVOID *)&lpsf2)))
142           {
143             IEnumIDList *lpe = NULL;
144
145             if (SUCCEEDED (IShellFolder_EnumObjects(lpsf2, 0, uEnumFlags, &lpe )))
146             {
147
148               LPITEMIDLIST pidlTemp = NULL;
149               ULONG ulFetched;
150
151               while ((!bAbortInit) && (NOERROR == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched)))
152               {
153                 if (SUCCEEDED (IShellFolder_GetAttributesOf(lpsf, 1, &pidlTemp, &ulItemAttr)))
154                 {
155                   ILGetDisplayName( pidlTemp, sTemp);
156                   if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, &iIcon)))
157                     iIcon = FM_BLANK_ICON;
158                   if ( SFGAO_FOLDER & ulItemAttr)
159                   {
160                     LPFMINFO lpFmMi;
161                     MENUINFO MenuInfo;
162                     HMENU hMenuPopup = CreatePopupMenu();
163         
164                     lpFmMi = (LPFMINFO) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
165
166                     lpFmMi->pidl = ILCombine(pidl, pidlTemp);
167                     lpFmMi->uEnumFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
168
169                     MenuInfo.cbSize = sizeof(MENUINFO);
170                     MenuInfo.fMask = MIM_MENUDATA;
171                     MenuInfo.dwMenuData = (DWORD) lpFmMi;
172                     SetMenuInfo (hMenuPopup, &MenuInfo);
173
174                     FileMenu_AppendItemA (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT);
175                   }
176                   else
177                   {
178                     ((LPSTR)PathFindExtensionA(sTemp))[0] = 0x00;
179                     FileMenu_AppendItemA (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT);
180                   }
181                 }
182
183                 if (lpfnCallback)
184                 {
185                   TRACE("enter callback\n");
186                   lpfnCallback ( pidl, pidlTemp);
187                   TRACE("leave callback\n");
188                 }
189
190                 NumberOfItems++;
191               }
192               IEnumIDList_Release (lpe);
193             }
194             IShellFolder_Release(lpsf2);
195           }
196           IShellFolder_Release(lpsf);
197         }
198
199         if ( GetMenuItemCount (hmenu) == 0 )
200         { FileMenu_AppendItemA (hmenu, "(empty)", uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT);
201           NumberOfItems++;
202         }
203
204         menudata->bInitialized = TRUE;
205         SetMenuInfo(hmenu, &MenuInfo);
206
207         return NumberOfItems;
208 }
209 /*************************************************************************
210  * FileMenu_Create                              [SHELL32.114]
211  *
212  */
213 HMENU WINAPI FileMenu_Create (
214         COLORREF crBorderColor,
215         int nBorderWidth,
216         HBITMAP hBorderBmp,
217         int nSelHeight,
218         UINT uFlags)
219 {
220         MENUINFO        MenuInfo;
221         LPFMINFO        menudata;
222
223         HMENU hMenu = CreatePopupMenu();
224
225         TRACE("0x%08lx 0x%08x 0x%08x 0x%08x 0x%08x  hMenu=0x%08x\n",
226         crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu);
227
228         menudata = (LPFMINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
229         menudata->bIsMagic = TRUE;
230         menudata->crBorderColor = crBorderColor;
231         menudata->nBorderWidth = nBorderWidth;
232         menudata->hBorderBmp = hBorderBmp;
233
234         MenuInfo.cbSize = sizeof(MENUINFO);
235         MenuInfo.fMask = MIM_MENUDATA;
236         MenuInfo.dwMenuData = (DWORD) menudata;
237         SetMenuInfo (hMenu, &MenuInfo);
238
239         return hMenu;
240 }
241
242 /*************************************************************************
243  * FileMenu_Destroy                             [SHELL32.118]
244  *
245  * NOTES
246  *  exported by name
247  */
248 void WINAPI FileMenu_Destroy (HMENU hmenu)
249 {
250         LPFMINFO        menudata;
251
252         TRACE("0x%08x\n", hmenu);
253
254         FileMenu_DeleteAllItems (hmenu);
255         
256         menudata = FM_GetMenuInfo(hmenu);
257
258         if ( menudata->pidl)
259         { SHFree( menudata->pidl);
260         }
261         HeapFree(GetProcessHeap(), 0, menudata);
262
263         DestroyMenu (hmenu);
264 }
265
266 /*************************************************************************
267  * FileMenu_AppendItemAW                        [SHELL32.115]
268  *
269  */
270 BOOL WINAPI FileMenu_AppendItemA(
271         HMENU hMenu,
272         LPCSTR lpText,
273         UINT uID,
274         int icon,
275         HMENU hMenuPopup,
276         int nItemHeight)
277 {
278         LPSTR lpszText = (LPSTR)lpText;
279         MENUITEMINFOA   mii;
280         LPFMITEM myItem;
281
282         TRACE("0x%08x %s 0x%08x 0x%08x 0x%08x 0x%08x\n",
283         hMenu, (lpszText!=FM_SEPARATOR) ? lpText: NULL,
284         uID, icon, hMenuPopup, nItemHeight);
285         
286         ZeroMemory (&mii, sizeof(MENUITEMINFOA));
287         
288         mii.cbSize = sizeof(MENUITEMINFOA);
289
290         if (lpText != FM_SEPARATOR)
291         { int len = strlen (lpText);
292           myItem = (LPFMITEM) SHAlloc( sizeof(FMITEM) + len);
293           strcpy (myItem->szItemText, lpText);
294           myItem->cchItemText = len;
295           myItem->iIconIndex = icon;
296           myItem->hMenu = hMenu;
297           mii.fMask = MIIM_DATA;
298           mii.dwItemData = (DWORD) myItem;
299         }
300         
301         if ( hMenuPopup )
302         { /* sub menu */
303           mii.fMask |= MIIM_TYPE | MIIM_SUBMENU;
304           mii.fType = MFT_OWNERDRAW;
305           mii.hSubMenu = hMenuPopup;
306         }
307         else if (lpText == FM_SEPARATOR )
308         { mii.fMask |= MIIM_ID | MIIM_TYPE;
309           mii.fType = MFT_SEPARATOR;
310         }
311         else
312         { /* normal item */
313           mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE;
314           mii.fState = MFS_ENABLED | MFS_DEFAULT;
315           mii.fType = MFT_OWNERDRAW;
316         }
317         mii.wID = uID;
318
319         InsertMenuItemA (hMenu, (UINT)-1, TRUE, &mii);
320
321         return TRUE;
322
323 }
324 BOOL WINAPI FileMenu_AppendItemAW(
325         HMENU hMenu,
326         LPCVOID lpText,
327         UINT uID,
328         int icon,
329         HMENU hMenuPopup,
330         int nItemHeight)
331 {
332         BOOL ret;
333         LPSTR lpszText=NULL;
334
335         if (VERSION_OsIsUnicode() && (lpText!=FM_SEPARATOR))
336           lpszText = HEAP_strdupWtoA ( GetProcessHeap(),0, lpText);
337
338         ret = FileMenu_AppendItemA(hMenu, (lpszText) ? lpszText : lpText, uID, icon, hMenuPopup, nItemHeight);
339
340         if (lpszText)
341           HeapFree( GetProcessHeap(), 0, lpszText );
342
343         return ret;
344 }
345 /*************************************************************************
346  * FileMenu_InsertUsingPidl                     [SHELL32.110]
347  *
348  * NOTES
349  *      uEnumFlags      any SHCONTF flag
350  */
351 int WINAPI FileMenu_InsertUsingPidl (
352         HMENU hmenu,
353         UINT uID,
354         LPCITEMIDLIST pidl,
355         UINT uFlags,
356         UINT uEnumFlags,
357         LPFNFMCALLBACK lpfnCallback)
358 {       
359         TRACE("0x%08x 0x%08x %p 0x%08x 0x%08x %p\n",
360         hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
361
362         pdump (pidl);
363
364         bAbortInit = FALSE;
365
366         FM_SetMenuParameter(hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);        
367
368         return FM_InitMenuPopup(hmenu, NULL);
369 }
370
371 /*************************************************************************
372  * FileMenu_ReplaceUsingPidl                    [SHELL32.113]
373  *
374  */
375 int WINAPI FileMenu_ReplaceUsingPidl(
376         HMENU   hmenu,
377         UINT    uID,
378         LPCITEMIDLIST   pidl,
379         UINT    uEnumFlags,
380         LPFNFMCALLBACK lpfnCallback)
381 {
382         TRACE("0x%08x 0x%08x %p 0x%08x %p\n",
383         hmenu, uID, pidl, uEnumFlags, lpfnCallback);
384         
385         FileMenu_DeleteAllItems (hmenu);
386
387         FM_SetMenuParameter(hmenu, uID, pidl, 0, uEnumFlags, lpfnCallback);     
388
389         return FM_InitMenuPopup(hmenu, NULL);
390 }
391
392 /*************************************************************************
393  * FileMenu_Invalidate                  [SHELL32.111]
394  */
395 void WINAPI FileMenu_Invalidate (HMENU hMenu)
396 {
397         FIXME("0x%08x\n",hMenu);        
398 }
399
400 /*************************************************************************
401  * FileMenu_FindSubMenuByPidl                   [SHELL32.106]
402  */
403 HMENU WINAPI FileMenu_FindSubMenuByPidl(
404         HMENU   hMenu,
405         LPCITEMIDLIST   pidl)
406 {
407         FIXME("0x%08x %p\n",hMenu, pidl);       
408         return 0;
409 }
410
411 /*************************************************************************
412  * FileMenu_AppendFilesForPidl                  [SHELL32.124]
413  */
414 HMENU WINAPI FileMenu_AppendFilesForPidl(
415         HMENU   hmenu,
416         LPCITEMIDLIST   pidl,
417         BOOL    bAddSeperator)
418 {
419         LPFMINFO        menudata;
420
421         menudata = FM_GetMenuInfo(hmenu);
422         
423         menudata->bInitialized = FALSE;
424         
425         FM_InitMenuPopup(hmenu, pidl);
426
427         if (bAddSeperator)
428           FileMenu_AppendItemA (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT);
429
430         TRACE("0x%08x %p 0x%08x\n",hmenu, pidl,bAddSeperator);  
431
432         return 0;
433 }
434 /*************************************************************************
435  * FileMenu_AddFilesForPidl                     [SHELL32.125]
436  *
437  * NOTES
438  *      uEnumFlags      any SHCONTF flag
439  */
440 int WINAPI FileMenu_AddFilesForPidl (
441         HMENU   hmenu,
442         UINT    uReserved,
443         UINT    uID,
444         LPCITEMIDLIST   pidl,
445         UINT    uFlags,
446         UINT    uEnumFlags,
447         LPFNFMCALLBACK  lpfnCallback)
448 {
449         TRACE("0x%08x 0x%08x 0x%08x %p 0x%08x 0x%08x %p\n",
450         hmenu, uReserved, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
451
452         return FileMenu_InsertUsingPidl ( hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
453
454 }
455
456
457 /*************************************************************************
458  * FileMenu_TrackPopupMenuEx                    [SHELL32.116]
459  */
460 HRESULT WINAPI FileMenu_TrackPopupMenuEx (
461         HMENU hMenu,
462         UINT uFlags,
463         int x,
464         int y,
465         HWND hWnd,
466         LPTPMPARAMS lptpm)
467 {
468         TRACE("0x%08x 0x%08x 0x%x 0x%x 0x%08x %p\n",
469         hMenu, uFlags, x, y, hWnd, lptpm);
470         return TrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, lptpm);
471 }
472
473 /*************************************************************************
474  * FileMenu_GetLastSelectedItemPidls            [SHELL32.107]
475  */
476 BOOL WINAPI FileMenu_GetLastSelectedItemPidls(
477         UINT    uReserved,
478         LPCITEMIDLIST   *ppidlFolder,
479         LPCITEMIDLIST   *ppidlItem)
480 {
481         FIXME("0x%08x %p %p\n",uReserved, ppidlFolder, ppidlItem);
482         return 0;
483 }
484
485 #define FM_ICON_SIZE    16
486 #define FM_Y_SPACE      4
487 #define FM_SPACE1       4
488 #define FM_SPACE2       2
489 #define FM_LEFTBORDER   2
490 #define FM_RIGHTBORDER  8
491 /*************************************************************************
492  * FileMenu_MeasureItem                         [SHELL32.112]
493  */
494 LRESULT WINAPI FileMenu_MeasureItem(
495         HWND    hWnd,
496         LPMEASUREITEMSTRUCT     lpmis)
497 {
498         LPFMITEM pMyItem = (LPFMITEM)(lpmis->itemData);
499         HDC hdc = GetDC(hWnd);
500         SIZE size;
501         LPFMINFO menuinfo;
502                 
503         TRACE("0x%08x %p %s\n", hWnd, lpmis, pMyItem->szItemText);
504         
505         GetTextExtentPoint32A(hdc, pMyItem->szItemText, pMyItem->cchItemText, &size);
506         
507         lpmis->itemWidth = size.cx + FM_LEFTBORDER + FM_ICON_SIZE + FM_SPACE1 + FM_SPACE2 + FM_RIGHTBORDER;
508         lpmis->itemHeight = (size.cy > (FM_ICON_SIZE + FM_Y_SPACE)) ? size.cy : (FM_ICON_SIZE + FM_Y_SPACE);
509
510         /* add the menubitmap */
511         menuinfo = FM_GetMenuInfo(pMyItem->hMenu);
512         if (menuinfo->bIsMagic)
513           lpmis->itemWidth += menuinfo->nBorderWidth;
514         
515         TRACE("-- 0x%04x 0x%04x\n", lpmis->itemWidth, lpmis->itemHeight);
516         ReleaseDC (hWnd, hdc);
517         return 0;
518 }
519 /*************************************************************************
520  * FileMenu_DrawItem                            [SHELL32.105]
521  */
522 LRESULT WINAPI FileMenu_DrawItem(
523         HWND                    hWnd,
524         LPDRAWITEMSTRUCT        lpdis)
525 {
526         LPFMITEM pMyItem = (LPFMITEM)(lpdis->itemData);
527         COLORREF clrPrevText, clrPrevBkgnd;
528         int xi,yi,xt,yt;
529         HIMAGELIST hImageList;
530         RECT TextRect, BorderRect;
531         LPFMINFO menuinfo;
532         
533         TRACE("0x%08x %p %s\n", hWnd, lpdis, pMyItem->szItemText);
534         
535         if (lpdis->itemState & ODS_SELECTED)
536         {
537           clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHTTEXT));
538           clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHT));
539         }
540         else
541         {
542           clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_MENUTEXT));
543           clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_MENU));
544         }
545         
546         CopyRect(&TextRect, &(lpdis->rcItem));
547
548         /* add the menubitmap */
549         menuinfo = FM_GetMenuInfo(pMyItem->hMenu);
550         if (menuinfo->bIsMagic)
551           TextRect.left += menuinfo->nBorderWidth;
552         
553         BorderRect.right = menuinfo->nBorderWidth;
554 /*      FillRect(lpdis->hDC, &BorderRect, CreateSolidBrush( menuinfo->crBorderColor));
555 */
556         TextRect.left += FM_LEFTBORDER;
557         xi = TextRect.left + FM_SPACE1;
558         yi = TextRect.top + FM_Y_SPACE/2;
559         TextRect.bottom -= FM_Y_SPACE/2;
560
561         xt = xi + FM_ICON_SIZE + FM_SPACE2;
562         yt = yi;
563
564         ExtTextOutA (lpdis->hDC, xt , yt, ETO_OPAQUE, &TextRect, pMyItem->szItemText, pMyItem->cchItemText, NULL);
565         
566         Shell_GetImageList(0, &hImageList);
567         pImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL);
568
569         TRACE("-- 0x%04x 0x%04x 0x%04x 0x%04x\n", TextRect.left, TextRect.top, TextRect.right, TextRect.bottom);
570         
571         SetTextColor(lpdis->hDC, clrPrevText);
572         SetBkColor(lpdis->hDC, clrPrevBkgnd);
573
574         return TRUE;
575 }
576
577 /*************************************************************************
578  * FileMenu_InitMenuPopup                       [SHELL32.109]
579  *
580  * NOTES
581  *  The filemenu is a ownerdrawn menu. Call this function responding to 
582  *  WM_INITPOPUPMENU
583  *
584  */
585 BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu)
586 {
587         FM_InitMenuPopup(hmenu, NULL);
588         return TRUE;
589 }
590
591 /*************************************************************************
592  * FileMenu_HandleMenuChar                      [SHELL32.108]
593  */
594 LRESULT WINAPI FileMenu_HandleMenuChar(
595         HMENU   hMenu,
596         WPARAM  wParam)
597 {
598         FIXME("0x%08x 0x%08x\n",hMenu,wParam);
599         return 0;
600 }
601
602 /*************************************************************************
603  * FileMenu_DeleteAllItems                      [SHELL32.104]
604  *
605  * NOTES
606  *  exported by name
607  */
608 BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu)
609 {       
610         MENUITEMINFOA   mii;
611         LPFMINFO        menudata;
612
613         int i;
614         
615         TRACE("0x%08x\n", hmenu);
616         
617         ZeroMemory ( &mii, sizeof(MENUITEMINFOA));
618         mii.cbSize = sizeof(MENUITEMINFOA);
619         mii.fMask = MIIM_SUBMENU|MIIM_DATA;
620
621         for (i = 0; i < GetMenuItemCount( hmenu ); i++)
622         { GetMenuItemInfoA(hmenu, i, TRUE, &mii );
623
624           if (mii.dwItemData)
625             SHFree((LPFMINFO)mii.dwItemData);
626
627           if (mii.hSubMenu)
628             FileMenu_Destroy(mii.hSubMenu);
629         }
630         
631         while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){};
632
633         menudata = FM_GetMenuInfo(hmenu);
634         
635         menudata->bInitialized = FALSE;
636         
637         return TRUE;
638 }
639
640 /*************************************************************************
641  * FileMenu_DeleteItemByCmd                     [SHELL32.]
642  *
643  */
644 BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID)
645 {
646         MENUITEMINFOA mii;
647
648         TRACE("0x%08x 0x%08x\n", hMenu, uID);
649         
650         ZeroMemory ( &mii, sizeof(MENUITEMINFOA));
651         mii.cbSize = sizeof(MENUITEMINFOA);
652         mii.fMask = MIIM_SUBMENU;
653
654         GetMenuItemInfoA(hMenu, uID, FALSE, &mii );
655         if ( mii.hSubMenu );
656
657         DeleteMenu(hMenu, MF_BYCOMMAND, uID);
658         return TRUE;
659 }
660
661 /*************************************************************************
662  * FileMenu_DeleteItemByIndex                   [SHELL32.140]
663  */
664 BOOL WINAPI FileMenu_DeleteItemByIndex ( HMENU hMenu, UINT uPos)
665 {
666         MENUITEMINFOA mii;
667
668         TRACE("0x%08x 0x%08x\n", hMenu, uPos);
669
670         ZeroMemory ( &mii, sizeof(MENUITEMINFOA));
671         mii.cbSize = sizeof(MENUITEMINFOA);
672         mii.fMask = MIIM_SUBMENU;
673
674         GetMenuItemInfoA(hMenu, uPos, TRUE, &mii );
675         if ( mii.hSubMenu );
676
677         DeleteMenu(hMenu, MF_BYPOSITION, uPos);
678         return TRUE;
679 }
680
681 /*************************************************************************
682  * FileMenu_DeleteItemByFirstID                 [SHELL32.141]
683  */
684 BOOL WINAPI FileMenu_DeleteItemByFirstID(
685         HMENU   hMenu,
686         UINT    uID)
687 {
688         TRACE("0x%08x 0x%08x\n", hMenu, uID);
689         return 0;
690 }
691
692 /*************************************************************************
693  * FileMenu_DeleteSeparator                     [SHELL32.142]
694  */
695 BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu)
696 {
697         TRACE("0x%08x\n", hMenu);
698         return 0;
699 }
700
701 /*************************************************************************
702  * FileMenu_EnableItemByCmd                     [SHELL32.143]
703  */
704 BOOL WINAPI FileMenu_EnableItemByCmd(
705         HMENU   hMenu,
706         UINT    uID,
707         BOOL    bEnable)
708 {
709         TRACE("0x%08x 0x%08x 0x%08x\n", hMenu, uID,bEnable);
710         return 0;
711 }
712
713 /*************************************************************************
714  * FileMenu_GetItemExtent                       [SHELL32.144]
715  * 
716  * NOTES
717  *  if the menu is to big, entrys are getting cut away!!
718  */
719 DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos)
720 {       RECT rect;
721         
722         FIXME("0x%08x 0x%08x\n", hMenu, uPos);
723
724         if (GetMenuItemRect(0, hMenu, uPos, &rect))
725         { FIXME("0x%04x 0x%04x 0x%04x 0x%04x\n",
726           rect.right, rect.left, rect.top, rect.bottom);
727           return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom);
728         }
729         return 0x00100010; /*fixme*/
730 }
731
732 /*************************************************************************
733  * FileMenu_AbortInitMenu                       [SHELL32.120]
734  *
735  */
736 void WINAPI FileMenu_AbortInitMenu (void)
737 {       TRACE("\n");
738         bAbortInit = TRUE;
739 }
740
741 /*************************************************************************
742  * SHFind_InitMenuPopup                         [SHELL32.149]
743  *
744  *
745  * PARAMETERS
746  *  hMenu               [in] handel of menu previously created
747  *  hWndParent  [in] parent window
748  *  w                   [in] no pointer
749  *  x                   [in] no pointer
750  */
751 HRESULT WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, DWORD w, DWORD x)
752 {       FIXME("hmenu=0x%08x hwnd=0x%08x 0x%08lx 0x%08lx stub\n",
753                 hMenu,hWndParent,w,x);
754         return TRUE;
755 }
756
757 /*************************************************************************
758  * Shell_MergeMenus                             [SHELL32.67]
759  *
760  */
761 BOOL _SHIsMenuSeparator(HMENU hm, int i)
762 {
763         MENUITEMINFOA mii;
764
765         mii.cbSize = sizeof(MENUITEMINFOA);
766         mii.fMask = MIIM_TYPE;
767         mii.cch = 0;    /* WARNING: We MUST initialize it to 0*/
768         if (!GetMenuItemInfoA(hm, i, TRUE, &mii))
769         {
770           return(FALSE);
771         }
772
773         if (mii.fType & MFT_SEPARATOR)
774         {
775           return(TRUE);
776         }
777
778         return(FALSE);
779 }
780
781 HRESULT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
782 {       int             nItem;
783         HMENU           hmSubMenu;
784         BOOL            bAlreadySeparated;
785         MENUITEMINFOA   miiSrc;
786         char            szName[256];
787         UINT            uTemp, uIDMax = uIDAdjust;
788
789         TRACE("hmenu1=0x%04x hmenu2=0x%04x 0x%04x 0x%04x 0x%04x  0x%04lx\n",
790                  hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags);
791
792         if (!hmDst || !hmSrc)
793         { return uIDMax;
794         }
795
796         nItem = GetMenuItemCount(hmDst);
797
798         if (uInsert >= (UINT)nItem)     /* insert position inside menu? */
799         {
800           uInsert = (UINT)nItem;        /* append on the end */
801           bAlreadySeparated = TRUE;
802         }
803         else
804         {
805           bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);;
806         }
807
808         if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
809         {
810           /* Add a separator between the menus */
811           InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
812           bAlreadySeparated = TRUE;
813         }
814
815
816         /* Go through the menu items and clone them*/
817         for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--)
818         {
819           miiSrc.cbSize = sizeof(MENUITEMINFOA);
820           miiSrc.fMask =  MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;
821
822           /* We need to reset this every time through the loop in case menus DON'T have IDs*/
823           miiSrc.fType = MFT_STRING;
824           miiSrc.dwTypeData = szName;
825           miiSrc.dwItemData = 0;
826           miiSrc.cch = sizeof(szName);
827
828           if (!GetMenuItemInfoA(hmSrc, nItem, TRUE, &miiSrc))
829           {
830             continue;
831           }
832
833 /*        TRACE("found menu=0x%04x %s id=0x%04x mask=0x%08x smenu=0x%04x\n", hmSrc, debugstr_a(miiSrc.dwTypeData), miiSrc.wID, miiSrc.fMask,  miiSrc.hSubMenu);
834 */
835           if (miiSrc.fType & MFT_SEPARATOR)
836           {
837             /* This is a separator; don't put two of them in a row */
838             if (bAlreadySeparated)
839               continue;
840
841             bAlreadySeparated = TRUE;
842           }
843           else if (miiSrc.hSubMenu)
844           {
845             if (uFlags & MM_SUBMENUSHAVEIDS)
846             {
847               miiSrc.wID += uIDAdjust;                  /* add uIDAdjust to the ID */
848
849               if (miiSrc.wID > uIDAdjustMax)            /* skip ID's higher uIDAdjustMax */
850                 continue;
851
852               if (uIDMax <= miiSrc.wID)                 /* remember the highest ID */
853                 uIDMax = miiSrc.wID + 1;
854             }
855             else
856             {
857               miiSrc.fMask &= ~MIIM_ID;                 /* Don't set IDs for submenus that didn't have them already */
858             }
859             hmSubMenu = miiSrc.hSubMenu;
860
861             miiSrc.hSubMenu = CreatePopupMenu();
862
863             if (!miiSrc.hSubMenu) return(uIDMax);
864
865             uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS);
866
867             if (uIDMax <= uTemp)
868               uIDMax = uTemp;
869
870             bAlreadySeparated = FALSE;
871           }
872           else                                          /* normal menu item */
873           {
874             miiSrc.wID += uIDAdjust;                    /* add uIDAdjust to the ID */
875
876             if (miiSrc.wID > uIDAdjustMax)              /* skip ID's higher uIDAdjustMax */
877               continue;
878
879             if (uIDMax <= miiSrc.wID)                   /* remember the highest ID */
880               uIDMax = miiSrc.wID + 1;
881
882             bAlreadySeparated = FALSE;
883           }
884
885 /*        TRACE("inserting menu=0x%04x %s id=0x%04x mask=0x%08x smenu=0x%04x\n", hmDst, debugstr_a(miiSrc.dwTypeData), miiSrc.wID, miiSrc.fMask, miiSrc.hSubMenu);
886 */
887           if (!InsertMenuItemA(hmDst, uInsert, TRUE, &miiSrc))
888           {
889             return(uIDMax);
890           }
891         }
892
893         /* Ensure the correct number of separators at the beginning of the
894         inserted menu items*/
895         if (uInsert == 0)
896         {
897           if (bAlreadySeparated)
898           {
899             DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
900           }
901         }
902         else
903         {
904           if (_SHIsMenuSeparator(hmDst, uInsert-1))
905           {
906             if (bAlreadySeparated)
907             {
908               DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
909             }
910           }
911           else
912           {
913             if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
914             {
915               /* Add a separator between the menus*/
916               InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
917             }
918           }
919         }
920         return(uIDMax);
921 }
922