Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

470 lines
12 KiB

  1. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // MMENU.CPP: Defines custom menu interface for multimedia applet
  4. //
  5. // Copyright (c) Microsoft Corporation 1998
  6. //
  7. // 1/28/98 David Stewart / dstewart
  8. //
  9. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  10. #include "windows.h"
  11. #include "mmenu.h"
  12. #include "tchar.h"
  13. #include "resource.h"
  14. #define ICON_SPACING 3
  15. extern HINSTANCE hInst;
  16. typedef struct ownermenu
  17. {
  18. TCHAR szText[MAX_PATH];
  19. HICON hIcon;
  20. } OWNERMENU, *LPOWNERMENU;
  21. HRESULT AllocCustomMenu(CustomMenu** ppMenu)
  22. {
  23. *ppMenu = new CCustomMenu();
  24. if (*ppMenu==NULL)
  25. {
  26. return E_OUTOFMEMORY;
  27. }
  28. return S_OK;
  29. }
  30. CCustomMenu::CCustomMenu()
  31. {
  32. m_hMenu = CreatePopupMenu();
  33. //get system font for any owner drawing
  34. NONCLIENTMETRICS metrics;
  35. metrics.cbSize = sizeof(metrics);
  36. SystemParametersInfo(SPI_GETNONCLIENTMETRICS,sizeof(metrics),&metrics,0);
  37. m_hFont = CreateFontIndirect(&metrics.lfMenuFont);
  38. if (metrics.lfMenuFont.lfCharSet == ANSI_CHARSET)
  39. {
  40. metrics.lfMenuFont.lfWeight = FW_BOLD;
  41. }
  42. m_hBoldFont = CreateFontIndirect(&metrics.lfMenuFont);
  43. if (IsBiDiLocalizedSystem(NULL))
  44. {
  45. m_bRTLMenu = TRUE;
  46. }
  47. else
  48. {
  49. m_bRTLMenu = FALSE;
  50. }
  51. }
  52. CCustomMenu::~CCustomMenu()
  53. {
  54. //clean up string data in menus
  55. int x = GetMenuItemCount(m_hMenu);
  56. for (int i = 0; i < x; i++)
  57. {
  58. MENUITEMINFO mii;
  59. ZeroMemory(&mii,sizeof(mii));
  60. mii.cbSize = sizeof(mii);
  61. mii.fMask = MIIM_DATA|MIIM_TYPE;
  62. GetMenuItemInfo(m_hMenu,i,TRUE,&mii);
  63. if ((mii.dwItemData!=0) && (mii.fType & MFT_OWNERDRAW))
  64. {
  65. OWNERMENU* pMenu = (OWNERMENU*)mii.dwItemData;
  66. if (pMenu)
  67. {
  68. DestroyIcon(pMenu->hIcon);
  69. delete [] pMenu;
  70. }
  71. }
  72. }
  73. DestroyMenu(m_hMenu);
  74. DeleteObject(m_hFont);
  75. DeleteObject(m_hBoldFont);
  76. }
  77. void CCustomMenu::Destroy()
  78. {
  79. delete this;
  80. }
  81. BOOL CCustomMenu::AppendMenu(HINSTANCE hInst, int nStringID, CustomMenu* pMenu)
  82. {
  83. TCHAR szMenu[MAX_PATH];
  84. LoadString(hInst,nStringID,szMenu,sizeof(szMenu)/sizeof(TCHAR));
  85. return ::AppendMenu(m_hMenu,MF_STRING|MF_POPUP,(UINT_PTR)pMenu->GetMenuHandle(),szMenu);
  86. }
  87. BOOL CCustomMenu::AppendMenu(int nMenuID, TCHAR* szMenu)
  88. {
  89. return ::AppendMenu(m_hMenu,MF_STRING,nMenuID,szMenu);
  90. }
  91. BOOL CCustomMenu::AppendMenu(int nMenuID, HINSTANCE hInst, int nStringID)
  92. {
  93. TCHAR szMenu[MAX_PATH];
  94. LoadString(hInst,nStringID,szMenu,sizeof(szMenu)/sizeof(TCHAR));
  95. return ::AppendMenu(m_hMenu,MF_STRING,nMenuID,szMenu);
  96. }
  97. BOOL CCustomMenu::AppendSeparator()
  98. {
  99. return ::AppendMenu(m_hMenu,MF_SEPARATOR,0,0);
  100. }
  101. BOOL CCustomMenu::AppendMenu(int nMenuID, HINSTANCE hInst, int nIconID, int nStringID)
  102. {
  103. OWNERMENU* pMenu = new OWNERMENU;
  104. if (!pMenu)
  105. {
  106. return FALSE;
  107. }
  108. LoadString(hInst,nStringID,pMenu->szText,sizeof(pMenu->szText)/sizeof(TCHAR));
  109. int cxMiniIcon = (int)GetSystemMetrics(SM_CXSMICON);
  110. int cyMiniIcon = (int)GetSystemMetrics(SM_CYSMICON);
  111. pMenu->hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(nIconID), IMAGE_ICON, cxMiniIcon, cyMiniIcon, LR_DEFAULTCOLOR);
  112. BOOL fAppend = ::AppendMenu(m_hMenu,MF_OWNERDRAW,nMenuID,(LPTSTR)pMenu);
  113. if (fAppend)
  114. {
  115. //this code allows the owner-draw menu to have text that can be read
  116. //by narrator and other apps that help with accessibility.
  117. MENUITEMINFO mii;
  118. memset(&mii, 0, sizeof(MENUITEMINFO));
  119. mii.cbSize = sizeof(MENUITEMINFO);
  120. mii.fMask = MIIM_STRING;
  121. mii.dwTypeData = pMenu->szText;
  122. mii.cch = sizeof (pMenu->szText) / sizeof(TCHAR);
  123. ::SetMenuItemInfo(m_hMenu,nMenuID,FALSE,&mii);
  124. }
  125. return (fAppend);
  126. }
  127. BOOL CCustomMenu::TrackPopupMenu(UINT uFlags, int x, int y, HWND hwnd, CONST RECT* pRect)
  128. {
  129. TPMPARAMS tpm;
  130. tpm.cbSize = sizeof(tpm);
  131. memcpy(&(tpm.rcExclude),pRect,sizeof(RECT));
  132. // if m_bRTLMenu then make the menu is right aligned and RTL reading.
  133. if (m_bRTLMenu) {
  134. MENUITEMINFO mii;
  135. TCHAR szMenuString[MAX_PATH];
  136. memset(&mii, 0, sizeof(MENUITEMINFO));
  137. mii.cbSize = sizeof(MENUITEMINFO);
  138. mii.fMask = MIIM_TYPE;
  139. mii.dwTypeData = szMenuString;
  140. mii.cch = sizeof (szMenuString) / sizeof(TCHAR);
  141. if ((mii.fType != MFT_OWNERDRAW) && (mii.fType != MFT_BITMAP)) {
  142. if(GetMenuItemInfo(m_hMenu, 0, TRUE, &mii)) {
  143. mii.fType |= (MFT_RIGHTORDER | MFT_RIGHTJUSTIFY);
  144. SetMenuItemInfo(m_hMenu, 0, TRUE, &mii);
  145. }
  146. }
  147. }
  148. return ::TrackPopupMenuEx(m_hMenu,uFlags,x,y,hwnd,&tpm);
  149. }
  150. BOOL CCustomMenu::SetMenuDefaultItem(UINT uItem, UINT fByPos)
  151. {
  152. return ::SetMenuDefaultItem(m_hMenu,uItem,fByPos);
  153. }
  154. void CCustomMenu::MeasureItem(HWND hwnd, LPMEASUREITEMSTRUCT pMeasure)
  155. {
  156. OWNERMENU* szMenu = (OWNERMENU*)pMeasure->itemData;
  157. int cxMiniIcon = (int)GetSystemMetrics(SM_CXSMICON);
  158. int cyMiniIcon = (int)GetSystemMetrics(SM_CYSMICON);
  159. HDC hdc = GetDC(hwnd);
  160. HFONT hOrgFont = (HFONT)SelectObject(hdc,m_hBoldFont);
  161. SIZE size;
  162. GetTextExtentPoint32(hdc, szMenu->szText, _tcslen(szMenu->szText), &size );
  163. pMeasure->itemWidth = size.cx + cxMiniIcon + (ICON_SPACING*2);
  164. pMeasure->itemHeight = max(cyMiniIcon,size.cy);
  165. SelectObject(hdc,hOrgFont);
  166. ReleaseDC(hwnd,hdc);
  167. }
  168. void CCustomMenu::DrawItem(HWND hwnd, LPDRAWITEMSTRUCT pDraw)
  169. {
  170. OWNERMENU* szMenu = (OWNERMENU*)pDraw->itemData;
  171. HDC hdc = pDraw->hDC;
  172. COLORREF colorFill = GetSysColor(COLOR_MENU);
  173. COLORREF colorText = GetSysColor(COLOR_MENUTEXT);
  174. if (pDraw->itemState & ODS_SELECTED)
  175. {
  176. colorFill = GetSysColor(COLOR_HIGHLIGHT);
  177. colorText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  178. }
  179. HBRUSH hbrBack = CreateSolidBrush(GetSysColor(COLOR_MENU));
  180. //blit the icon, always with menu color background
  181. int cxMiniIcon = (int)GetSystemMetrics(SM_CXSMICON);
  182. int cyMiniIcon = (int)GetSystemMetrics(SM_CYSMICON);
  183. // if m_bRTLMenu then draw the icon on the right hand side.
  184. if (m_bRTLMenu) {
  185. DrawIconEx(hdc,pDraw->rcItem.right - cxMiniIcon,pDraw->rcItem.top,szMenu->hIcon,cxMiniIcon,cyMiniIcon,0,hbrBack,DI_NORMAL);
  186. } else {
  187. DrawIconEx(hdc,pDraw->rcItem.left,pDraw->rcItem.top,szMenu->hIcon,cxMiniIcon,cyMiniIcon,0,hbrBack,DI_NORMAL);
  188. }
  189. DeleteObject(hbrBack);
  190. hbrBack = CreateSolidBrush(colorFill);
  191. HFONT hOrgFont;
  192. if (pDraw->itemState & ODS_DEFAULT)
  193. {
  194. hOrgFont = (HFONT)SelectObject(hdc,m_hBoldFont);
  195. }
  196. else
  197. {
  198. hOrgFont = (HFONT)SelectObject(hdc,m_hFont);
  199. }
  200. if (m_bRTLMenu) {
  201. pDraw->rcItem.right -= (cxMiniIcon + ICON_SPACING);
  202. } else {
  203. pDraw->rcItem.left += (cxMiniIcon + ICON_SPACING);
  204. }
  205. FillRect(hdc,&pDraw->rcItem,hbrBack);
  206. DeleteObject(hbrBack);
  207. if (m_bRTLMenu) {
  208. pDraw->rcItem.right -= ICON_SPACING;
  209. } else {
  210. pDraw->rcItem.left += ICON_SPACING;
  211. }
  212. SetBkMode(hdc,TRANSPARENT);
  213. SetTextColor(hdc,colorText);
  214. // if m_bRTLMenu then draw the text right aligned and RTL reading.
  215. if (m_bRTLMenu) {
  216. DrawText(hdc, szMenu->szText, -1, &pDraw->rcItem, DT_SINGLELINE | DT_RIGHT | DT_RTLREADING);
  217. } else {
  218. DrawText(hdc, szMenu->szText, -1, &pDraw->rcItem, DT_SINGLELINE);
  219. }
  220. SelectObject(hdc,hOrgFont);
  221. }
  222. LRESULT CCustomMenu::MenuChar(TCHAR tChar, UINT fuFlag, HMENU hMenu)
  223. {
  224. //go through the menus one-by-one looking for the accel key
  225. int nReturn = 0;
  226. int nCode = MNC_IGNORE;
  227. int x = GetMenuItemCount(m_hMenu);
  228. TCHAR teststr[3];
  229. wsprintf(teststr,TEXT("&%c"),tChar);
  230. _tcsupr(teststr);
  231. for (int i = 0; i < x; i++)
  232. {
  233. MENUITEMINFO mii;
  234. ZeroMemory(&mii,sizeof(mii));
  235. mii.cbSize = sizeof(mii);
  236. mii.fMask = MIIM_DATA|MIIM_TYPE;
  237. GetMenuItemInfo(m_hMenu,i,TRUE,&mii);
  238. if ((mii.dwItemData!=0) && (mii.fType & MFT_OWNERDRAW))
  239. {
  240. OWNERMENU* szMenu = (OWNERMENU*)mii.dwItemData;
  241. TCHAR* pMenu = new TCHAR[_tcslen(szMenu->szText)+sizeof(TCHAR)];
  242. _tcscpy(pMenu,szMenu->szText);
  243. _tcsupr(pMenu);
  244. if (_tcsstr(pMenu,teststr)!=NULL)
  245. {
  246. nReturn = i;
  247. nCode = MNC_EXECUTE;
  248. if (pMenu)
  249. {
  250. delete [] pMenu;
  251. pMenu = NULL;
  252. }
  253. break;
  254. }
  255. if (pMenu)
  256. {
  257. delete [] pMenu;
  258. pMenu = NULL;
  259. }
  260. } //end if not separator
  261. }
  262. return (MAKELRESULT(nReturn, nCode));
  263. }
  264. /***************************************************************************\
  265. * ConvertHexStringToInt
  266. *
  267. * Converts a hex numeric string into an integer.
  268. *
  269. * History:
  270. * 04-Feb-1998 samera Created
  271. \***************************************************************************/
  272. BOOL ConvertHexStringToInt( CHAR *pszHexNum , int *piNum )
  273. {
  274. int n=0L;
  275. CHAR *psz=pszHexNum;
  276. for(n=0 ; ; psz=CharNextA(psz))
  277. {
  278. if( (*psz>='0') && (*psz<='9') )
  279. n = 0x10 * n + *psz - '0';
  280. else
  281. {
  282. CHAR ch = *psz;
  283. int n2;
  284. if(ch >= 'a')
  285. ch -= 'a' - 'A';
  286. n2 = ch - 'A' + 0xA;
  287. if (n2 >= 0xA && n2 <= 0xF)
  288. n = 0x10 * n + n2;
  289. else
  290. break;
  291. }
  292. }
  293. /*
  294. * Update results
  295. */
  296. *piNum = n;
  297. return (psz != pszHexNum);
  298. }
  299. /***************************************************************************\
  300. * IsBiDiLocalizedSystem
  301. *
  302. * returns TRUE if running on a lozalized BiDi (Arabic/Hebrew) NT5 or Memphis.
  303. * Should be called whenever SetProcessDefaultLayout is to be called.
  304. *
  305. * History:
  306. * 02-Feb-1998 samera Created
  307. \***************************************************************************/
  308. BOOL IsBiDiLocalizedSystem( LANGID *pLangID )
  309. {
  310. HKEY hKey;
  311. DWORD dwType;
  312. CHAR szResourceLocale[12];
  313. DWORD dwSize = sizeof(szResourceLocale)/sizeof(CHAR);
  314. int iLCID=0L;
  315. static BOOL bRet = (BOOL)(DWORD)-1;
  316. static LANGID langID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  317. if (bRet != (BOOL)(DWORD)-1)
  318. {
  319. if (bRet && pLangID)
  320. {
  321. *pLangID = langID;
  322. }
  323. return bRet;
  324. }
  325. bRet = FALSE;
  326. #ifdef UNICODE
  327. /*
  328. * Need to use NT5 detection method (Multiligual UI ID)
  329. */
  330. langID = GetUserDefaultUILanguage();
  331. if( langID )
  332. {
  333. WCHAR wchLCIDFontSignature[16];
  334. iLCID = MAKELCID( langID , SORT_DEFAULT );
  335. /*
  336. * Let's verify this is a RTL (BiDi) locale. Since reg value is a hex string,
  337. * convert to decimal value and call GetLocaleInfo afterwards.
  338. * LOCALE_FONTSIGNATURE always gives back 16 WCHARs.
  339. */
  340. if( GetLocaleInfoW( iLCID ,
  341. LOCALE_FONTSIGNATURE ,
  342. (WCHAR *) &wchLCIDFontSignature[0] ,
  343. (sizeof(wchLCIDFontSignature)/sizeof(WCHAR))) )
  344. {
  345. /* Let's verify the bits we have a BiDi UI locale */
  346. if( wchLCIDFontSignature[7] & (WCHAR)0x0800 )
  347. {
  348. bRet = TRUE;
  349. }
  350. }
  351. }
  352. #else
  353. /*
  354. * Check if BiDi-Memphis is running with Lozalized Resources (
  355. * i.e. Arabic/Hebrew systems) -It should be enabled ofcourse-.
  356. */
  357. if(GetSystemMetrics(SM_MIDEASTENABLED))
  358. {
  359. if( RegOpenKeyExA( HKEY_CURRENT_USER ,
  360. "Control Panel\\Desktop\\ResourceLocale" ,
  361. 0,
  362. KEY_READ, &hKey) == ERROR_SUCCESS)
  363. {
  364. RegQueryValueExA( hKey , "" , 0 , &dwType , (LPBYTE)szResourceLocale , &dwSize );
  365. szResourceLocale[(sizeof(szResourceLocale)/sizeof(CHAR))-1] = 0;
  366. RegCloseKey(hKey);
  367. if( ConvertHexStringToInt( szResourceLocale , &iLCID ) )
  368. {
  369. iLCID = PRIMARYLANGID(LANGIDFROMLCID(iLCID));
  370. if( (LANG_ARABIC == iLCID) || (LANG_HEBREW == iLCID) )
  371. {
  372. bRet = TRUE;
  373. langID = LANGIDFROMLCID(iLCID);
  374. }
  375. }
  376. }
  377. }
  378. #endif
  379. if (bRet && pLangID)
  380. {
  381. *pLangID = langID;
  382. }
  383. return bRet;
  384. }