ODMenu.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:26k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // ODMenu.cpp
  2. //
  3. #include "odmenu.h"
  4. using namespace std;
  5. ODMenu::ODMenu()
  6. {
  7.     m_seqNumber = 0;
  8.     //Set default colors
  9.     //Transparent color is color of "transparent" background in bitmaps
  10.     m_clrTranparent = RGB(192, 192, 192);
  11.     m_clrItemText = GetSysColor(COLOR_MENUTEXT);
  12.     m_clrItemBackground = GetSysColor(COLOR_MENU);
  13.     if(GetColorIntensity(m_clrItemBackground) < 0.82)
  14.         m_clrItemBackground = LightenColor(m_clrItemBackground, 0.27);
  15.     else
  16.         m_clrItemBackground = DarkenColor(m_clrItemBackground, 0.10);
  17.     m_clrHighlightItemText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  18.     m_clrHighlightItemBackground = GetSysColor(COLOR_HIGHLIGHT);
  19.     m_clrHighlightItemBackground = LightenColor(m_clrHighlightItemBackground, 0.5);
  20.     m_clrHighlightItemOutline = GetSysColor(COLOR_HIGHLIGHT);
  21.     m_clrSeparator = GetSysColor(COLOR_3DSHADOW);
  22.     m_clrIconBar = GetSysColor(COLOR_MENU);
  23.     m_clrIconShadow = GetSysColor(COLOR_3DSHADOW);
  24.     m_clrCheckMark = GetSysColor(COLOR_MENUTEXT);
  25.     m_clrCheckMarkBackground = AverageColor(m_clrIconBar, m_clrHighlightItemBackground, 0.8);
  26.     m_clrCheckMarkBackgroundHighlight = AverageColor(m_clrIconBar, m_clrHighlightItemBackground, 0.25);
  27.     m_clrCheckMarkBackgroundHighlight = DarkenColor(m_clrHighlightItemBackground, 0.1);
  28.     //Get the system font for menus
  29.     NONCLIENTMETRICS ncms;
  30.     ncms.cbSize = sizeof(NONCLIENTMETRICS);
  31.     if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncms, 0))
  32.         m_hFont = CreateFontIndirect(&ncms.lfMenuFont);
  33.     //Set menu metrics
  34.     m_iconBarMargin = 3;
  35.     m_textLeftMargin = 6;
  36.     m_textRightMargin = 3;
  37.     m_iconWidth = GetSystemMetrics(SM_CXSMICON);
  38.     m_iconHeight = GetSystemMetrics(SM_CYSMICON);
  39.     m_verticalSpacing = 6;
  40.     //Create GDI objects
  41.     m_hItemBackground = CreateSolidBrush(m_clrItemBackground);
  42.     m_hIconBarBrush = CreateSolidBrush(m_clrIconBar);
  43.     m_hIconShadowBrush = CreateSolidBrush(m_clrIconShadow);
  44.     m_hHighlightItemBackgroundBrush = CreateSolidBrush(m_clrHighlightItemBackground);
  45.     m_hCheckMarkBackgroundBrush = CreateSolidBrush(m_clrCheckMarkBackground);
  46.     m_hCheckMarkBackgroundHighlightBrush = CreateSolidBrush(m_clrCheckMarkBackgroundHighlight);
  47.     m_hSelectionOutlinePen = CreatePen(PS_SOLID, 1, m_clrHighlightItemOutline);
  48.     m_hSeparatorPen = CreatePen(PS_SOLID, 1, m_clrSeparator);
  49.     m_hCheckMarkPen = CreatePen(PS_SOLID, 1, m_clrCheckMark);
  50. }
  51. ODMenu::~ODMenu()
  52. {
  53.     if(m_hFont)
  54.         DeleteObject(m_hFont);
  55.     if(m_hIconBarBrush)
  56.         DeleteObject(m_hIconBarBrush);
  57.     if(m_hIconShadowBrush)
  58.         DeleteObject(m_hIconShadowBrush);
  59.     if(m_hCheckMarkBackgroundBrush)
  60.         DeleteObject(m_hCheckMarkBackgroundBrush);
  61.     if(m_hCheckMarkBackgroundHighlightBrush)
  62.         DeleteObject(m_hCheckMarkBackgroundHighlightBrush);
  63.     if(m_hSelectionOutlinePen)
  64.         DeleteObject(m_hSelectionOutlinePen);
  65.     if(m_hSeparatorPen)
  66.         DeleteObject(m_hSeparatorPen);
  67.     if(m_hCheckMarkPen)
  68.         DeleteObject(m_hCheckMarkPen);
  69.     if(m_hItemBackground)
  70.         DeleteObject(m_hItemBackground);
  71.     if(m_hHighlightItemBackgroundBrush)
  72.         DeleteObject(m_hHighlightItemBackgroundBrush);
  73. }
  74. bool ODMenu::Init(HWND hOwnerWnd, HMENU hMenu)
  75. {
  76.     m_hRootMenu = hMenu;
  77.     //Traverse through all menu items to allocate a map of ODMENUITEM which
  78.     //will be subsequently used to measure and draw menu items.
  79.     if(m_seqNumber == 0)
  80.         EnumMenuItems(hMenu);
  81.     return true;
  82. }
  83. void ODMenu::EnumMenuItems(HMENU hMenu)
  84. {
  85.     int i, numItems;
  86.     MENUITEMINFO miInfo;
  87.     numItems = GetMenuItemCount(hMenu);
  88.     if(numItems > 0)
  89.     {
  90.         miInfo.cbSize = sizeof(MENUITEMINFO);
  91.         miInfo.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;
  92.         miInfo.dwTypeData = m_szItemText;
  93.         miInfo.cch = sizeof(m_szItemText);
  94.         for(i=0; i<numItems; i++)
  95.         {
  96.             if(GetMenuItemInfo(hMenu, i, TRUE, &miInfo))
  97.                 AddItem(hMenu, i, &miInfo);
  98.             if(miInfo.hSubMenu)
  99.             {
  100.                 //Resursive call
  101.                 EnumMenuItems(miInfo.hSubMenu);
  102.             }
  103.             miInfo.cch = sizeof(m_szItemText);
  104.             miInfo.dwTypeData = m_szItemText;
  105.         }
  106.     }
  107. }
  108. void ODMenu::DeleteSubMenu(HMENU hMenu)
  109. {
  110.     //Recursively remove map items according to menu structure
  111.     int i;
  112.     MENUITEMINFO miInfo;
  113.     i = 0;
  114.     miInfo.cbSize = sizeof(MENUITEMINFO);
  115.     miInfo.fMask = MIIM_SUBMENU | MIIM_DATA;
  116.     while(GetMenuItemInfo(hMenu, i, TRUE, &miInfo))
  117.     {
  118.         //Make recursive call
  119.         if(miInfo.hSubMenu)
  120.             DeleteSubMenu(miInfo.hSubMenu);
  121.         //Remove this item from map
  122.         m_menuItems.erase(miInfo.dwItemData);
  123.         i++;
  124.     }
  125. }
  126. void ODMenu::SetMenuItemOwnerDrawn(HMENU hMenu, UINT item, UINT type)
  127. {
  128.     //Set menu item type to owner-drawn and set itemdata to sequence number.
  129.     MENUITEMINFO miInfo;
  130.   
  131.     miInfo.cbSize = sizeof(MENUITEMINFO);
  132.     miInfo.fMask = MIIM_TYPE | MIIM_DATA;
  133.     miInfo.fType = type | MFT_OWNERDRAW;
  134.     miInfo.dwItemData = m_seqNumber++;
  135.     
  136.     SetMenuItemInfo(hMenu, item, TRUE, &miInfo);
  137. }
  138. void ODMenu::GenerateDisplayText(ODMENUITEM& item)
  139. {
  140.     TCHAR* pChr;
  141.     int i;
  142.     item.displayText = "";
  143.     item.rawDisplayText = "";
  144.     item.shortcutText = "";
  145.     //Does shortcut text exist?
  146.     if(pChr = strchr((LPTSTR)item.rawText.c_str(), 't'))
  147.         item.shortcutText = pChr + 1;
  148.     i = 0;
  149.     pChr = (LPTSTR)item.rawText.c_str();
  150.     while(*(pChr + i) != 't' && *(pChr + i) != '')
  151.     {
  152.         if(*(pChr + i) == '&')
  153.         {
  154.             item.rawDisplayText.append(pChr + i, 1);
  155.             i++;
  156.             continue;
  157.         }
  158.         item.rawDisplayText.append(pChr + i, 1);
  159.         item.displayText.append(pChr + i, 1);
  160.         i++;
  161.     }
  162. }
  163. void ODMenu::DrawItemText(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
  164. {
  165.     int x, y;
  166.     SIZE size;
  167.     RECT rectText;
  168.     RECT rectItem;
  169.     memcpy(&rectItem, &lpdis->rcItem, sizeof(RECT));
  170.     //Get size of text to draw
  171.     GetTextExtentPoint32(lpdis->hDC, item.displayText.c_str(), item.displayText.length(), &size);
  172.     // Determine where to draw.
  173.     ComputeMenuTextPos(lpdis, item, x, y, size);
  174.     rectText.left = x;
  175.     rectText.right = lpdis->rcItem.right - m_textRightMargin;
  176.     rectText.top = y;
  177.     rectText.bottom = lpdis->rcItem.bottom;
  178.     //Adjust rectangle that will contain the menu item
  179.     if(!item.topMost)
  180.     {
  181.         rectItem.left += (m_iconWidth + 2*m_iconBarMargin);
  182.     }
  183.     //Draw the item rectangle with appropriate background color
  184.     ExtTextOut(lpdis->hDC, x, y, ETO_OPAQUE, &rectItem, "", 0, NULL);
  185.     //Draw the text
  186.     DrawText(lpdis->hDC, item.rawDisplayText.c_str(), item.rawDisplayText.length(),
  187.         &rectText, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
  188.     DrawText(lpdis->hDC, item.shortcutText.c_str(), item.shortcutText.length(),
  189.         &rectText, DT_RIGHT | DT_SINGLELINE | DT_VCENTER);
  190. }
  191. void ODMenu::DrawIconBar(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
  192. {
  193.     RECT rectBar;
  194.     memcpy(&rectBar, &lpdis->rcItem, sizeof(RECT));
  195.     //Draw icon bar if not top level
  196.     if(!item.topMost)
  197.     {
  198.         rectBar.right = rectBar.left + m_iconWidth + 2*m_iconBarMargin + 1;
  199.         if(lpdis->itemState & ODS_SELECTED &&
  200.                 !(lpdis->itemState & ODS_DISABLED || lpdis->itemState & ODS_GRAYED))
  201.         {
  202.             FillRect(lpdis->hDC, &rectBar, m_hHighlightItemBackgroundBrush);
  203.         }
  204.         else
  205.         {
  206.             FillRect(lpdis->hDC, &rectBar, m_hIconBarBrush);
  207.         }
  208.     }
  209.     int x, y;
  210.     //Draw icon for menu item if handle is valid
  211.     if(item.hBitmap)
  212.     {
  213.         x = m_iconBarMargin;
  214.         y = rectBar.top + ((rectBar.bottom - rectBar.top - 16) / 2);
  215.         if(lpdis->itemState & ODS_DISABLED || lpdis->itemState & ODS_GRAYED)
  216.         {
  217.             //Draw disabled icon in normal position
  218.             DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eDisabled);
  219.         }
  220.         else if(lpdis->itemState & ODS_SELECTED)
  221.         {
  222.             //Draw icon "raised"
  223.             //Draw shadow right one pixel and down one pixel from normal position
  224.             DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x+1, y+1, m_clrTranparent, eShadow);
  225.             //Draw normal left one pixel and up one pixel from normal position
  226.             DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x-1, y-1, m_clrTranparent);
  227.         }
  228.         else
  229.         {
  230.             //Draw faded icon in normal position
  231.             DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eFaded);
  232.         }
  233.     }
  234.     else if(lpdis->itemState & ODS_CHECKED)
  235.     {
  236.         HBRUSH hPrevBrush;
  237.         HPEN hPrevPen;
  238.         RECT rect;
  239.         //Draw filled, outlined rectangle around checkmark first
  240.         if(lpdis->itemState & ODS_SELECTED)
  241.             hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, m_hCheckMarkBackgroundHighlightBrush);
  242.         else
  243.             hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, m_hCheckMarkBackgroundBrush);
  244.         hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSelectionOutlinePen);
  245.         rect.left = m_iconBarMargin;
  246.         rect.right = m_iconBarMargin + m_iconWidth;
  247.         rect.top = rectBar.top + (rectBar.bottom - rectBar.top - m_iconHeight) / 2;
  248.         rect.bottom = rect.top + m_iconHeight;
  249.         Rectangle(lpdis->hDC, rect.left, rect.top, rect.right, rect.bottom);
  250.         SelectObject(lpdis->hDC, hPrevBrush);
  251.         SelectObject(lpdis->hDC, hPrevPen);
  252.         //Draw check mark
  253.         x = (m_iconWidth + 2*m_iconBarMargin - 6) / 2;
  254.         y = rectBar.top + ((rectBar.bottom - rectBar.top - 7) / 2) + 1;
  255.         DrawCheckMark(lpdis->hDC, x, y, true);
  256.     }
  257. }
  258. void ODMenu::ComputeMenuTextPos(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item, int& x, int& y, SIZE& size)
  259. {
  260.     x = lpdis->rcItem.left;
  261.     y = lpdis->rcItem.top;
  262. //    y += ((lpdis->rcItem.bottom - lpdis->rcItem.top - size.cy) / 2);
  263.     if(!item.topMost)
  264.     {
  265.         //Correct position for drop down menus. Leave space for a bitmap
  266.         x += (m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin);
  267.     }
  268.     else
  269.     {
  270.         //Center horizontally for top level menu items
  271.         x += ((lpdis->rcItem.right - lpdis->rcItem.left - size.cx) / 2);
  272.     }
  273. }
  274. void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
  275.                                    short yStart, COLORREF cTransparentColor,
  276.                                    bitmapType eType)
  277. {
  278.     BITMAP     bm;
  279.     COLORREF   cColor;
  280.     HBITMAP    bmAndBack, bmAndObject, bmAndMem, bmSave;
  281.     HBITMAP    bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
  282.     HDC        hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
  283.     POINT      ptSize;
  284.     HBRUSH     hOldBrush;
  285.     BOOL bRC;
  286.     hdcTemp = CreateCompatibleDC(hDC);
  287.     SelectObject(hdcTemp, hBitmap);   // Select the bitmap
  288.     GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
  289.     ptSize.x = bm.bmWidth;            // Get width of bitmap
  290.     ptSize.y = bm.bmHeight;           // Get height of bitmap
  291.     DPtoLP(hdcTemp, &ptSize, 1);      // Convert from device
  292.                                       // to logical points
  293.     // Create some DCs to hold temporary data.
  294.     hdcBack   = CreateCompatibleDC(hDC);
  295.     hdcObject = CreateCompatibleDC(hDC);
  296.     hdcMem    = CreateCompatibleDC(hDC);
  297.     hdcSave   = CreateCompatibleDC(hDC);
  298.     // Create a bitmap for each DC. DCs are required for a number of
  299.     // GDI functions.
  300.     // Monochrome DC
  301.     bmAndBack   = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
  302.     // Monochrome DC
  303.     bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
  304.     bmAndMem    = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y);
  305.     bmSave      = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y);
  306.     // Each DC must select a bitmap object to store pixel data.
  307.     bmBackOld   = (HBITMAP)SelectObject(hdcBack, bmAndBack);
  308.     bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject);
  309.     bmMemOld    = (HBITMAP)SelectObject(hdcMem, bmAndMem);
  310.     bmSaveOld   = (HBITMAP)SelectObject(hdcSave, bmSave);
  311.     // Set proper mapping mode.
  312.     SetMapMode(hdcTemp, GetMapMode(hDC));
  313.     // Save the bitmap sent here, because it will be overwritten.
  314.     bRC = BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
  315.     // Create an "AND mask" that contains the mask of the colors to draw
  316.     // (the nontransparent portions of the image).
  317.     // Set the background color of the source DC to the color.
  318.     // contained in the parts of the bitmap that should be transparent
  319.     cColor = SetBkColor(hdcTemp, cTransparentColor);
  320.     // Create the object mask for the bitmap by performing a BitBlt
  321.     // from the source bitmap to a monochrome bitmap.
  322.     bRC = BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
  323.     // Set the background color of the source DC back to the original color.
  324.     SetBkColor(hdcTemp, cColor);
  325.     // Create the inverse of the object mask.
  326.     bRC = BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
  327.     // Copy the background of the main DC to the destination.
  328.     bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hDC, xStart, yStart, SRCCOPY);
  329.     // Mask out the places where the bitmap will be placed.
  330.     // hdcMem then contains the background color of hDC only in the places
  331.     // where the transparent pixels reside.
  332.     bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
  333.     if(eType == eNormal)
  334.     {
  335.         // Mask out the transparent colored pixels on the bitmap.
  336.         // hdcTemp then contains only the non-transparent pixels.
  337.         BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
  338.         // XOR the bitmap with the background on the destination DC.
  339.         // hdcMem then contains the required result.
  340.         BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
  341.     }
  342.     else if(eType == eShadow)
  343.     {
  344.         //Select shadow brush into hdcTemp
  345.         hOldBrush = (HBRUSH)SelectObject(hdcTemp, m_hIconShadowBrush);
  346.         //Copy shadow brush pixels for all non-transparent pixels to hdcTemp
  347.         bRC = BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, MERGECOPY);
  348.         // XOR the bitmap with the background on the destination DC.
  349.         // hdcMem then contains the required result.
  350.         bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
  351.         //Restore the brush in hdcTemp
  352.         SelectObject(hdcTemp, hOldBrush);
  353.     }
  354.     else if(eType == eFaded)
  355.     {
  356.         COLORREF col;
  357.         int x, y;
  358.         //Lighten the color of each pixel in hdcTemp
  359.         for(x=0; x<ptSize.x; x++)
  360.         {
  361.             for(y=0; y<ptSize.y; y++)
  362.             {
  363.                 col = GetPixel(hdcTemp, x, y);
  364.                 col = LightenColor(col, 0.3);
  365.                 SetPixel(hdcTemp, x, y, col);
  366.             }
  367.         }
  368.         // Mask out the transparent colored pixels on the bitmap.
  369.         // hdcTemp then contains only the non-transparent pixels.
  370.         BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
  371.         // XOR the bitmap with the background on the destination DC.
  372.         // hdcMem then contains the required result.
  373.         BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
  374.     }
  375.     else if(eType == eDisabled)
  376.     {
  377.         COLORREF discol, col;
  378.         BYTE r, g, b;
  379.         int x, y;
  380.         int avgcol;
  381.         double factor;
  382.         //Lighten the color of COLOR_BTNSHADOW by a weighted average of the color at each pixel in hdcTemp.
  383.         //Set the pixel to the lightened color.
  384.         discol = GetSysColor(COLOR_BTNSHADOW);
  385.         for(x=0; x<ptSize.x; x++)
  386.         {
  387.             for(y=0; y<ptSize.y; y++)
  388.             {
  389.                 col = GetPixel(hdcTemp, x, y);
  390.                 r = GetRValue(col);
  391. g = GetGValue(col);
  392. b = GetBValue(col);
  393.                 avgcol = (r + g + b) / 3;
  394. factor = avgcol / 255.0;
  395.                 SetPixel(hdcTemp, x, y, LightenColor(discol, factor));
  396.             }
  397.         }
  398.         // Mask out the transparent colored pixels on the bitmap.
  399.         // hdcTemp then contains only the non-transparent pixels.
  400.         BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
  401.         // XOR the bitmap with the background on the destination DC.
  402.         // hdcMem then contains the required result.
  403.         BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
  404.     }
  405.     // Copy the destination to the screen.
  406.     bRC = BitBlt(hDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
  407.     // Place the original bitmap back into the bitmap sent here.
  408.     bRC = BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
  409.     // Delete the memory bitmaps.
  410.     DeleteObject(SelectObject(hdcBack, bmBackOld));
  411.     DeleteObject(SelectObject(hdcObject, bmObjectOld));
  412.     DeleteObject(SelectObject(hdcMem, bmMemOld));
  413.     DeleteObject(SelectObject(hdcSave, bmSaveOld));
  414.     // Delete the memory DCs.
  415.     DeleteDC(hdcMem);
  416.     DeleteDC(hdcBack);
  417.     DeleteDC(hdcObject);
  418.     DeleteDC(hdcSave);
  419.     DeleteDC(hdcTemp);
  420. }
  421. void ODMenu::DrawCheckMark(HDC hDC, short x, short y, bool bNarrow)
  422. {
  423.     HPEN hOldPen;
  424.     int dp = 0;
  425.     if(bNarrow)
  426.         dp = 1;
  427.     //Select check mark pen
  428.     hOldPen = (HPEN)SelectObject(hDC, m_hCheckMarkPen);
  429.     //Draw the check mark
  430.     MoveToEx(hDC, x, y + 2, NULL);
  431. LineTo(hDC, x, y + 5 - dp);
  432. MoveToEx(hDC, x + 1, y + 3, NULL);
  433. LineTo(hDC, x + 1, y + 6 - dp);
  434. MoveToEx(hDC, x + 2, y + 4, NULL);
  435. LineTo(hDC, x + 2, y + 7 - dp);
  436. MoveToEx(hDC, x + 3, y + 3, NULL);
  437. LineTo(hDC, x + 3, y + 6 - dp);
  438. MoveToEx(hDC, x + 4, y + 2, NULL);
  439. LineTo(hDC, x + 4, y + 5 - dp);
  440. MoveToEx(hDC, x + 5, y + 1, NULL);
  441. LineTo(hDC, x + 5, y + 4 - dp);
  442. MoveToEx(hDC, x + 6, y, NULL);
  443. LineTo(hDC, x + 6, y + 3 - dp);
  444.     //Restore original DC pen
  445.     SelectObject(hDC, hOldPen);
  446. }
  447. COLORREF ODMenu::LightenColor(COLORREF col, double factor)
  448. {
  449. if(factor > 0.0 && factor <= 1.0)
  450.     {
  451. BYTE red, green, blue, lightred, lightgreen, lightblue;
  452. red = GetRValue(col);
  453. green = GetGValue(col);
  454. blue = GetBValue(col);
  455. lightred = (BYTE)((factor*(255 - red)) + red);
  456. lightgreen = (BYTE)((factor*(255 - green)) + green);
  457. lightblue = (BYTE)((factor*(255 - blue)) + blue);
  458. col = RGB(lightred, lightgreen, lightblue);
  459. }
  460. return col;
  461. }
  462. COLORREF ODMenu::DarkenColor(COLORREF col, double factor)
  463. {
  464. if(factor > 0.0 && factor <= 1.0)
  465.     {
  466. BYTE red, green, blue, lightred, lightgreen, lightblue;
  467. red = GetRValue(col);
  468. green = GetGValue(col);
  469. blue = GetBValue(col);
  470. lightred = (BYTE)(red - (factor*red));
  471. lightgreen = (BYTE)(green - (factor*green));
  472. lightblue = (BYTE)(blue - (factor*blue));
  473. col = RGB(lightred, lightgreen, lightblue);
  474. }
  475. return col;
  476. }
  477. COLORREF ODMenu::AverageColor(COLORREF col1, COLORREF col2, double weight)
  478. {
  479.     BYTE avgRed, avgGreen, avgBlue;
  480.     if (weight <= 0.0)
  481.         return col1;
  482. else if (weight > 1.0)
  483. return col2;
  484.     avgRed   = (BYTE) (GetRValue(col1) * weight + GetRValue(col2) * (1.0 - weight));
  485.     avgGreen = (BYTE) (GetGValue(col1) * weight + GetGValue(col2) * (1.0 - weight));
  486.     avgBlue  = (BYTE) (GetBValue(col1) * weight + GetBValue(col2) * (1.0 - weight));
  487.     return RGB(avgRed, avgGreen, avgBlue);
  488. }
  489. double ODMenu::GetColorIntensity(COLORREF col)
  490. {
  491.     BYTE red, green, blue;
  492.     red = GetRValue(col);
  493.     green = GetGValue(col);
  494. blue = GetBValue(col);
  495.     //denominator of 765 is (255*3)
  496.     return (double)red/765.0 + (double)green/765.0 + (double)blue/765.0;
  497. }
  498. void ODMenu::MeasureItem(HWND hWnd, LPARAM lParam)
  499. {
  500.     MEASUREITEMSTRUCT* lpmis = (MEASUREITEMSTRUCT*)lParam;
  501.     ODMENUITEMS::iterator it;
  502.     ODMENUITEM item;
  503.     HDC hDC;
  504.     HFONT hfntOld;
  505.     RECT rect;
  506.     it = m_menuItems.find(lpmis->itemData);
  507.     if(it == m_menuItems.end())
  508.         return;
  509.     hDC = GetDC(hWnd);
  510.     hfntOld = (HFONT)SelectObject(hDC, m_hFont);
  511.     item = it->second;
  512.     if(item.displayText.length() > 0)
  513.     {
  514.         DrawText(hDC, item.rawText.c_str(), item.rawText.length(), &rect,
  515.             DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
  516.         lpmis->itemWidth = rect.right - rect.left;
  517.         if(!item.topMost)
  518.         {
  519.             //Correct size for drop down menus
  520.             lpmis->itemWidth += (m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin + m_textRightMargin);
  521.             lpmis->itemHeight += m_verticalSpacing;
  522.         }
  523.      }
  524.     else if(item.dwType & MFT_SEPARATOR)
  525.     {
  526.         //Correct size for drop down menus
  527.         if(!item.topMost)
  528.         {
  529.             lpmis->itemWidth += (m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin + m_textRightMargin);
  530.             lpmis->itemHeight = 3;
  531.         }
  532.     }
  533.     SelectObject(hDC, hfntOld);
  534.     ReleaseDC(hWnd, hDC);
  535. }
  536. void ODMenu::DrawItem(HWND hWnd, LPARAM lParam)
  537. {
  538.     DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
  539.     ODMENUITEMS::iterator it;
  540.     ODMENUITEM item;
  541.     COLORREF clrPrevText, clrPrevBkgnd;
  542.     HFONT hPrevFnt;
  543.     HPEN hPrevPen;
  544.     HBRUSH hPrevBrush;
  545.     it = m_menuItems.find(lpdis->itemData);
  546.     if(it == m_menuItems.end())
  547.         return;
  548.     item = it->second;
  549.     //Draw based on type of item
  550.     if(item.displayText.length() > 0)
  551.     {
  552.         // Set the appropriate foreground and background colors. 
  553.         if(item.topMost)
  554.         {
  555.             if(lpdis->itemState & ODS_SELECTED)
  556.             { 
  557.                 clrPrevText = SetTextColor(lpdis->hDC, m_clrHighlightItemText);
  558.                 clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrHighlightItemBackground);
  559.             }
  560.             else
  561.             { 
  562.                 clrPrevText = SetTextColor(lpdis->hDC, m_clrItemText);
  563.                 clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor(COLOR_MENU));
  564.             }
  565.         }
  566.         else
  567.         {
  568.             if(lpdis->itemState & ODS_GRAYED || lpdis->itemState & ODS_DISABLED)
  569.             {
  570.                 clrPrevText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_3DSHADOW));
  571.                 clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrItemBackground);
  572.             }
  573.             else if(lpdis->itemState & ODS_SELECTED)
  574.             {
  575.                 clrPrevText = SetTextColor(lpdis->hDC, m_clrHighlightItemText);
  576.                 clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrHighlightItemBackground);
  577.             }
  578.             else
  579.             { 
  580.                 clrPrevText = SetTextColor(lpdis->hDC, m_clrItemText);
  581.                 clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrItemBackground);
  582.             }
  583.         }
  584.         // Select the font.
  585.         hPrevFnt = (HFONT)SelectObject(lpdis->hDC, m_hFont);
  586.         //Draw the text
  587.         DrawItemText(lpdis, item);
  588.         //Restore original font
  589.         SelectObject(lpdis->hDC, hPrevFnt);
  590.         SetTextColor(lpdis->hDC, clrPrevText);
  591.         SetBkColor(lpdis->hDC, clrPrevBkgnd);
  592.     }
  593.     else if(item.dwType & MFT_SEPARATOR)
  594.     {
  595. //Fill menu space with menu background, first.
  596.         RECT rect;
  597.         memcpy(&rect, &lpdis->rcItem, sizeof(RECT));
  598.         rect.left += (m_iconWidth + 2*m_iconBarMargin);
  599.         FillRect(lpdis->hDC, &rect, m_hItemBackground);
  600.         //Draw the separator line
  601.         hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSeparatorPen);
  602.         MoveToEx(lpdis->hDC, lpdis->rcItem.left + m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin,
  603.             lpdis->rcItem.top+1, NULL);
  604.         LineTo(lpdis->hDC, lpdis->rcItem.right, lpdis->rcItem.top+1);
  605.         //Restore GDI objects in DC
  606.         SelectObject(lpdis->hDC, hPrevPen);
  607.     }
  608.     //Draw the left icon bar
  609.     DrawIconBar(lpdis, item);
  610.     //Draw selection outline if drawing a selected item
  611.     if(lpdis->itemState & ODS_SELECTED && !(lpdis->itemState & ODS_GRAYED || lpdis->itemState & ODS_DISABLED))
  612.     {
  613.         hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, (HBRUSH)GetStockObject(NULL_BRUSH));
  614.         hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSelectionOutlinePen);
  615.         Rectangle(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
  616.             lpdis->rcItem.right, lpdis->rcItem.bottom);
  617.         //Restore GDI objects in DC
  618.         SelectObject(lpdis->hDC, hPrevBrush);
  619.         SelectObject(lpdis->hDC, hPrevPen);
  620.     }
  621. }
  622. void ODMenu::OnDestroy()
  623. {
  624. }
  625. bool ODMenu::GetItem(UINT id, ODMENUITEM** ppItem)
  626. {
  627.     bool bRC = true;
  628.     if(!ppItem)
  629.         return false;
  630.     ODMENUITEMS::iterator it = m_menuItems.find(id);
  631.     if(it != m_menuItems.end())
  632.         *ppItem = &it->second;
  633.     return bRC;
  634. }
  635. void ODMenu::SetItemImage(HINSTANCE hInst, UINT wID, UINT idBitmap)
  636. {
  637.     // Get iterator to ODMENUITEM
  638.     ODMENUITEMS::iterator it;
  639.     HBITMAP hBitmap;
  640.     // Load the bitmap resource
  641.     hBitmap = (HBITMAP) LoadImage(hInst,
  642.                                   MAKEINTRESOURCE(idBitmap),
  643.                                   IMAGE_BITMAP, 0, 0, LR_SHARED);
  644.     if (hBitmap)
  645.     {
  646.         // Find menu item having specified wID.
  647.         it = m_menuItems.begin();
  648.         while(it != m_menuItems.end())
  649.         {
  650.             if(it->second.wID == wID)
  651.             {
  652.                 it->second.hBitmap = hBitmap;
  653.                 break;
  654.             }
  655.             it++;
  656.         }
  657.     }
  658.     else
  659.     {
  660.         DWORD dwErr = GetLastError();
  661.         dwErr = 0;
  662.     }
  663. }
  664. void ODMenu::AddItem(HMENU hMenu, int index, MENUITEMINFO* pItemInfo)
  665. {
  666.     MENUITEMINFO miInfo;
  667.     ODMENUITEM odInfo;
  668.     //Obtain menu item info if not supplied
  669.     if(!pItemInfo)
  670.     {
  671.         miInfo.cbSize = sizeof(MENUITEMINFO);
  672.         miInfo.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;
  673.         miInfo.dwTypeData = m_szItemText;
  674.         miInfo.cch = sizeof(m_szItemText);
  675.         if(GetMenuItemInfo(hMenu, index, TRUE, &miInfo))
  676.             pItemInfo = &miInfo;
  677.     }
  678.     //Add menu info to map of menu items
  679.     if(pItemInfo)
  680.     {
  681.         if(pItemInfo->hSubMenu != NULL && hMenu == m_hRootMenu)
  682.             odInfo.topMost = true;
  683.         else
  684.             odInfo.topMost = false;
  685.         if(pItemInfo->fType == MFT_STRING)
  686.         {
  687.             odInfo.rawText = pItemInfo->dwTypeData;
  688.             GenerateDisplayText(odInfo);
  689.         }
  690.         else
  691.         {
  692.             odInfo.rawText = "";
  693.             odInfo.displayText = "";
  694.         }
  695.         odInfo.dwType = pItemInfo->fType;
  696.         odInfo.wID = pItemInfo->wID;
  697.         odInfo.hBitmap = NULL;
  698.         m_menuItems[m_seqNumber] = odInfo;
  699.         SetMenuItemOwnerDrawn(hMenu, index, pItemInfo->fType);
  700.     }
  701. }
  702. void ODMenu::DeleteItem(HMENU hMenu, int index)
  703. {
  704.     //Item data for item is map index
  705.     MENUITEMINFO miInfo;
  706.     miInfo.cbSize = sizeof(MENUITEMINFO);
  707.     miInfo.fMask = MIIM_SUBMENU | MIIM_DATA;
  708.     if(GetMenuItemInfo(hMenu, index, TRUE, &miInfo))
  709.     {
  710.         if(miInfo.hSubMenu)
  711.             DeleteSubMenu(miInfo.hSubMenu);
  712.         //Remove this item from map
  713.         m_menuItems.erase(miInfo.dwItemData);
  714.     }
  715. }