📄 skinmenu.cpp
字号:
// SkinMenu.cpp: implementation of the CSkinMenu class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "SkinMenu.h"
#include "SkinMenuMgr.h"
#include "wclassdefines.h"
#include "winclasses.h"
#include "skinglobals.h"
#include "skinbase.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
ISkinMenuRender* CSkinMenu::s_pRenderer = NULL;
enum { REDRAWALL = -2 };
#ifndef SPI_GETMENUANIMATION
#define SPI_GETMENUANIMATION 0x1002
#endif
#ifndef SPI_GETMENUFADE
#define SPI_GETMENUFADE 0x1012
#endif
//////////////////////////////////////////////////////////////////////
struct colorMapping
{
int nSrcColor;
int nDestColor;
};
static colorMapping colors[] =
{
// { COLOR_HIGHLIGHT, COLOR_HIGHLIGHT },
{ COLOR_WINDOWTEXT, COLOR_WINDOWTEXT },
{ COLOR_GRAYTEXT, COLOR_MENU },
{ COLOR_HIGHLIGHTTEXT, COLOR_HIGHLIGHTTEXT },
{ COLOR_3DHILIGHT, COLOR_MENU },
// { COLOR_3DDKSHADOW, COLOR_MENU },
{ COLOR_3DSHADOW, COLOR_3DSHADOW },
{ COLOR_3DFACE, COLOR_MENU },
{ COLOR_MENU, COLOR_MENU },
};
CSkinMenu::CSkinMenu(CSkinGlobals* pGlobals, DWORD dwStyle, int nSBWidth)
: m_pGlobals(pGlobals), m_nSidebarWidth(nSBWidth), m_dwStyle(dwStyle)
{
m_nSelIndex = REDRAWALL; // this ensures a full repaint when we first show
m_hContextWnd = NULL;
m_hMenu = NULL;
// fix for animated menus
m_bFirstRedraw = TRUE;
m_bAnimatedMenus = FALSE;
SystemParametersInfo(SPI_GETMENUANIMATION, 0, &m_bAnimatedMenus, 0);
}
CSkinMenu::~CSkinMenu()
{
}
BOOL CSkinMenu::IsMenuWnd(HWND hWnd)
{
return CWinClasses::IsClass(hWnd, WC_MENU);
}
BOOL CSkinMenu::AttachWindow(HWND hWnd)
{
if (!IsMenuWnd(hWnd))
return FALSE;
if (HookWindow(hWnd))
{
// Invalidate();
// PostMessage(WM_NCPAINT);
return TRUE;
}
// else
return FALSE;
}
BOOL CSkinMenu::DetachWindow()
{
return HookWindow((HWND)NULL);
}
LRESULT CSkinMenu::WindowProc(CWnd* pRealWnd, UINT msg, WPARAM wp, LPARAM lp)
{
ASSERT_VALID(pRealWnd);
UINT uRes = 0;
LRESULT lr = 0;
int nOS = CSkinBase::GetOS();
switch (msg)
{
case WM_NCPAINT:
// the very first WM_NCPAINT appears to be responsible for
// doing any menu animation. since our std OnNcPaint does not
// deal with animation we must leave it to the default handler.
// fortunately, the default handler calls WM_PRINT to implement
// the animation.
if (!m_bAnimatedMenus || !m_bFirstRedraw)
{
CWindowDC dc(pRealWnd);
OnNcPaint(&dc);
return 0;
}
break;
case WM_PRINT:
if (nOS != SBOS_95 && nOS != SBOS_NT4)
{
lr = CSubclassWnd::WindowProc(pRealWnd, msg, wp, lp);
OnNcPaint(CDC::FromHandle((HDC)wp));
return lr;
}
break;
case WM_PRINTCLIENT:
if (nOS != SBOS_95 && nOS != SBOS_NT4)
{
OnPrintClient(CDC::FromHandle((HDC)wp), lp);
return 0;
}
break;
case WM_PAINT:
if (nOS != SBOS_95 && nOS != SBOS_NT4)
{
CPaintDC dc(pRealWnd);
// OnPaint(&dc);
SendMessage(WM_PRINTCLIENT, (WPARAM)(HDC)dc, PRF_CLIENT | PRF_CHECKVISIBLE);
return 0;
}
break;
// handle keyboard navigation
case WM_KEYDOWN:
if (nOS != SBOS_95 && nOS != SBOS_NT4)
{
switch (wp)
{
case VK_UP:
case VK_DOWN:
case VK_RIGHT:
// left is much trickier because if the currently selected item
// has a popup menu then left will close that submenu, and if
// we prevent the default redrawing then the submenu is not correctly
// removed from the screen.
// so we must always do the default drawing and follow it up with our own.
case VK_LEFT:
if (!m_hMenu)
{
if (wp != VK_LEFT)
SetRedraw(FALSE);
lr = Default();
if (wp != VK_LEFT)
SetRedraw(TRUE);
// TRACE ("Invalidating entire menu in response to a cursor keypress\n");
m_nSelIndex = -1; // reset current selection because its too risky to
// try to figure it out for ourselves
Invalidate(FALSE);
UpdateWindow(*this);
m_bFirstRedraw = FALSE;
}
else // have menu handle
{
int nPrevSel = GetCurSel();
if (wp != VK_LEFT)
SetRedraw(FALSE);
lr = Default();
if (wp != VK_LEFT)
SetRedraw(TRUE);
// if we have the handle of the menu then
// we can do a selective redraw else we must redraw all
m_nSelIndex = GetCurSel();
if (m_nSelIndex != nPrevSel)
{
CRect rInvalid;
GetInvalidRect(m_nSelIndex, nPrevSel, rInvalid);
// TRACE ("Invalidating menu items %d & %d in response to a cursor keypress\n", m_nSelIndex, nPrevSel);
InvalidateRect(*this, rInvalid, FALSE);
UpdateWindow(*this);
m_bFirstRedraw = FALSE;
}
}
return lr;
}
}
break;
case 0x1e5:
if (nOS != SBOS_95 && nOS != SBOS_NT4)
{
if (m_nSelIndex != (int)wp)
{
// attempt to do a partial redraw where possible
// this needs more thought
CRect rInvalid;
if (m_hMenu)
GetInvalidRect((int)wp, m_nSelIndex, rInvalid);
else
GetClientRect(rInvalid);
// prevent redrawing during default message processing
// because otherwise the item is redrawn oven ours.
SetRedraw(FALSE);
lr = Default();
SetRedraw(TRUE);
m_nSelIndex = (int)wp;
pRealWnd->InvalidateRect(rInvalid, FALSE);
if (!m_bFirstRedraw)
pRealWnd->UpdateWindow();
}
// special fix for animated menus
if (m_bAnimatedMenus && m_bFirstRedraw)
{
CWindowDC dc(pRealWnd);
OnNcPaint(&dc);
}
m_bFirstRedraw = FALSE;
return lr;
}
break;
case WM_NCCALCSIZE:
if (Sidebar())
{
lr = Default();
LPRECT pRect = wp ? &((LPNCCALCSIZE_PARAMS)lp)->rgrc[0] : (LPRECT)lp;
pRect->left += m_nSidebarWidth;
return lr;
}
break;
case WM_WINDOWPOSCHANGING:
{
WINDOWPOS* pWP = (WINDOWPOS*)lp;
// adjust width for sidebar
if (Sidebar() && !(pWP->flags & SWP_NOSIZE))
pWP->cx += m_nSidebarWidth;
// if we have a parent menu we may need to adjust our
// pos to avoid client repainting issues
if (m_pParentMenu && !(pWP->flags & SWP_NOMOVE))
{
// if we are on the right side of our parent
// then we need to adjust ourselves to avoid the client rect
CRect rParentWindow;
::GetWindowRect(*m_pParentMenu, rParentWindow);
if (pWP->x > rParentWindow.left) // right
{
CRect rParentClient;
::GetClientRect(*m_pParentMenu, rParentClient);
m_pParentMenu->GetHookedWnd()->ClientToScreen(rParentClient);
pWP->x = rParentClient.right;
}
}
}
break;
case WM_ERASEBKGND:
if (nOS != SBOS_95 && nOS != SBOS_NT4)
return TRUE;
break;
default:
break;
}
// We don't handle it: pass along
return CSubclassWnd::WindowProc(pRealWnd, msg, wp, lp);
}
CDC* CSkinMenu::ReplaceSystemColors(CDC* pDCSrc, CDC* pDCDest, LPRECT pRect, LPRECT pClip)
{
int nOS = CSkinBase::GetOS();
if (nOS == SBOS_95 || nOS == SBOS_NT4)
return pDCSrc;
// replace the system colors with skin colors
CMap<COLORREF, COLORREF, int, int&> mapColors;
// 1. replace the actual background color with COLOR_MENU
const COLORREF COLORMENU = GetColor(COLOR_MENU);
COLORREF crSrc, crDest = COLORMENU;
if (m_nSelIndex != 0)
crSrc = pDCSrc->GetPixel(pRect->right, pRect->top);
else
crSrc = pDCSrc->GetPixel(pRect->right, pRect->bottom);
// see if user wants to render bkgnd
if (crSrc != -1)
{
if (s_pRenderer && s_pRenderer->DrawMenuClientBkgnd(pDCDest, pRect, pClip))
{
// transparent blt
CSkinBase::BitBlt(pDCDest, pRect->left, pRect->top,
pRect->right - pRect->left,
pRect->bottom - pRect->top, pDCSrc, 0, 0, SRCCOPY, crSrc);
// swap dest and src
SwapDCs(pDCSrc, pDCDest);
}
// else simple color replacement
else if (ReplaceColor(pDCSrc, crSrc, pDCDest, crDest, pRect, pClip))
{
// swap dest and src
SwapDCs(pDCSrc, pDCDest);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -