📄 bcgpopupmenu.cpp
字号:
//*******************************************************************************
// COPYRIGHT NOTES
// ---------------
// This source code is a part of BCGControlBar library.
// You may use, compile or redistribute it as part of your application
// for free. You cannot redistribute it as a part of a software development
// library without the agreement of the author. If the sources are
// distributed along with the application, you should leave the original
// copyright notes in the source code without any changes.
// This code can be used WITHOUT ANY WARRANTIES on your own risk.
//
// Stas Levin <stas@iet.co.il>
//*******************************************************************************
// BCGPopupMenu.cpp : implementation file
//
#include "stdafx.h"
#include "BCGPopupMenu.h"
#include "BCGMenuBar.h"
#include "globals.h"
#include "BCGToolbarMenuButton.h"
#include "BCGMDIFrameWnd.h"
#include "BCGFrameWnd.h"
#include "BCGOleIPFrameWnd.h"
#include "BCGMenuBar.h"
#include "menupage.h"
#include "MenuHash.h"
#include "MenuImages.h"
#include "BCGShowAllButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static COLORREF PixelAlpha (COLORREF srcPixel, int percent);
inline static void SetAlphaPixel (COLORREF* pBits, CRect rect, int x, int y, int percent, int iShadowSize);
/////////////////////////////////////////////////////////////////////////////
// CBCGPopupMenu
static const int iBorderSize = 2;
static const int iAnimTimerId = 1;
static const int iAnimTimerDuration = 30;
static const int iScrollTimerId = 2;
static const int iScrollTimerDuration = 80;
static const int iShadowSize = 7;
CString CBCGPopupMenu::m_strClassName;
int CBCGPopupMenu::m_nBitsPerPixel = 0;
CBCGPopupMenu::ANIMATION_TYPE CBCGPopupMenu::m_AnimationType = NO_ANIMATION;
IMPLEMENT_SERIAL(CBCGPopupMenu, CMiniFrameWnd, VERSIONABLE_SCHEMA | 1)
CBCGPopupMenu::CBCGPopupMenu() :
m_pMenuCustomizationPage (NULL)
{
Initialize ();
}
//****************************************************************************************
CBCGPopupMenu::CBCGPopupMenu(CBCGMenuPage* pCustPage, LPCTSTR lpszTitle) :
m_pMenuCustomizationPage (pCustPage),
m_strCaption (lpszTitle)
{
Initialize ();
}
//****************************************************************************************
void CBCGPopupMenu::Initialize ()
{
m_hMenu = NULL;
m_ptLocation = CPoint (0, 0);
m_ptLocationAnim = CPoint (-1, -1);
m_pParentBtn = NULL;
m_bAutoDestroyParent = TRUE;
m_bAutoDestroy = TRUE;
m_FinalSize = CSize (0, 0);
m_AnimSize = CSize (0, 0);
m_bAnimationIsDone = (m_AnimationType == NO_ANIMATION);
m_bScrollable = FALSE;
m_bTobeDstroyed = FALSE;
m_bShown = FALSE;
m_iMaxWidth = -1;
m_rectScrollUp.SetRectEmpty ();
m_rectScrollDn.SetRectEmpty ();
m_iScrollMode = 0;
m_bIsAnimRight = TRUE;
m_bIsAnimDown = TRUE;
m_bSaveShadows = FALSE;
if (m_nBitsPerPixel == 0) // Not defined yet
{
CClientDC dc (NULL);
m_nBitsPerPixel = dc.GetDeviceCaps (BITSPIXEL);
}
m_iShadowSize = CBCGMenuBar::IsMenuShadows () &&
!CBCGToolBar::IsCustomizeMode () &&
m_nBitsPerPixel > 8 ? // Don't draw shadows in 256 colors or less
iShadowSize : 0;
}
//****************************************************************************************
CBCGPopupMenu::~CBCGPopupMenu()
{
if (m_bAutoDestroy && m_hMenu != NULL)
{
::DestroyMenu (m_hMenu);
}
}
BEGIN_MESSAGE_MAP(CBCGPopupMenu, CMiniFrameWnd)
//{{AFX_MSG_MAP(CBCGPopupMenu)
ON_WM_CREATE()
ON_WM_SIZE()
ON_WM_PAINT()
ON_WM_MOUSEACTIVATE()
ON_WM_DESTROY()
ON_WM_KEYDOWN()
ON_WM_ERASEBKGND()
ON_WM_ACTIVATEAPP()
ON_WM_TIMER()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBCGPopupMenu message handlers
BOOL CBCGPopupMenu::Create (CWnd* pWndParent, int x, int y, HMENU hMenu, BOOL bLocked)
{
// Play standard menu popup sound!
::PlaySound (_T("MenuPopup"), NULL, SND_ASYNC | SND_NODEFAULT);
ASSERT (pWndParent != NULL);
if (m_strClassName.IsEmpty ())
{
m_strClassName = ::AfxRegisterWndClass (
CS_SAVEBITS,
::LoadCursor(NULL, IDC_ARROW),
(HBRUSH)(COLOR_BTNFACE + 1), NULL);
}
m_hMenu = hMenu;
if (x == -1 && y == -1) // Undefined position
{
if (pWndParent != NULL)
{
CRect rectParent;
pWndParent->GetClientRect (&rectParent);
pWndParent->ClientToScreen (&rectParent);
m_ptLocation = CPoint (rectParent.left + 5, rectParent.top + 5);
}
else
{
m_ptLocation = CPoint (0, 0);
}
}
else
{
m_ptLocation = CPoint (x, y);
}
DWORD dwStyle = WS_POPUP;
if (m_pMenuCustomizationPage != NULL)
{
dwStyle |= (WS_CAPTION | WS_SYSMENU);
}
BOOL bIsAnimate = (m_AnimationType != NO_ANIMATION) &&
!CBCGToolBar::IsCustomizeMode ();
CRect rect (x, y, x, y);
BOOL bCreated = CMiniFrameWnd::CreateEx (
0,
m_strClassName, m_strCaption,
dwStyle, rect,
pWndParent->GetOwner () == NULL ?
pWndParent : pWndParent->GetOwner ());
if (!bCreated)
{
return FALSE;
}
CBCGPopupMenuBar* pMenuBar = GetMenuBar ();
ASSERT_VALID (pMenuBar);
pMenuBar->m_bLocked = bLocked;
if (bIsAnimate)
{
if (m_bIsAnimDown)
{
pMenuBar->SetOffset (pMenuBar->m_Buttons.GetCount () - 1);
}
//--------------------------
// Adjust initial menu size:
//--------------------------
m_AnimSize = m_FinalSize;
m_AnimSize.cy = pMenuBar->GetRowHeight ();
if (m_AnimationType == UNFOLD)
{
m_AnimSize.cx = pMenuBar->GetColumnWidth ();
}
//------------------------------
// Adjust initial menu position:
//------------------------------
m_ptLocationAnim = m_ptLocation;
if (!m_bIsAnimRight)
{
m_ptLocationAnim.x += m_FinalSize.cx - m_AnimSize.cx;
}
if (!m_bIsAnimDown)
{
m_ptLocationAnim.y += m_FinalSize.cy - m_AnimSize.cy;
}
SetWindowPos (NULL, m_ptLocationAnim.x, m_ptLocationAnim.y,
m_AnimSize.cx, m_AnimSize.cy,
SWP_NOZORDER | SWP_NOACTIVATE);
SetTimer (iAnimTimerId, iAnimTimerDuration, NULL);
}
//--------------------------------------
// Update windows covered by the shadow:
//--------------------------------------
UpdateBottomWindows (!m_bAnimationIsDone);
ShowWindow (SW_SHOWNOACTIVATE);
if (CBCGToolBar::IsCustomizeMode ())
{
pMenuBar->Invalidate ();
pMenuBar->UpdateWindow ();
}
return TRUE;
}
//****************************************************************************************
//-----------------------------------------------------
// My "classic " trick - how I can access to protected
// member m_pRecentFileList?
//-----------------------------------------------------
class CBCGApp : public CWinApp
{
friend class CBCGPopupMenu;
};
int CBCGPopupMenu::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMiniFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndMenuBar.Create (this, dwDefaultToolbarStyle | CBRS_TOOLTIPS | CBRS_FLYBY))
{
TRACE(_T("Can't create popup menu bar\n"));
return FALSE;
}
CBCGPopupMenu* pParentPopupMenu = GetParentPopupMenu ();
if (pParentPopupMenu != NULL)
{
m_iMaxWidth = pParentPopupMenu->m_iMaxWidth;
}
m_wndMenuBar.m_iMaxWidth = m_iMaxWidth;
m_wndMenuBar.SetOwner (GetParent ());
return InitMenuBar () ? 0 : 1;
}
//****************************************************************************************
void CBCGPopupMenu::OnSize(UINT nType, int cx, int cy)
{
CMiniFrameWnd::OnSize(nType, cx, cy);
CBCGPopupMenuBar* pMenuBar = GetMenuBar ();
ASSERT_VALID (pMenuBar);
if (pMenuBar->GetSafeHwnd () == NULL)
{
return;
}
CRect rectClient;
GetClientRect (rectClient);
if (m_bAnimationIsDone && !CBCGToolBar::IsCustomizeMode ())
{
rectClient.right -= m_iShadowSize;
rectClient.bottom -= m_iShadowSize;
}
rectClient.DeflateRect (iBorderSize, iBorderSize);
if (m_bScrollable)
{
int iScrollBtnHeight = CMenuImages::Size ().cy + 2 * iBorderSize;
pMenuBar->SetWindowPos (NULL, rectClient.left,
rectClient.top + iScrollBtnHeight + iBorderSize,
rectClient.Width (),
rectClient.Height () - 2 * iScrollBtnHeight - iBorderSize,
SWP_NOZORDER | SWP_NOACTIVATE);
m_rectScrollUp = rectClient;
m_rectScrollUp.top += iBorderSize;
m_rectScrollUp.bottom = m_rectScrollUp.top + iScrollBtnHeight;
m_rectScrollDn = rectClient;
m_rectScrollDn.top = m_rectScrollDn.bottom - iScrollBtnHeight;
}
else
{
UINT uiFlags = SWP_NOZORDER | SWP_NOACTIVATE;
if (!m_bAnimationIsDone)
{
uiFlags |= SWP_NOREDRAW;
}
pMenuBar->SetWindowPos (NULL, rectClient.left, rectClient.top,
rectClient.Width (),
rectClient.Height (),
uiFlags);
m_rectScrollUp.SetRectEmpty ();
m_rectScrollDn.SetRectEmpty ();
}
}
//****************************************************************************************
void CBCGPopupMenu::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rectClient; // Client area rectangle
GetClientRect (&rectClient);
BOOL bDrawShadows = m_iShadowSize != 0 &&
m_bAnimationIsDone &&
!CBCGToolBar::IsCustomizeMode ();
if (bDrawShadows)
{
rectClient.right -= m_iShadowSize;
rectClient.bottom -= m_iShadowSize;
}
if (bDrawShadows)
{
DrawShadows (dc, rectClient);
}
dc.Draw3dRect (rectClient,
globalData.clrBtnLight,
globalData.clrBtnDkShadow);
rectClient.DeflateRect (1, 1);
dc.Draw3dRect (rectClient,
globalData.clrBtnHilite,
globalData.clrBtnShadow);
if (m_bScrollable)
{
DrawImage (&dc, m_rectScrollUp,
IsScrollUpAvailable () ? CMenuImages::IdArowUp : CMenuImages::IdArowUpDisabled,
m_iScrollMode < 0);
DrawImage (&dc, m_rectScrollDn,
IsScrollDnAvailable () ? CMenuImages::IdArowDown : CMenuImages::IdArowDownDsbl,
m_iScrollMode > 0);
}
m_bShown = TRUE;
}
//****************************************************************************************
int CBCGPopupMenu::OnMouseActivate(CWnd* /*pDesktopWnd*/, UINT /*nHitTest*/, UINT /*message*/)
{
return MA_NOACTIVATE;
}
//****************************************************************************************
void CBCGPopupMenu::RecalcLayout (BOOL /*bNotify*/)
{
#ifdef _DEBUG
if (m_pParentBtn != NULL)
{
ASSERT_VALID (m_pParentBtn);
ASSERT (m_pParentBtn->m_pPopupMenu == this);
}
#endif // _DEBUG
CBCGPopupMenuBar* pMenuBar = GetMenuBar ();
ASSERT_VALID (pMenuBar);
if (!::IsWindow (m_hWnd) ||
!::IsWindow (pMenuBar->m_hWnd))
{
return;
}
CRect rectScreen;
::SystemParametersInfo (SPI_GETWORKAREA, 0, &rectScreen, 0);
CSize size = pMenuBar->CalcSize ();
size.cx += iBorderSize * 2;
size.cy += iBorderSize * 2;
if (m_pMenuCustomizationPage != NULL)
{
size.cy += ::GetSystemMetrics (SM_CYSMCAPTION);
size.cy += 2 * ::GetSystemMetrics (SM_CYBORDER) + 5;
}
//---------------------------------------------
// Adjust the menu position by the screen size:
//---------------------------------------------
if (m_ptLocation.x + size.cx > rectScreen.right)
{
//-----------------------------------------------------
// Menu can't be overlapped with the parent popup menu!
//-----------------------------------------------------
CBCGPopupMenu* pParentMenu = GetParentPopupMenu ();
CBCGMenuBar* pParentMenuBar = m_pParentBtn == NULL ? NULL :
DYNAMIC_DOWNCAST (CBCGMenuBar, m_pParentBtn->m_pWndParent);
if (pParentMenu != NULL)
{
CRect rectParent;
pParentMenu->GetWindowRect (rectParent);
m_ptLocation.x = rectParent.left - size.cx;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -