📄 bcgpopupmenu.cpp
字号:
//**************************************************************************************
void CBCGPopupMenu::SetMaxWidth (int iMaxWidth)
{
if (iMaxWidth == m_iMaxWidth)
{
return;
}
m_iMaxWidth = iMaxWidth;
if (GetSafeHwnd () == NULL)
{
return;
}
CBCGPopupMenuBar* pMenuBar = GetMenuBar ();
ASSERT_VALID (pMenuBar);
if (!::IsWindow (m_hWnd) ||
!::IsWindow (pMenuBar->m_hWnd))
{
return;
}
pMenuBar->m_iMaxWidth = m_iMaxWidth;
RecalcLayout ();
}
//*************************************************************************************
BOOL CBCGPopupMenu::InitMenuBar ()
{
if (m_hMenu != NULL)
{
if (m_pParentBtn != NULL ||
!g_menuHash.LoadMenuBar (m_hMenu, &m_wndMenuBar))
{
//-------------------------------------------
// Failed to restore, load the default state:
//-------------------------------------------
if (!m_wndMenuBar.ImportFromMenu (m_hMenu, !HideRarelyUsedCommands ()))
{
TRACE(_T("Can't import menu\n"));
return FALSE;
}
}
}
//----------------------------------------
// Maybe, we should process the MRU files:
//----------------------------------------
CRecentFileList* pMRUFiles =
((CBCGApp*) AfxGetApp ())->m_pRecentFileList;
if (pMRUFiles != NULL && !CBCGToolBar::IsCustomizeMode ())
{
int iMRUItemIndex = 0;
BOOL bIsPrevSeparator = FALSE;
for (POSITION pos = m_wndMenuBar.m_Buttons.GetHeadPosition ();
pos != NULL; iMRUItemIndex ++)
{
POSITION posSave = pos;
CBCGToolbarButton* pButton =
(CBCGToolbarButton*) m_wndMenuBar.m_Buttons.GetNext (pos);
ASSERT (pButton != NULL);
if (pButton->m_nID == ID_FILE_MRU_FILE1 &&
pButton->m_strText == _T("Recent File"))
{
//------------------------------
// Remove dummy item ("Recent"):
//------------------------------
m_wndMenuBar.m_Buttons.RemoveAt (posSave);
delete pButton;
TCHAR szCurDir [_MAX_PATH];
::GetCurrentDirectory (_MAX_PATH, szCurDir);
int nCurDir = lstrlen (szCurDir);
ASSERT (nCurDir >= 0);
szCurDir [nCurDir] = _T('\\');
szCurDir [++ nCurDir] = _T('\0');
//---------------
// Add MRU files:
//---------------
int iNumOfFiles = 0; // Actual added to menu
for (int i = 0; i < pMRUFiles->GetSize (); i ++)
{
CString strName;
if (pMRUFiles->GetDisplayName (strName, i,
szCurDir, nCurDir))
{
//---------------------
// Add shortcut number:
//---------------------
CString strItem;
strItem.Format (_T("&%d %s"), ++iNumOfFiles, strName);
m_wndMenuBar.InsertButton (
CBCGToolbarMenuButton (
ID_FILE_MRU_FILE1 + i, NULL,
-1, strItem),
iMRUItemIndex ++);
}
}
//------------------------------------------------------
// Usualy, the MRU group is "covered" by two seperators.
// If MRU list is empty, remove redandant separator:
//------------------------------------------------------
if (iNumOfFiles == 0 && // No files were added
bIsPrevSeparator && // Prev. button was separator
pos != NULL) // Not a last button
{
posSave = pos;
pButton = (CBCGToolbarButton*)
m_wndMenuBar.m_Buttons.GetNext (pos);
ASSERT (pButton != NULL);
if (pButton->m_nStyle & TBBS_SEPARATOR)
{
//---------------------------------------
// Next button also separator, remove it:
//---------------------------------------
m_wndMenuBar.m_Buttons.RemoveAt (posSave);
delete pButton;
}
}
break;
}
bIsPrevSeparator = (pButton->m_nStyle & TBBS_SEPARATOR);
}
}
//-----------------------------------------------------------------------------
// Maybe, main application frame should update the popup menu context before it
// displayed (example - windows list):
//-----------------------------------------------------------------------------
if (!ActivatePopupMenu (GetTopLevelFrame (), this))
{
return FALSE;
}
RecalcLayout ();
return TRUE;
}
//************************************************************************************
BOOL CBCGPopupMenu::HideRarelyUsedCommands () const
{
return (m_pParentBtn != NULL &&
m_pParentBtn->GetParentWnd ()->IsKindOf (RUNTIME_CLASS (CBCGMenuBar)));
}
//************************************************************************************
void CBCGPopupMenu::UpdateBottomWindows (BOOL bCheckOnly)
{
if (m_iShadowSize > 0)
{
CWnd* pWndMain = GetTopLevelParent ();
if (pWndMain != NULL)
{
//---------------------------------------------------------
// If menu will be shown outside of the application window,
// don't show shadows!
//---------------------------------------------------------
CRect rectMain;
pWndMain->GetWindowRect (rectMain);
CRect rectMenu (m_ptLocation,
CSize (m_FinalSize.cx + m_iShadowSize, m_FinalSize.cy + m_iShadowSize));
CRect rectInter;
rectInter.UnionRect (&rectMenu, &rectMain);
if (rectInter != rectMain)
{
m_iShadowSize = 0;
if (!bCheckOnly)
{
SetWindowPos (NULL, -1, -1, m_FinalSize.cx, m_FinalSize.cy,
SWP_NOMOVE | SWP_NOZORDER |
SWP_NOACTIVATE);
}
}
else
{
pWndMain->UpdateWindow ();
}
}
}
}
// ==================================================================
//
// FUNCTION : DrawShadows ()
//
// * Description : Draws the shadow for a rectangular screen element
//
// * Authors: [Stas Levin ]
// [Timo Hummel], Modified: [8/11/99 5:06:59 PM]
//
// * Function parameters :
// [dc] - The device context to draw into
// [rect] - The CRect of the rectangular region to draw the
// shadow around (altough the CDC needs to be big enough
// to hold the shadow)
// ==================================================================
void CBCGPopupMenu::DrawShadows (CDC& dc, const CRect& rect)
{
const int iMinBrightness = 100;
const int iMaxBrightness = 50;
if (m_iShadowSize == 0)
{
return;
}
int cx = rect.Width ();
int cy = rect.Height ();
if (m_bmpShadowRight.GetSafeHandle () != NULL &&
m_bmpShadowBottom.GetSafeHandle () != NULL)
{
//---------------------------------------------------
// Shadows are already implemented, put them directly
// to the DC:
//---------------------------------------------------
dc.DrawState (CPoint (rect.right + 1, rect.top),
CSize (m_iShadowSize, cy + m_iShadowSize),
&m_bmpShadowRight, DSS_NORMAL);
dc.DrawState (CPoint (rect.left, rect.bottom + 1),
CSize (cx + m_iShadowSize, m_iShadowSize),
&m_bmpShadowBottom, DSS_NORMAL);
return;
}
ASSERT (m_bmpShadowRight.GetSafeHandle () == NULL);
ASSERT (m_bmpShadowBottom.GetSafeHandle () == NULL);
//--------------------------------------------
// Copy screen content into the memory bitmap:
//--------------------------------------------
CDC dcMem;
if (!dcMem.CreateCompatibleDC (&dc))
{
return;
}
//--------------------------------------------
// Gets the whole menu and changes the shadow.
//--------------------------------------------
CBitmap bmpMem;
if (!bmpMem.CreateCompatibleBitmap (&dc, cx + m_iShadowSize, cy + m_iShadowSize))
{
return;
}
CBitmap* pOldBmp = dcMem.SelectObject(&bmpMem);
ASSERT (pOldBmp != NULL);
LPBITMAPINFO lpbi;
// Fill in the BITMAPINFOHEADER
lpbi = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER) ];
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbi->bmiHeader.biWidth = cx + m_iShadowSize;
lpbi->bmiHeader.biHeight = cy + m_iShadowSize;
lpbi->bmiHeader.biPlanes = 1;
lpbi->bmiHeader.biBitCount = 32;
lpbi->bmiHeader.biCompression = BI_RGB;
lpbi->bmiHeader.biSizeImage = (cx + m_iShadowSize) * (cy + m_iShadowSize);
lpbi->bmiHeader.biXPelsPerMeter = 0;
lpbi->bmiHeader.biYPelsPerMeter = 0;
lpbi->bmiHeader.biClrUsed = 0;
lpbi->bmiHeader.biClrImportant = 0;
COLORREF* pBits = NULL;
HBITMAP hmbpDib = CreateDIBSection (
dcMem.m_hDC, lpbi, DIB_RGB_COLORS, (void **)&pBits,
NULL, NULL);
if (hmbpDib == NULL || pBits == NULL)
{
delete lpbi;
return;
}
dcMem.SelectObject (hmbpDib);
dcMem.BitBlt (0, 0, cx + m_iShadowSize, cy + m_iShadowSize, &dc, rect.left, rect.top, SRCCOPY);
//----------------------------------------------------------------------------
// Process shadowing:
// For having a very nice shadow effect, its actually hard work. Currently,
// I'm using a more or less "hardcoded" way to set the shadows (by using a
// hardcoded algorythm):
//
// This algorythm works as follows:
//
// It always draws a few lines, from left to bottom, from bottom to right,
// from right to up, and from up to left). It does this for the specified
// shadow width and the color settings.
//-----------------------------------------------------------------------------
// For speeding up things, iShadowOffset is the
// value which is needed to multiply for each shadow step
int iShadowOffset = (iMaxBrightness - iMinBrightness) / m_iShadowSize;
// Loop for drawing the shadow
// Actually, this was simpler to implement than I thought
for (int c = 0; c < m_iShadowSize; c++)
{
// Draw the shadow from left to bottom
for (int y = cy; y < cy + (m_iShadowSize - c); y++)
{
SetAlphaPixel (pBits, rect, c + m_iShadowSize, y,
iMaxBrightness - ((m_iShadowSize - c) * (iShadowOffset)),m_iShadowSize);
}
// Draw the shadow from left to right
for (int x = m_iShadowSize + (m_iShadowSize - c); x < cx + c; x++)
{
SetAlphaPixel(pBits, rect,x, cy + c,
iMaxBrightness - ((c) * (iShadowOffset)),m_iShadowSize);
}
// Draw the shadow from top to bottom
for (int y1 = m_iShadowSize + (m_iShadowSize - c); y1 < cy + c + 1; y1++)
{
SetAlphaPixel(pBits, rect, cx+c, y1,
iMaxBrightness - ((c) * (iShadowOffset)),
m_iShadowSize);
}
// Draw the shadow from top to left
for (int x1 = cx; x1 < cx + (m_iShadowSize - c); x1++)
{
SetAlphaPixel (pBits, rect, x1, c + m_iShadowSize,
iMaxBrightness - ((m_iShadowSize - c) * (iShadowOffset)),
m_iShadowSize);
}
}
//-----------------------------------------
// Copy shadowed bitmap back to the screen:
//-----------------------------------------
dc.BitBlt (rect.left, rect.top, cx + m_iShadowSize, cy + m_iShadowSize,
&dcMem, 0, 0, SRCCOPY);
if (m_bSaveShadows)
{
//------------------------------------
// Save shadows in the memory bitmaps:
//------------------------------------
m_bmpShadowRight.CreateCompatibleBitmap (&dc, m_iShadowSize, cy + m_iShadowSize);
dcMem.SelectObject (&m_bmpShadowRight);
dcMem.BitBlt (0, 0, m_iShadowSize, cy + m_iShadowSize,
&dc, rect.right + 1, rect.top, SRCCOPY);
m_bmpShadowBottom.CreateCompatibleBitmap (&dc, cx + m_iShadowSize, m_iShadowSize);
dcMem.SelectObject (&m_bmpShadowBottom);
dcMem.BitBlt (0, 0, cx + m_iShadowSize, m_iShadowSize,
&dc, rect.left, rect.bottom + 1, SRCCOPY);
}
dcMem.SelectObject (pOldBmp);
DeleteObject (hmbpDib);
delete lpbi;
}
// ==================================================================
//
// FUNCTION : static void SetAlphaPixel ()
//
// * Description : Draws an alpha blended pixel
//
// * Author : [Timo Hummel], Created : [8/11/99 5:04:38 PM]
//
// * Function parameters :
// [pBits] - The DIB bits
// [x] - X-Coordinate
// [y] - Y-Coordinate
// [percent] - Percentage to blit (100 = hollow, 0 = solid)
//
// ==================================================================
inline static void SetAlphaPixel (COLORREF* pBits, CRect rect, int x, int y, int percent, int m_iShadowSize)
{
// Our direct bitmap access swapped the y coordinate...
y = (rect.Height()+m_iShadowSize)- y;
COLORREF* pColor = (COLORREF*) (pBits + (rect.Width () + m_iShadowSize) * y + x);
*pColor = PixelAlpha (*pColor, percent);
}
// ==================================================================
//
// FUNCTION : PixelAlpha ()
//
// * Description : Shades a color value with a specified percentage
//
// * Author : [Timo Hummel], Created : [8/11/99 2:37:04 PM]
//
// * Returns : [COLORREF] - The result pixel
//
// * Function parameters :
// [srcPixel] - The source pixel
// [percent] - Percentage (amount of shadow)
//
// Example: percent = 10 makes the pixel around 10 times darker
// percent = 50 makes the pixel around 2 times darker
//
// ==================================================================
COLORREF PixelAlpha (COLORREF srcPixel, int percent)
{
// My formula for calculating the transpareny is as
// follows (for each single color):
//
// percent
// destPixel = sourcePixel * ( ------- )
// 100
//
// This is not real alpha blending, as it only modifies the brightness,
// but not the color (a real alpha blending had to mix the source and
// destination pixels, e.g. mixing green and red makes yellow).
// For our nice "menu" shadows its good enough.
COLORREF clrFinal = RGB ( (GetRValue (srcPixel) * percent) / 100,
(GetGValue (srcPixel) * percent) / 100,
(GetBValue (srcPixel) * percent) / 100);
return (clrFinal);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -