📄 xskinbutton.cpp
字号:
#include "stdafx.h"
#include "xSkinButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CxSkinButton
CxSkinButton::CxSkinButton()
{
m_nDrawMode = 1; // normal drawing mode
m_nFocusRectMargin = 0; // disable focus dotted rect
m_hClipRgn = NULL; // no clipping region
m_clrText = GetSysColor(COLOR_BTNTEXT); // default button text color
m_bButtonDown = FALSE;
m_bChecked = FALSE;
}
CxSkinButton::~CxSkinButton()
{
if (m_hClipRgn)
DeleteObject(m_hClipRgn);
DestroyBitmap();
}
void CxSkinButton::DestroyBitmap()
{
m_bmpNormal.DeleteObject();
m_bmpDown.DeleteObject();
m_bmpDisabled.DeleteObject();
m_bmpMask.DeleteObject();
m_bmpOver.DeleteObject();
m_bmpFocus.DeleteObject();
}
/////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CxSkinButton, CButton)
//{{AFX_MSG_MAP(CxSkinButton)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDBLCLK()
ON_WM_KILLFOCUS()
//ON_CONTROL_REFLECT_EX(BN_CLICKED, OnClicked)
ON_WM_KEYDOWN()
//}}AFX_MSG_MAP
// ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
ON_MESSAGE(WM_CXSHADE_RADIO , OnRadioInfo)
ON_MESSAGE(BM_SETCHECK , OnBMSetCheck)
ON_MESSAGE(BM_GETCHECK , OnBMGetCheck)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CxSkinButton message handlers
/////////////////////////////////////////////////////////////////////////////
void CxSkinButton::PreSubclassWindow()
{
// get specific BS_ styles
m_nStyle = GetButtonStyle();
if ((m_nStyle & BS_AUTOCHECKBOX)==BS_AUTOCHECKBOX)
m_nStyle=BS_CHECKBOX;
else if ((m_nStyle & BS_AUTORADIOBUTTON)==BS_AUTORADIOBUTTON)
m_nStyle=BS_RADIOBUTTON;
else { m_nStyle=BS_PUSHBUTTON; }
CButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW);
}
/////////////////////////////////////////////////////////////////////////////
BOOL CxSkinButton::OnEraseBkgnd(CDC* pDC)
{
return TRUE;
} // doesn't erase the button background
/////////////////////////////////////////////////////////////////////////////
void CxSkinButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
ASSERT (lpDrawItemStruct);
// Check if the button state in not in inconsistent mode...
POINT mouse_position;
if ((m_bButtonDown) && (::GetCapture() == m_hWnd) && (::GetCursorPos(&mouse_position)))
{
if (::WindowFromPoint(mouse_position) == m_hWnd)
{
if ((GetState() & BST_PUSHED) != BST_PUSHED)
{
SetState(TRUE);
return;
}
}
else
{
if ((GetState() & BST_PUSHED) == BST_PUSHED)
{
SetState(FALSE);
return;
}
}
}
CString sCaption = _T("");
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); // get device context
RECT r = lpDrawItemStruct->rcItem; // context rectangle
int cx = r.right - r.left ; // get width
int cy = r.bottom - r.top ; // get height
// get text box position
RECT tr = {r.left+m_nFocusRectMargin+2,r.top,r.right-m_nFocusRectMargin-2,r.bottom};
//GetWindowText(sCaption); // get button text
pDC->SetBkMode(TRANSPARENT);
// Select the correct skin
if (lpDrawItemStruct->itemState & ODS_DISABLED)
{
// DISABLED BUTTON
if (m_bmpDisabled.m_hObject == NULL)
pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE));
else
DrawBitmap(pDC, m_bmpDisabled, r, m_nDrawMode);
// if needed, draw the standard 3D rectangular border
if (m_bBorder)
pDC->DrawEdge(&r,EDGE_RAISED,BF_RECT);
// paint the etched button text
pDC->SetTextColor(GetSysColor(COLOR_3DHILIGHT));
pDC->DrawText(sCaption, &tr, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
OffsetRect(&tr, -1, -1);
pDC->DrawText(sCaption, &tr, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
}
else
{
// SELECTED (DOWN) BUTTON
if ((lpDrawItemStruct->itemState & ODS_SELECTED) || m_bChecked)
{
if (m_bmpDown.m_hObject == NULL)
// no skin selected for selected state -> standard button
pDC->FillSolidRect(&r,GetSysColor(COLOR_BTNFACE));
else
{
// paint the skin
DrawBitmap(pDC, m_bmpDown, r, m_nDrawMode);
}
OffsetRect(&tr,1,1); //shift text
// if needed, draw the standard 3D rectangular border
if (m_bBorder)
pDC->DrawEdge(&r,EDGE_SUNKEN,BF_RECT);
}
else
{
// DEFAULT BUTTON
if (m_bmpNormal.m_hObject == NULL)
pDC->FillSolidRect(&r, GetSysColor(COLOR_BTNFACE));
else
{
if ((lpDrawItemStruct->itemState & ODS_FOCUS) && (m_bmpFocus.m_hObject != NULL))
{
DrawBitmap(pDC, m_bmpFocus, r, m_nDrawMode);
}
else
{
DrawBitmap(pDC, m_bmpNormal, r, m_nDrawMode);
}
}
// if needed, draw the standard 3D rectangular border
if (m_bBorder)
pDC->DrawEdge(&r, EDGE_RAISED, BF_RECT);
}
// paint the focus rect
if ((lpDrawItemStruct->itemState & ODS_FOCUS)&&(m_nFocusRectMargin > 0))
{
r.left += m_nFocusRectMargin;
r.top += m_nFocusRectMargin;
r.right -= m_nFocusRectMargin;
r.bottom -= m_nFocusRectMargin;
DrawFocusRect(lpDrawItemStruct->hDC, &r);
}
// paint the enabled button text
pDC->SetTextColor(m_clrText);
pDC->DrawText(sCaption,&tr,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
}
}
/////////////////////////////////////////////////////////////////////////////
int CxSkinButton::GetBitmapWidth (HBITMAP hBitmap)
{
BITMAP bm;
GetObject(hBitmap,sizeof(BITMAP),(PSTR)&bm);
return bm.bmWidth;
}
/////////////////////////////////////////////////////////////////////////////
int CxSkinButton::GetBitmapHeight (HBITMAP hBitmap)
{
BITMAP bm;
GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm);
return bm.bmHeight;
}
/////////////////////////////////////////////////////////////////////////////
void CxSkinButton::DrawBitmap(CDC* dc, HBITMAP hbmp, RECT r, int DrawMode)
{
// DrawMode: 0=Normal; 1=stretch; 2=tiled fill
if (DrawMode == 2)
{
FillWithBitmap(dc,hbmp,r);
return;
}
if (!hbmp) return; //safe check
int cx=r.right - r.left;
int cy=r.bottom - r.top;
CDC dcBmp,dcMask;
dcBmp.CreateCompatibleDC(dc);
dcBmp.SelectObject(hbmp);
if (m_bmpMask.m_hObject != NULL)
{
dcMask.CreateCompatibleDC(dc);
dcMask.SelectObject(m_bmpMask);
CDC hdcMem;
hdcMem.CreateCompatibleDC(dc);
CBitmap hBitmap;
hBitmap.CreateCompatibleBitmap(dc,cx,cy);
hdcMem.SelectObject(hBitmap);
hdcMem.BitBlt(r.left,r.top,cx,cy,dc,0,0,SRCCOPY);
if (!DrawMode)
{
hdcMem.BitBlt(r.left,r.top,cx,cy,&dcBmp,0,0,SRCINVERT);
hdcMem.BitBlt(r.left,r.top,cx,cy,&dcMask,0,0,SRCAND);
hdcMem.BitBlt(r.left,r.top,cx,cy,&dcBmp,0,0,SRCINVERT);
}
else
{
int bx = GetBitmapWidth(hbmp);
int by = GetBitmapHeight(hbmp);
hdcMem.StretchBlt(r.left,r.top,cx,cy,&dcBmp,0,0,bx,by,SRCINVERT);
hdcMem.StretchBlt(r.left,r.top,cx,cy,&dcMask,0,0,bx,by,SRCAND);
hdcMem.StretchBlt(r.left,r.top,cx,cy,&dcBmp,0,0,bx,by,SRCINVERT);
}
dc->BitBlt(r.left,r.top,cx,cy,&hdcMem,0,0,SRCCOPY);
hdcMem.DeleteDC();
hBitmap.DeleteObject();
DeleteDC(dcMask);
}
else
{
if (!DrawMode)
{
dc->BitBlt(r.left,r.top,cx,cy,&dcBmp,0,0,SRCCOPY);
}
else
{
int bx = GetBitmapWidth(hbmp);
int by = GetBitmapHeight(hbmp);
dc->StretchBlt(r.left, r.top, cx, cy, &dcBmp, 0, 0, bx, by, SRCCOPY);
}
}
DeleteDC(dcBmp);
}
/////////////////////////////////////////////////////////////////////////////
void CxSkinButton::FillWithBitmap(CDC* dc, HBITMAP hbmp, RECT r)
{
if (!hbmp) return;
CDC memdc;
memdc.CreateCompatibleDC(dc);
memdc.SelectObject(hbmp);
int w = r.right - r.left;
int h = r.bottom - r.top;
int x,y,z;
int bx=GetBitmapWidth(hbmp);
int by=GetBitmapHeight(hbmp);
for (y = r.top ; y < h ; y += by)
{
if ((y + by) > h) by = h - y;
z = bx;
for (x = r.left ; x < w ; x += z)
{
if ((x + z) > w) z = w - x;
dc->BitBlt(x, y, z, by, &memdc, 0, 0, SRCCOPY);
}
}
DeleteDC(memdc);
}
void CxSkinButton::SetSkin(LPCTSTR normal, LPCTSTR down, LPCTSTR over, LPCTSTR disabled,
LPCTSTR focus, LPCTSTR mask, short drawmode, short border, short margin)
{
DestroyBitmap();
if (normal != NULL)
{
m_bmpNormal.LoadBitmapEx(normal);
if (m_bmpNormal.m_hObject != NULL)
{
SetWindowPos(NULL, 0, 0, GetBitmapWidth(m_bmpNormal), GetBitmapHeight(m_bmpNormal), SWP_NOREPOSITION);
}
}
if (down != NULL)
m_bmpDown.LoadBitmapEx(down);
if (over != NULL)
m_bmpOver.LoadBitmapEx(over);
if (focus != NULL)
m_bmpFocus.LoadBitmapEx(focus);
if (disabled != NULL)
m_bmpDisabled.LoadBitmapEx(disabled);
else if (normal != NULL)
m_bmpDisabled.LoadBitmapEx(normal);
m_nDrawMode = max(0, min(drawmode,2));
m_bBorder = border;
m_nFocusRectMargin = max(0,margin);
if (mask > 0)
{
m_bmpMask.LoadBitmap(mask);
if (m_hClipRgn)
DeleteObject(m_hClipRgn);
m_hClipRgn = CreateRgnFromBitmap(m_bmpMask,RGB(255,255,255));
if (m_hClipRgn)
{
SetWindowRgn(m_hClipRgn, TRUE);
SelectClipRgn((HDC)GetDC(),m_hClipRgn);
}
if (m_nDrawMode == 0)
{
SetWindowPos(NULL,0,0,GetBitmapWidth(m_bmpMask), GetBitmapHeight(m_bmpMask),SWP_NOZORDER|SWP_NOMOVE);
}
}
}
/////////////////////////////////////////////////////////////////////////////
void CxSkinButton::SetSkin(UINT normal, UINT down, UINT over, UINT disabled, UINT focus,
UINT mask, short drawmode, short border, short margin)
{
DestroyBitmap();
if (normal > 0)
{
m_bmpNormal.LoadBitmap(normal);
if (m_bmpNormal.m_hObject != NULL)
{
SetWindowPos(NULL, 0, 0, GetBitmapWidth(m_bmpNormal), GetBitmapHeight(m_bmpNormal), SWP_NOREPOSITION);
}
}
if (down > 0) m_bmpDown.LoadBitmap(down);
if (over > 0) m_bmpOver.LoadBitmap(over);
if (focus > 0) m_bmpFocus.LoadBitmap(focus);
if (disabled > 0) m_bmpDisabled.LoadBitmap(disabled);
else if (normal > 0) m_bmpDisabled.LoadBitmap(normal);
m_nDrawMode = max(0, min(drawmode,2));
m_bBorder = border;
m_nFocusRectMargin = max(0,margin);
if (mask > 0)
{
m_bmpMask.LoadBitmap(mask);
if (m_hClipRgn)
DeleteObject(m_hClipRgn);
m_hClipRgn = CreateRgnFromBitmap(m_bmpMask,RGB(255,255,255));
if (m_hClipRgn)
{
SetWindowRgn(m_hClipRgn, TRUE);
SelectClipRgn((HDC)GetDC(),m_hClipRgn);
}
if (m_nDrawMode == 0)
{
SetWindowPos(NULL,0,0,GetBitmapWidth(m_bmpMask), GetBitmapHeight(m_bmpMask),SWP_NOZORDER|SWP_NOMOVE);
}
}
}
/////////////////////////////////////////////////////////////////////////////
HRGN CxSkinButton::CreateRgnFromBitmap(HBITMAP hBmp, COLORREF color)
{
if (!hBmp) return NULL;
BITMAP bm;
GetObject( hBmp, sizeof(BITMAP), &bm ); // get bitmap attributes
CDC dcBmp;
dcBmp.CreateCompatibleDC(GetDC()); //Creates a memory device context for the bitmap
dcBmp.SelectObject(hBmp); //selects the bitmap in the device context
const DWORD RDHDR = sizeof(RGNDATAHEADER);
const DWORD MAXBUF = 40; // size of one block in RECTs
LPRECT pRects;
DWORD cBlocks = 0; // number of allocated blocks
INT i, j; // current position in mask image
INT first = 0; // left position of current scan line
// where mask was found
bool wasfirst = FALSE; // set when if mask was found in current scan line
bool ismask; // set when current color is mask color
// allocate memory for region data
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -