Initial stab at owner-draw menu class.
parent
add3d7e665
commit
1ee36bbe5b
|
@ -0,0 +1,862 @@
|
|||
// ODMenu.cpp
|
||||
//
|
||||
|
||||
#include "ODMenu.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
ODMenu::ODMenu()
|
||||
{
|
||||
m_seqNumber = 0;
|
||||
|
||||
//Set default colors
|
||||
|
||||
//Transparent color is color of "transparent" background in bitmaps
|
||||
m_clrTranparent = RGB(192, 192, 192);
|
||||
|
||||
m_clrItemText = GetSysColor(COLOR_MENUTEXT);
|
||||
m_clrItemBackground = GetSysColor(COLOR_MENU);
|
||||
if(GetColorIntensity(m_clrItemBackground) < 0.82)
|
||||
m_clrItemBackground = LightenColor(m_clrItemBackground, 0.27);
|
||||
else
|
||||
m_clrItemBackground = DarkenColor(m_clrItemBackground, 0.10);
|
||||
m_clrHighlightItemText = GetSysColor(COLOR_HIGHLIGHTTEXT);
|
||||
m_clrHighlightItemBackground = GetSysColor(COLOR_HIGHLIGHT);
|
||||
m_clrHighlightItemBackground = LightenColor(m_clrHighlightItemBackground, 0.5);
|
||||
m_clrHighlightItemOutline = GetSysColor(COLOR_HIGHLIGHT);
|
||||
m_clrSeparator = GetSysColor(COLOR_3DSHADOW);
|
||||
m_clrIconBar = GetSysColor(COLOR_MENU);
|
||||
m_clrIconShadow = GetSysColor(COLOR_3DSHADOW);
|
||||
m_clrCheckMark = GetSysColor(COLOR_MENUTEXT);
|
||||
m_clrCheckMarkBackground = AverageColor(m_clrIconBar, m_clrHighlightItemBackground, 0.8);
|
||||
m_clrCheckMarkBackgroundHighlight = AverageColor(m_clrIconBar, m_clrHighlightItemBackground, 0.25);
|
||||
m_clrCheckMarkBackgroundHighlight = DarkenColor(m_clrHighlightItemBackground, 0.1);
|
||||
|
||||
//Get the system font for menus
|
||||
NONCLIENTMETRICS ncms;
|
||||
ncms.cbSize = sizeof(NONCLIENTMETRICS);
|
||||
if(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncms, 0))
|
||||
m_hFont = CreateFontIndirect(&ncms.lfMenuFont);
|
||||
|
||||
//Set menu metrics
|
||||
m_iconBarMargin = 3;
|
||||
m_textLeftMargin = 6;
|
||||
m_textRightMargin = 3;
|
||||
m_iconWidth = GetSystemMetrics(SM_CXSMICON);
|
||||
m_iconHeight = GetSystemMetrics(SM_CYSMICON);
|
||||
m_verticalSpacing = 6;
|
||||
|
||||
//Create GDI objects
|
||||
m_hItemBackground = CreateSolidBrush(m_clrItemBackground);
|
||||
m_hIconBarBrush = CreateSolidBrush(m_clrIconBar);
|
||||
m_hIconShadowBrush = CreateSolidBrush(m_clrIconShadow);
|
||||
m_hHighlightItemBackgroundBrush = CreateSolidBrush(m_clrHighlightItemBackground);
|
||||
m_hCheckMarkBackgroundBrush = CreateSolidBrush(m_clrCheckMarkBackground);
|
||||
m_hCheckMarkBackgroundHighlightBrush = CreateSolidBrush(m_clrCheckMarkBackgroundHighlight);
|
||||
m_hSelectionOutlinePen = CreatePen(PS_SOLID, 1, m_clrHighlightItemOutline);
|
||||
m_hSeparatorPen = CreatePen(PS_SOLID, 1, m_clrSeparator);
|
||||
m_hCheckMarkPen = CreatePen(PS_SOLID, 1, m_clrCheckMark);
|
||||
}
|
||||
|
||||
ODMenu::~ODMenu()
|
||||
{
|
||||
if(m_hFont)
|
||||
DeleteObject(m_hFont);
|
||||
if(m_hIconBarBrush)
|
||||
DeleteObject(m_hIconBarBrush);
|
||||
if(m_hIconShadowBrush)
|
||||
DeleteObject(m_hIconShadowBrush);
|
||||
if(m_hCheckMarkBackgroundBrush)
|
||||
DeleteObject(m_hCheckMarkBackgroundBrush);
|
||||
if(m_hCheckMarkBackgroundHighlightBrush)
|
||||
DeleteObject(m_hCheckMarkBackgroundHighlightBrush);
|
||||
if(m_hSelectionOutlinePen)
|
||||
DeleteObject(m_hSelectionOutlinePen);
|
||||
if(m_hSeparatorPen)
|
||||
DeleteObject(m_hSeparatorPen);
|
||||
if(m_hCheckMarkPen)
|
||||
DeleteObject(m_hCheckMarkPen);
|
||||
if(m_hItemBackground)
|
||||
DeleteObject(m_hItemBackground);
|
||||
if(m_hHighlightItemBackgroundBrush)
|
||||
DeleteObject(m_hHighlightItemBackgroundBrush);
|
||||
}
|
||||
|
||||
bool ODMenu::Init(HWND hOwnerWnd, HMENU hMenu)
|
||||
{
|
||||
m_hRootMenu = hMenu;
|
||||
|
||||
//Traverse through all menu items to allocate a map of ODMENUITEM which
|
||||
//will be subsequently used to measure and draw menu items.
|
||||
|
||||
EnumMenuItems(hMenu);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ODMenu::EnumMenuItems(HMENU hMenu)
|
||||
{
|
||||
int i, numItems;
|
||||
MENUITEMINFO miInfo;
|
||||
|
||||
numItems = GetMenuItemCount(hMenu);
|
||||
if(numItems > 0)
|
||||
{
|
||||
miInfo.cbSize = sizeof(MENUITEMINFO);
|
||||
miInfo.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;
|
||||
miInfo.dwTypeData = m_szItemText;
|
||||
miInfo.cch = sizeof(m_szItemText);
|
||||
|
||||
for(i=0; i<numItems; i++)
|
||||
{
|
||||
if(GetMenuItemInfo(hMenu, i, TRUE, &miInfo))
|
||||
AddItem(hMenu, i, &miInfo);
|
||||
|
||||
if(miInfo.hSubMenu)
|
||||
{
|
||||
//Resursive call
|
||||
EnumMenuItems(miInfo.hSubMenu);
|
||||
}
|
||||
|
||||
miInfo.cch = sizeof(m_szItemText);
|
||||
miInfo.dwTypeData = m_szItemText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::DeleteSubMenu(HMENU hMenu)
|
||||
{
|
||||
//Recursively remove map items according to menu structure
|
||||
int i;
|
||||
MENUITEMINFO miInfo;
|
||||
|
||||
i = 0;
|
||||
miInfo.cbSize = sizeof(MENUITEMINFO);
|
||||
miInfo.fMask = MIIM_SUBMENU | MIIM_DATA;
|
||||
while(GetMenuItemInfo(hMenu, i, TRUE, &miInfo))
|
||||
{
|
||||
//Make recursive call
|
||||
if(miInfo.hSubMenu)
|
||||
DeleteSubMenu(miInfo.hSubMenu);
|
||||
|
||||
//Remove this item from map
|
||||
m_menuItems.erase(miInfo.dwItemData);
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::SetMenuItemOwnerDrawn(HMENU hMenu, UINT item, UINT type)
|
||||
{
|
||||
//Set menu item type to owner-drawn and set itemdata to sequence number.
|
||||
MENUITEMINFO miInfo;
|
||||
|
||||
miInfo.cbSize = sizeof(MENUITEMINFO);
|
||||
miInfo.fMask = MIIM_TYPE | MIIM_DATA;
|
||||
miInfo.fType = type | MFT_OWNERDRAW;
|
||||
miInfo.dwItemData = m_seqNumber++;
|
||||
|
||||
SetMenuItemInfo(hMenu, item, TRUE, &miInfo);
|
||||
}
|
||||
|
||||
void ODMenu::GenerateDisplayText(ODMENUITEM& item)
|
||||
{
|
||||
TCHAR* pChr;
|
||||
int i;
|
||||
|
||||
item.displayText = "";
|
||||
item.rawDisplayText = "";
|
||||
item.shortcutText = "";
|
||||
|
||||
//Does shortcut text exist?
|
||||
if(pChr = strchr((LPTSTR)item.rawText.c_str(), '\t'))
|
||||
item.shortcutText = pChr + 1;
|
||||
|
||||
i = 0;
|
||||
pChr = (LPTSTR)item.rawText.c_str();
|
||||
while(*(pChr + i) != '\t' && *(pChr + i) != '\0')
|
||||
{
|
||||
if(*(pChr + i) == '&')
|
||||
{
|
||||
item.rawDisplayText.append(pChr + i, 1);
|
||||
i++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
item.rawDisplayText.append(pChr + i, 1);
|
||||
item.displayText.append(pChr + i, 1);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::DrawItemText(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
|
||||
{
|
||||
int x, y;
|
||||
SIZE size;
|
||||
RECT rectText;
|
||||
RECT rectItem;
|
||||
|
||||
memcpy(&rectItem, &lpdis->rcItem, sizeof(RECT));
|
||||
|
||||
//Get size of text to draw
|
||||
GetTextExtentPoint32(lpdis->hDC, item.displayText.c_str(), item.displayText.length(), &size);
|
||||
|
||||
// Determine where to draw.
|
||||
ComputeMenuTextPos(lpdis, item, x, y, size);
|
||||
|
||||
rectText.left = x;
|
||||
rectText.right = lpdis->rcItem.right - m_textRightMargin;
|
||||
rectText.top = y;
|
||||
rectText.bottom = lpdis->rcItem.bottom;
|
||||
|
||||
//Adjust rectangle that will contain the menu item
|
||||
if(!item.topMost)
|
||||
{
|
||||
rectItem.left += (m_iconWidth + 2*m_iconBarMargin);
|
||||
}
|
||||
|
||||
//Draw the item rectangle with appropriate background color
|
||||
ExtTextOut(lpdis->hDC, x, y, ETO_OPAQUE, &rectItem, "", 0, NULL);
|
||||
|
||||
//Draw the text
|
||||
DrawText(lpdis->hDC, item.rawDisplayText.c_str(), item.rawDisplayText.length(),
|
||||
&rectText, DT_LEFT | DT_SINGLELINE | DT_VCENTER);
|
||||
DrawText(lpdis->hDC, item.shortcutText.c_str(), item.shortcutText.length(),
|
||||
&rectText, DT_RIGHT | DT_SINGLELINE | DT_VCENTER);
|
||||
}
|
||||
|
||||
void ODMenu::DrawIconBar(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item)
|
||||
{
|
||||
RECT rectBar;
|
||||
memcpy(&rectBar, &lpdis->rcItem, sizeof(RECT));
|
||||
|
||||
//Draw icon bar if not top level
|
||||
if(!item.topMost)
|
||||
{
|
||||
rectBar.right = rectBar.left + m_iconWidth + 2*m_iconBarMargin + 1;
|
||||
if(lpdis->itemState & ODS_SELECTED &&
|
||||
!(lpdis->itemState & ODS_DISABLED || lpdis->itemState & ODS_GRAYED))
|
||||
{
|
||||
FillRect(lpdis->hDC, &rectBar, m_hHighlightItemBackgroundBrush);
|
||||
}
|
||||
else
|
||||
{
|
||||
FillRect(lpdis->hDC, &rectBar, m_hIconBarBrush);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int x, y;
|
||||
|
||||
//Draw icon for menu item if handle is valid
|
||||
if(item.hBitmap)
|
||||
{
|
||||
x = m_iconBarMargin;
|
||||
y = rectBar.top + ((rectBar.bottom - rectBar.top - 16) / 2);
|
||||
|
||||
if(lpdis->itemState & ODS_DISABLED || lpdis->itemState & ODS_GRAYED)
|
||||
{
|
||||
//Draw disabled icon in normal position
|
||||
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eDisabled);
|
||||
}
|
||||
else if(lpdis->itemState & ODS_SELECTED)
|
||||
{
|
||||
//Draw icon "raised"
|
||||
//Draw shadow right one pixel and down one pixel from normal position
|
||||
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x+1, y+1, m_clrTranparent, eShadow);
|
||||
|
||||
//Draw normal left one pixel and up one pixel from normal position
|
||||
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x-1, y-1, m_clrTranparent);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Draw faded icon in normal position
|
||||
DrawTransparentBitmap(lpdis->hDC, item.hBitmap, x, y, m_clrTranparent, eFaded);
|
||||
}
|
||||
}
|
||||
else if(lpdis->itemState & ODS_CHECKED)
|
||||
{
|
||||
HBRUSH hPrevBrush;
|
||||
HPEN hPrevPen;
|
||||
RECT rect;
|
||||
|
||||
//Draw filled, outlined rectangle around checkmark first
|
||||
if(lpdis->itemState & ODS_SELECTED)
|
||||
hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, m_hCheckMarkBackgroundHighlightBrush);
|
||||
else
|
||||
hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, m_hCheckMarkBackgroundBrush);
|
||||
hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSelectionOutlinePen);
|
||||
rect.left = m_iconBarMargin;
|
||||
rect.right = m_iconBarMargin + m_iconWidth;
|
||||
rect.top = rectBar.top + (rectBar.bottom - rectBar.top - m_iconHeight) / 2;
|
||||
rect.bottom = rect.top + m_iconHeight;
|
||||
Rectangle(lpdis->hDC, rect.left, rect.top, rect.right, rect.bottom);
|
||||
SelectObject(lpdis->hDC, hPrevBrush);
|
||||
SelectObject(lpdis->hDC, hPrevPen);
|
||||
|
||||
//Draw check mark
|
||||
x = (m_iconWidth + 2*m_iconBarMargin - 6) / 2;
|
||||
y = rectBar.top + ((rectBar.bottom - rectBar.top - 7) / 2) + 1;
|
||||
DrawCheckMark(lpdis->hDC, x, y, true);
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::ComputeMenuTextPos(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item, int& x, int& y, SIZE& size)
|
||||
{
|
||||
x = lpdis->rcItem.left;
|
||||
y = lpdis->rcItem.top;
|
||||
// y += ((lpdis->rcItem.bottom - lpdis->rcItem.top - size.cy) / 2);
|
||||
|
||||
if(!item.topMost)
|
||||
{
|
||||
//Correct position for drop down menus. Leave space for a bitmap
|
||||
x += (m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Center horizontally for top level menu items
|
||||
x += ((lpdis->rcItem.right - lpdis->rcItem.left - size.cx) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart,
|
||||
short yStart, COLORREF cTransparentColor,
|
||||
bitmapType eType)
|
||||
{
|
||||
BITMAP bm;
|
||||
COLORREF cColor;
|
||||
HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave;
|
||||
HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld;
|
||||
HDC hdcMem, hdcBack, hdcObject, hdcTemp, hdcSave;
|
||||
POINT ptSize;
|
||||
HBRUSH hOldBrush;
|
||||
|
||||
BOOL bRC;
|
||||
|
||||
hdcTemp = CreateCompatibleDC(hDC);
|
||||
SelectObject(hdcTemp, hBitmap); // Select the bitmap
|
||||
|
||||
GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
|
||||
ptSize.x = bm.bmWidth; // Get width of bitmap
|
||||
ptSize.y = bm.bmHeight; // Get height of bitmap
|
||||
DPtoLP(hdcTemp, &ptSize, 1); // Convert from device
|
||||
// to logical points
|
||||
|
||||
// Create some DCs to hold temporary data.
|
||||
hdcBack = CreateCompatibleDC(hDC);
|
||||
hdcObject = CreateCompatibleDC(hDC);
|
||||
hdcMem = CreateCompatibleDC(hDC);
|
||||
hdcSave = CreateCompatibleDC(hDC);
|
||||
|
||||
// Create a bitmap for each DC. DCs are required for a number of
|
||||
// GDI functions.
|
||||
|
||||
// Monochrome DC
|
||||
bmAndBack = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
|
||||
|
||||
// Monochrome DC
|
||||
bmAndObject = CreateBitmap(ptSize.x, ptSize.y, 1, 1, NULL);
|
||||
|
||||
bmAndMem = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y);
|
||||
bmSave = CreateCompatibleBitmap(hDC, ptSize.x, ptSize.y);
|
||||
|
||||
// Each DC must select a bitmap object to store pixel data.
|
||||
bmBackOld = (HBITMAP)SelectObject(hdcBack, bmAndBack);
|
||||
bmObjectOld = (HBITMAP)SelectObject(hdcObject, bmAndObject);
|
||||
bmMemOld = (HBITMAP)SelectObject(hdcMem, bmAndMem);
|
||||
bmSaveOld = (HBITMAP)SelectObject(hdcSave, bmSave);
|
||||
|
||||
// Set proper mapping mode.
|
||||
SetMapMode(hdcTemp, GetMapMode(hDC));
|
||||
|
||||
// Save the bitmap sent here, because it will be overwritten.
|
||||
bRC = BitBlt(hdcSave, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
|
||||
|
||||
// Create an "AND mask" that contains the mask of the colors to draw
|
||||
// (the nontransparent portions of the image).
|
||||
|
||||
// Set the background color of the source DC to the color.
|
||||
// contained in the parts of the bitmap that should be transparent
|
||||
cColor = SetBkColor(hdcTemp, cTransparentColor);
|
||||
|
||||
// Create the object mask for the bitmap by performing a BitBlt
|
||||
// from the source bitmap to a monochrome bitmap.
|
||||
bRC = BitBlt(hdcObject, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCCOPY);
|
||||
|
||||
// Set the background color of the source DC back to the original color.
|
||||
SetBkColor(hdcTemp, cColor);
|
||||
|
||||
// Create the inverse of the object mask.
|
||||
bRC = BitBlt(hdcBack, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, NOTSRCCOPY);
|
||||
|
||||
// Copy the background of the main DC to the destination.
|
||||
bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hDC, xStart, yStart, SRCCOPY);
|
||||
|
||||
// Mask out the places where the bitmap will be placed.
|
||||
// hdcMem then contains the background color of hDC only in the places
|
||||
// where the transparent pixels reside.
|
||||
bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcObject, 0, 0, SRCAND);
|
||||
|
||||
if(eType == eNormal)
|
||||
{
|
||||
// Mask out the transparent colored pixels on the bitmap.
|
||||
// hdcTemp then contains only the non-transparent pixels.
|
||||
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
|
||||
|
||||
// XOR the bitmap with the background on the destination DC.
|
||||
// hdcMem then contains the required result.
|
||||
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
|
||||
}
|
||||
else if(eType == eShadow)
|
||||
{
|
||||
//Select shadow brush into hdcTemp
|
||||
hOldBrush = (HBRUSH)SelectObject(hdcTemp, m_hIconShadowBrush);
|
||||
|
||||
//Copy shadow brush pixels for all non-transparent pixels to hdcTemp
|
||||
bRC = BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, MERGECOPY);
|
||||
|
||||
// XOR the bitmap with the background on the destination DC.
|
||||
// hdcMem then contains the required result.
|
||||
bRC = BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
|
||||
|
||||
//Restore the brush in hdcTemp
|
||||
SelectObject(hdcTemp, hOldBrush);
|
||||
}
|
||||
else if(eType == eFaded)
|
||||
{
|
||||
COLORREF col;
|
||||
int x, y;
|
||||
|
||||
//Lighten the color of each pixel in hdcTemp
|
||||
for(x=0; x<ptSize.x; x++)
|
||||
{
|
||||
for(y=0; y<ptSize.y; y++)
|
||||
{
|
||||
col = GetPixel(hdcTemp, x, y);
|
||||
col = LightenColor(col, 0.3);
|
||||
SetPixel(hdcTemp, x, y, col);
|
||||
}
|
||||
}
|
||||
|
||||
// Mask out the transparent colored pixels on the bitmap.
|
||||
// hdcTemp then contains only the non-transparent pixels.
|
||||
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
|
||||
|
||||
// XOR the bitmap with the background on the destination DC.
|
||||
// hdcMem then contains the required result.
|
||||
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
|
||||
}
|
||||
else if(eType == eDisabled)
|
||||
{
|
||||
COLORREF discol, col;
|
||||
BYTE r, g, b;
|
||||
int x, y;
|
||||
int avgcol;
|
||||
double factor;
|
||||
|
||||
//Lighten the color of COLOR_BTNSHADOW by a weighted average of the color at each pixel in hdcTemp.
|
||||
//Set the pixel to the lightened color.
|
||||
discol = GetSysColor(COLOR_BTNSHADOW);
|
||||
for(x=0; x<ptSize.x; x++)
|
||||
{
|
||||
for(y=0; y<ptSize.y; y++)
|
||||
{
|
||||
col = GetPixel(hdcTemp, x, y);
|
||||
r = GetRValue(col);
|
||||
g = GetGValue(col);
|
||||
b = GetBValue(col);
|
||||
avgcol = (r + g + b) / 3;
|
||||
factor = avgcol / 255.0;
|
||||
SetPixel(hdcTemp, x, y, LightenColor(discol, factor));
|
||||
}
|
||||
}
|
||||
|
||||
// Mask out the transparent colored pixels on the bitmap.
|
||||
// hdcTemp then contains only the non-transparent pixels.
|
||||
BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcBack, 0, 0, SRCAND);
|
||||
|
||||
// XOR the bitmap with the background on the destination DC.
|
||||
// hdcMem then contains the required result.
|
||||
BitBlt(hdcMem, 0, 0, ptSize.x, ptSize.y, hdcTemp, 0, 0, SRCPAINT);
|
||||
}
|
||||
|
||||
// Copy the destination to the screen.
|
||||
bRC = BitBlt(hDC, xStart, yStart, ptSize.x, ptSize.y, hdcMem, 0, 0, SRCCOPY);
|
||||
|
||||
// Place the original bitmap back into the bitmap sent here.
|
||||
bRC = BitBlt(hdcTemp, 0, 0, ptSize.x, ptSize.y, hdcSave, 0, 0, SRCCOPY);
|
||||
|
||||
// Delete the memory bitmaps.
|
||||
DeleteObject(SelectObject(hdcBack, bmBackOld));
|
||||
DeleteObject(SelectObject(hdcObject, bmObjectOld));
|
||||
DeleteObject(SelectObject(hdcMem, bmMemOld));
|
||||
DeleteObject(SelectObject(hdcSave, bmSaveOld));
|
||||
|
||||
// Delete the memory DCs.
|
||||
DeleteDC(hdcMem);
|
||||
DeleteDC(hdcBack);
|
||||
DeleteDC(hdcObject);
|
||||
DeleteDC(hdcSave);
|
||||
DeleteDC(hdcTemp);
|
||||
}
|
||||
|
||||
void ODMenu::DrawCheckMark(HDC hDC, short x, short y, bool bNarrow)
|
||||
{
|
||||
HPEN hOldPen;
|
||||
int dp = 0;
|
||||
|
||||
if(bNarrow)
|
||||
dp = 1;
|
||||
|
||||
//Select check mark pen
|
||||
hOldPen = (HPEN)SelectObject(hDC, m_hCheckMarkPen);
|
||||
|
||||
//Draw the check mark
|
||||
MoveToEx(hDC, x, y + 2, NULL);
|
||||
LineTo(hDC, x, y + 5 - dp);
|
||||
|
||||
MoveToEx(hDC, x + 1, y + 3, NULL);
|
||||
LineTo(hDC, x + 1, y + 6 - dp);
|
||||
|
||||
MoveToEx(hDC, x + 2, y + 4, NULL);
|
||||
LineTo(hDC, x + 2, y + 7 - dp);
|
||||
|
||||
MoveToEx(hDC, x + 3, y + 3, NULL);
|
||||
LineTo(hDC, x + 3, y + 6 - dp);
|
||||
|
||||
MoveToEx(hDC, x + 4, y + 2, NULL);
|
||||
LineTo(hDC, x + 4, y + 5 - dp);
|
||||
|
||||
MoveToEx(hDC, x + 5, y + 1, NULL);
|
||||
LineTo(hDC, x + 5, y + 4 - dp);
|
||||
|
||||
MoveToEx(hDC, x + 6, y, NULL);
|
||||
LineTo(hDC, x + 6, y + 3 - dp);
|
||||
|
||||
//Restore original DC pen
|
||||
SelectObject(hDC, hOldPen);
|
||||
}
|
||||
|
||||
COLORREF ODMenu::LightenColor(COLORREF col, double factor)
|
||||
{
|
||||
if(factor > 0.0 && factor <= 1.0)
|
||||
{
|
||||
BYTE red, green, blue, lightred, lightgreen, lightblue;
|
||||
red = GetRValue(col);
|
||||
green = GetGValue(col);
|
||||
blue = GetBValue(col);
|
||||
lightred = (BYTE)((factor*(255 - red)) + red);
|
||||
lightgreen = (BYTE)((factor*(255 - green)) + green);
|
||||
lightblue = (BYTE)((factor*(255 - blue)) + blue);
|
||||
col = RGB(lightred, lightgreen, lightblue);
|
||||
}
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
COLORREF ODMenu::DarkenColor(COLORREF col, double factor)
|
||||
{
|
||||
if(factor > 0.0 && factor <= 1.0)
|
||||
{
|
||||
BYTE red, green, blue, lightred, lightgreen, lightblue;
|
||||
red = GetRValue(col);
|
||||
green = GetGValue(col);
|
||||
blue = GetBValue(col);
|
||||
lightred = (BYTE)(red - (factor*red));
|
||||
lightgreen = (BYTE)(green - (factor*green));
|
||||
lightblue = (BYTE)(blue - (factor*blue));
|
||||
col = RGB(lightred, lightgreen, lightblue);
|
||||
}
|
||||
return col;
|
||||
}
|
||||
|
||||
COLORREF ODMenu::AverageColor(COLORREF col1, COLORREF col2, double weight1)
|
||||
{
|
||||
BYTE red1, green1, blue1, red2, green2, blue2;
|
||||
BYTE avgRed, avgGreen, avgBlue;
|
||||
COLORREF col;
|
||||
double weight2;
|
||||
|
||||
if(weight1 < 0.0 || weight1 > 1.0)
|
||||
return col1;
|
||||
|
||||
weight2 = 1.0 - weight1;
|
||||
|
||||
red1 = GetRValue(col1);
|
||||
green1 = GetGValue(col1);
|
||||
blue1 = GetBValue(col1);
|
||||
red2 = GetRValue(col2);
|
||||
green2 = GetGValue(col2);
|
||||
blue2 = GetBValue(col2);
|
||||
|
||||
avgRed = weight1 * red1 + weight2 * red2;
|
||||
avgGreen = weight1 * green1 + weight2 * green2;
|
||||
avgBlue = weight1 * blue1 + weight2 * blue2;
|
||||
|
||||
col = RGB(avgRed, avgGreen, avgBlue);
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
double ODMenu::GetColorIntensity(COLORREF col)
|
||||
{
|
||||
BYTE red, green, blue;
|
||||
|
||||
red = GetRValue(col);
|
||||
green = GetGValue(col);
|
||||
blue = GetBValue(col);
|
||||
|
||||
//denominator of 765 is (255*3)
|
||||
return (double)red/765.0 + (double)green/765.0 + (double)blue/765.0;
|
||||
}
|
||||
|
||||
void ODMenu::MeasureItem(HWND hWnd, LPARAM lParam)
|
||||
{
|
||||
MEASUREITEMSTRUCT* lpmis = (MEASUREITEMSTRUCT*)lParam;
|
||||
ODMENUITEMS::iterator it;
|
||||
ODMENUITEM item;
|
||||
HDC hDC;
|
||||
HFONT hfntOld;
|
||||
RECT rect;
|
||||
|
||||
it = m_menuItems.find(lpmis->itemData);
|
||||
if(it == m_menuItems.end())
|
||||
return;
|
||||
|
||||
hDC = GetDC(hWnd);
|
||||
hfntOld = (HFONT)SelectObject(hDC, m_hFont);
|
||||
|
||||
item = it->second;
|
||||
if(item.displayText.length() > 0)
|
||||
{
|
||||
DrawText(hDC, item.rawText.c_str(), item.rawText.length(), &rect,
|
||||
DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);
|
||||
lpmis->itemWidth = rect.right - rect.left;
|
||||
|
||||
if(!item.topMost)
|
||||
{
|
||||
//Correct size for drop down menus
|
||||
lpmis->itemWidth += (m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin + m_textRightMargin);
|
||||
lpmis->itemHeight += m_verticalSpacing;
|
||||
}
|
||||
}
|
||||
else if(item.dwType & MFT_SEPARATOR)
|
||||
{
|
||||
//Correct size for drop down menus
|
||||
if(!item.topMost)
|
||||
{
|
||||
lpmis->itemWidth += (m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin + m_textRightMargin);
|
||||
lpmis->itemHeight = 3;
|
||||
}
|
||||
}
|
||||
|
||||
SelectObject(hDC, hfntOld);
|
||||
ReleaseDC(hWnd, hDC);
|
||||
}
|
||||
|
||||
void ODMenu::DrawItem(HWND hWnd, LPARAM lParam)
|
||||
{
|
||||
DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
|
||||
ODMENUITEMS::iterator it;
|
||||
ODMENUITEM item;
|
||||
COLORREF clrPrevText, clrPrevBkgnd;
|
||||
HFONT hPrevFnt;
|
||||
HPEN hPrevPen;
|
||||
HBRUSH hPrevBrush;
|
||||
|
||||
it = m_menuItems.find(lpdis->itemData);
|
||||
if(it == m_menuItems.end())
|
||||
return;
|
||||
|
||||
item = it->second;
|
||||
|
||||
//Draw based on type of item
|
||||
if(item.displayText.length() > 0)
|
||||
{
|
||||
// Set the appropriate foreground and background colors.
|
||||
if(item.topMost)
|
||||
{
|
||||
if(lpdis->itemState & ODS_SELECTED)
|
||||
{
|
||||
clrPrevText = SetTextColor(lpdis->hDC, m_clrHighlightItemText);
|
||||
clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrHighlightItemBackground);
|
||||
}
|
||||
else
|
||||
{
|
||||
clrPrevText = SetTextColor(lpdis->hDC, m_clrItemText);
|
||||
clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor(COLOR_MENU));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(lpdis->itemState & ODS_GRAYED || lpdis->itemState & ODS_DISABLED)
|
||||
{
|
||||
clrPrevText = SetTextColor(lpdis->hDC, GetSysColor(COLOR_3DSHADOW));
|
||||
clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrItemBackground);
|
||||
}
|
||||
else if(lpdis->itemState & ODS_SELECTED)
|
||||
{
|
||||
clrPrevText = SetTextColor(lpdis->hDC, m_clrHighlightItemText);
|
||||
clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrHighlightItemBackground);
|
||||
}
|
||||
else
|
||||
{
|
||||
clrPrevText = SetTextColor(lpdis->hDC, m_clrItemText);
|
||||
clrPrevBkgnd = SetBkColor(lpdis->hDC, m_clrItemBackground);
|
||||
}
|
||||
}
|
||||
|
||||
// Select the font.
|
||||
hPrevFnt = (HFONT)SelectObject(lpdis->hDC, m_hFont);
|
||||
|
||||
//Draw the text
|
||||
DrawItemText(lpdis, item);
|
||||
|
||||
//Restore original font
|
||||
SelectObject(lpdis->hDC, hPrevFnt);
|
||||
|
||||
SetTextColor(lpdis->hDC, clrPrevText);
|
||||
SetBkColor(lpdis->hDC, clrPrevBkgnd);
|
||||
}
|
||||
else if(item.dwType & MFT_SEPARATOR)
|
||||
{
|
||||
//Fill menu space with menu background, first.
|
||||
RECT rect;
|
||||
memcpy(&rect, &lpdis->rcItem, sizeof(RECT));
|
||||
rect.left += (m_iconWidth + 2*m_iconBarMargin);
|
||||
FillRect(lpdis->hDC, &rect, m_hItemBackground);
|
||||
|
||||
//Draw the separator line
|
||||
hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSeparatorPen);
|
||||
MoveToEx(lpdis->hDC, lpdis->rcItem.left + m_iconWidth + 2*m_iconBarMargin + m_textLeftMargin,
|
||||
lpdis->rcItem.top+1, NULL);
|
||||
LineTo(lpdis->hDC, lpdis->rcItem.right, lpdis->rcItem.top+1);
|
||||
|
||||
//Restore GDI objects in DC
|
||||
SelectObject(lpdis->hDC, hPrevPen);
|
||||
}
|
||||
|
||||
//Draw the left icon bar
|
||||
DrawIconBar(lpdis, item);
|
||||
|
||||
//Draw selection outline if drawing a selected item
|
||||
if(lpdis->itemState & ODS_SELECTED && !(lpdis->itemState & ODS_GRAYED || lpdis->itemState & ODS_DISABLED))
|
||||
{
|
||||
hPrevBrush = (HBRUSH)SelectObject(lpdis->hDC, (HBRUSH)GetStockObject(NULL_BRUSH));
|
||||
hPrevPen = (HPEN)SelectObject(lpdis->hDC, m_hSelectionOutlinePen);
|
||||
Rectangle(lpdis->hDC, lpdis->rcItem.left, lpdis->rcItem.top,
|
||||
lpdis->rcItem.right, lpdis->rcItem.bottom);
|
||||
|
||||
//Restore GDI objects in DC
|
||||
SelectObject(lpdis->hDC, hPrevBrush);
|
||||
SelectObject(lpdis->hDC, hPrevPen);
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::OnDestroy()
|
||||
{
|
||||
}
|
||||
|
||||
bool ODMenu::GetItem(UINT id, ODMENUITEM** ppItem)
|
||||
{
|
||||
bool bRC = true;
|
||||
|
||||
if(!ppItem)
|
||||
return false;
|
||||
|
||||
ODMENUITEMS::iterator it = m_menuItems.find(id);
|
||||
if(it != m_menuItems.end())
|
||||
*ppItem = &it->second;
|
||||
|
||||
return bRC;
|
||||
}
|
||||
|
||||
void ODMenu::SetItemImage(HINSTANCE hInst, UINT wID, UINT idBitmap)
|
||||
{
|
||||
//Get iterator to ODMENUITEM
|
||||
ODMENUITEMS::iterator it;
|
||||
HBITMAP hBitmap;
|
||||
|
||||
//Load the bitmap resource
|
||||
hBitmap = (HBITMAP)LoadImage(hInst, MAKEINTRESOURCE(idBitmap), IMAGE_BITMAP, 0, 0, LR_SHARED);
|
||||
if(hBitmap)
|
||||
{
|
||||
//Find menu item having specified wID.
|
||||
it = m_menuItems.begin();
|
||||
while(it != m_menuItems.end())
|
||||
{
|
||||
if(it->second.wID == wID)
|
||||
{
|
||||
it->second.hBitmap = hBitmap;
|
||||
break;
|
||||
}
|
||||
|
||||
it++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD dwErr = GetLastError();
|
||||
dwErr = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::AddItem(HMENU hMenu, int index, MENUITEMINFO* pItemInfo)
|
||||
{
|
||||
MENUITEMINFO miInfo;
|
||||
ODMENUITEM odInfo;
|
||||
|
||||
//Obtain menu item info if not supplied
|
||||
if(!pItemInfo)
|
||||
{
|
||||
miInfo.cbSize = sizeof(MENUITEMINFO);
|
||||
miInfo.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;
|
||||
miInfo.dwTypeData = m_szItemText;
|
||||
miInfo.cch = sizeof(m_szItemText);
|
||||
|
||||
if(GetMenuItemInfo(hMenu, index, TRUE, &miInfo))
|
||||
pItemInfo = &miInfo;
|
||||
}
|
||||
|
||||
//Add menu info to map of menu items
|
||||
if(pItemInfo)
|
||||
{
|
||||
if(pItemInfo->hSubMenu != NULL && hMenu == m_hRootMenu)
|
||||
odInfo.topMost = true;
|
||||
else
|
||||
odInfo.topMost = false;
|
||||
if(pItemInfo->fType == MFT_STRING)
|
||||
{
|
||||
odInfo.rawText = pItemInfo->dwTypeData;
|
||||
GenerateDisplayText(odInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
odInfo.rawText = "";
|
||||
odInfo.displayText = "";
|
||||
}
|
||||
odInfo.dwType = pItemInfo->fType;
|
||||
odInfo.wID = pItemInfo->wID;
|
||||
odInfo.hBitmap = NULL;
|
||||
m_menuItems[m_seqNumber] = odInfo;
|
||||
SetMenuItemOwnerDrawn(hMenu, index, pItemInfo->fType);
|
||||
}
|
||||
}
|
||||
|
||||
void ODMenu::DeleteItem(HMENU hMenu, int index)
|
||||
{
|
||||
//Item data for item is map index
|
||||
MENUITEMINFO miInfo;
|
||||
|
||||
miInfo.cbSize = sizeof(MENUITEMINFO);
|
||||
miInfo.fMask = MIIM_SUBMENU | MIIM_DATA;
|
||||
if(GetMenuItemInfo(hMenu, index, TRUE, &miInfo))
|
||||
{
|
||||
if(miInfo.hSubMenu)
|
||||
DeleteSubMenu(miInfo.hSubMenu);
|
||||
|
||||
//Remove this item from map
|
||||
m_menuItems.erase(miInfo.dwItemData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#ifndef _ODMENU_CLW
|
||||
#define _ODMENU_CLW
|
||||
|
||||
#include <windows.h>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
enum bitmapType {eNormal, eDisabled, eShadow, eFaded};
|
||||
|
||||
typedef struct tagODMENUITEM
|
||||
{
|
||||
UINT dwType;
|
||||
UINT wID;
|
||||
string rawText;
|
||||
string displayText;
|
||||
string rawDisplayText;
|
||||
string shortcutText;
|
||||
HBITMAP hBitmap;
|
||||
bool topMost;
|
||||
|
||||
} ODMENUITEM;
|
||||
|
||||
typedef map<UINT, ODMENUITEM> ODMENUITEMS;
|
||||
|
||||
class ODMenu
|
||||
{
|
||||
//Aesthetic parameters
|
||||
COLORREF m_clrIconBar;
|
||||
COLORREF m_clrTranparent;
|
||||
COLORREF m_clrItemText;
|
||||
COLORREF m_clrItemBackground;
|
||||
COLORREF m_clrHighlightItemText;
|
||||
COLORREF m_clrHighlightItemBackground;
|
||||
COLORREF m_clrHighlightItemOutline;
|
||||
COLORREF m_clrSeparator;
|
||||
COLORREF m_clrIconShadow;
|
||||
COLORREF m_clrCheckMark;
|
||||
COLORREF m_clrCheckMarkBackground;
|
||||
COLORREF m_clrCheckMarkBackgroundHighlight;
|
||||
UINT m_iconBarMargin;
|
||||
UINT m_iconWidth;
|
||||
UINT m_iconHeight;
|
||||
UINT m_textLeftMargin;
|
||||
UINT m_textRightMargin;
|
||||
UINT m_verticalSpacing;
|
||||
|
||||
//GDI object handles
|
||||
HBRUSH m_hIconBarBrush;
|
||||
HBRUSH m_hIconShadowBrush;
|
||||
HBRUSH m_hCheckMarkBackgroundBrush;
|
||||
HBRUSH m_hCheckMarkBackgroundHighlightBrush;
|
||||
HBRUSH m_hItemBackground;
|
||||
HBRUSH m_hHighlightItemBackgroundBrush;
|
||||
HPEN m_hSelectionOutlinePen;
|
||||
HPEN m_hSeparatorPen;
|
||||
HPEN m_hCheckMarkPen;
|
||||
HFONT m_hFont;
|
||||
|
||||
UINT m_seqNumber;
|
||||
HMENU m_hRootMenu;
|
||||
TCHAR m_szItemText[256];
|
||||
ODMENUITEMS m_menuItems;
|
||||
|
||||
int m_alpDx[256];
|
||||
|
||||
void EnumMenuItems(HMENU hMenu);
|
||||
void DeleteSubMenu(HMENU hMenu);
|
||||
void SetMenuItemOwnerDrawn(HMENU hMenu, UINT item, UINT type);
|
||||
void GenerateDisplayText(ODMENUITEM& item);
|
||||
void DrawItemText(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item);
|
||||
void DrawIconBar(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item);
|
||||
void ComputeMenuTextPos(DRAWITEMSTRUCT* lpdis, ODMENUITEM& item, int& x, int& y, SIZE& size);
|
||||
void DrawTransparentBitmap(HDC hDC, HBITMAP hBitmap, short xStart, short yStart,
|
||||
COLORREF cTransparentColor, bitmapType eType=eNormal);
|
||||
void DrawCheckMark(HDC hDC, short x, short y, bool bNarrow=true);
|
||||
COLORREF LightenColor(COLORREF col, double factor);
|
||||
COLORREF DarkenColor(COLORREF col, double factor);
|
||||
COLORREF AverageColor(COLORREF col1, COLORREF col2, double weight1=0.5);
|
||||
double GetColorIntensity(COLORREF col);
|
||||
|
||||
public:
|
||||
ODMenu();
|
||||
~ODMenu();
|
||||
|
||||
bool Init(HWND hOwnerWnd, HMENU hMenu);
|
||||
void MeasureItem(HWND hWnd, LPARAM lParam);
|
||||
void DrawItem(HWND hWnd, LPARAM lParam);
|
||||
void OnDestroy();
|
||||
bool GetItem(UINT id, ODMENUITEM** ppItem);
|
||||
void SetItemImage(HINSTANCE hInst, UINT wID, UINT idBitmap);
|
||||
void AddItem(HMENU hMenu, int index, MENUITEMINFO* pItemInfo=NULL);
|
||||
void DeleteItem(HMENU hMenu, int index);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue