📄 vxskinbutton.cpp
字号:
// VxSkinButton.cpp : implementation file
//
#include "stdafx.h"
#include "VxSkinButton.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CVxSkinButton
CVxSkinButton::CVxSkinButton()
{
m_DrawMode = 1; // normal drawing mode
m_FocusRectMargin = 0; // disable focus dotted rect
hClipRgn = NULL; // no clipping region
m_TextColor = GetSysColor(COLOR_BTNTEXT); // default button text color
m_button_down = m_tracking = m_Checked = false;
m_bMask = FALSE;
}
CVxSkinButton::~CVxSkinButton()
{
if (hClipRgn)
DeleteObject(hClipRgn);
// free clip region
}
BEGIN_MESSAGE_MAP(CVxSkinButton, CButton)
//{{AFX_MSG_MAP(CVxSkinButton)
ON_WM_ERASEBKGND()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDBLCLK()
ON_WM_KILLFOCUS()
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()
/////////////////////////////////////////////////////////////////////////////
// CVxSkinButton message handlers
void CVxSkinButton::PreSubclassWindow()
{
m_Style = GetButtonStyle(); // get specific BS_ styles
if ((m_Style & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX)
//||((m_Style & BS_CHECKBOX) == BS_CHECKBOX))
{
m_Style = BS_CHECKBOX;
}
else if ((m_Style & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON)
//||((m_Style & BS_RADIOBUTTON) == BS_RADIOBUTTON))
{
m_Style = BS_RADIOBUTTON;
}
else
{
m_Style = BS_PUSHBUTTON;
}
CButton::PreSubclassWindow();
ModifyStyle(0, BS_OWNERDRAW);
}
/////////////////////////////////////////////////////////////////////////////
// doesn't erase the button background
BOOL CVxSkinButton::OnEraseBkgnd(CDC *pDC)
{
return 1;
}
/////////////////////////////////////////////////////////////////////////////
void CVxSkinButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
ASSERT(lpDrawItemStruct);
//TRACE("* Captured: %08X\n", ::GetCapture());
// Check if the button state in not in inconsistent mode...
POINT mouse_position;
if ((m_button_down) && (::GetCapture() == m_hWnd) && (::GetCursorPos
(&mouse_position)))
{
if (::WindowFromPoint(mouse_position) == m_hWnd)
{
if ((GetState() &BST_PUSHED) != BST_PUSHED)
{
//TRACE("* Inconsistency up detected! Fixing.\n");
SetState(TRUE);
return;
}
}
else
{
if ((GetState() & BST_PUSHED) == BST_PUSHED)
{
//TRACE("* Inconsistency up detected! Fixing.\n");
SetState(FALSE);
return;
}
}
}
//TRACE("* Drawing: %08x\n", lpDrawItemStruct->itemState);
CString sCaption;
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_FocusRectMargin + 2, r.top, r.right - m_FocusRectMargin - 2,
r.bottom
};
GetWindowText(sCaption); // get button text
pDC->SetBkMode(TRANSPARENT);
// Select the correct skin
if (lpDrawItemStruct->itemState & ODS_DISABLED)
{
// DISABLED BUTTON
DrawBitmap(pDC, 3, r, m_DrawMode);
// if needed, draw the standard 3D rectangular border
if (m_Border)
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_Checked)
{
DrawBitmap(pDC, 2, r, m_DrawMode);
OffsetRect(&tr, 2, 1); // shift text
// if needed, draw the standard 3D rectangular border
if (m_Border)
pDC->DrawEdge(&r, EDGE_SUNKEN, BF_RECT);
}
else
{
// DEFAULT BUTTON
if (m_tracking)
{
DrawBitmap(pDC, 1, r, m_DrawMode);
}
else
{
if ((lpDrawItemStruct->itemState &ODS_FOCUS))
{
DrawBitmap(pDC, 0, r, m_DrawMode);
}
else
{
DrawBitmap(pDC, 0, r, m_DrawMode);
}
}
// if needed, draw the standard 3D rectangular border
if (m_Border)
{
pDC->DrawEdge(&r, EDGE_RAISED, BF_RECT);
}
}
// paint the focus rect
if ((lpDrawItemStruct->itemState & ODS_FOCUS) && (m_FocusRectMargin > 0))
{
r.left += m_FocusRectMargin;
r.top += m_FocusRectMargin;
r.right -= m_FocusRectMargin;
r.bottom -= m_FocusRectMargin;
DrawFocusRect(lpDrawItemStruct->hDC, &r);
}
// paint the enabled button text
pDC->SetTextColor(m_TextColor);
pDC->DrawText(sCaption, &tr, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
}
}
/////////////////////////////////////////////////////////////////////////////
int CVxSkinButton::GetBitmapWidth(HBITMAP hBitmap)
{
BITMAP bm;
GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm);
return bm.bmWidth;
}
/////////////////////////////////////////////////////////////////////////////
int CVxSkinButton::GetBitmapHeight(HBITMAP hBitmap)
{
BITMAP bm;
GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm);
return bm.bmHeight;
}
/////////////////////////////////////////////////////////////////////////////
void CVxSkinButton::DrawBitmap(CDC *dc, int nState, RECT r, int DrawMode)
{
int cx = r.right - r.left;
int cy = r.bottom - r.top;
cx = m_ButtonSize.cx;
cy = m_ButtonSize.cy;
if (m_bMask)
{
CDC dcBmp;
dcBmp.CreateCompatibleDC(dc);
dcBmp.SelectObject(m_bImage);
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, m_ButtonSize.cx
*nState, 0, SRCINVERT);
hdcMem.BitBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx *4, 0,
SRCAND);
hdcMem.BitBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
*nState, 0, SRCINVERT);
}
else
{
hdcMem.StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
*nState, 0, m_ButtonSize.cx, m_ButtonSize.cy, SRCINVERT);
hdcMem.StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx *4,
0, m_ButtonSize.cx, m_ButtonSize.cy, SRCAND);
hdcMem.StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
*nState, 0, m_ButtonSize.cx, m_ButtonSize.cy, SRCINVERT);
}
dc->BitBlt(r.left, r.top, cx, cy, &hdcMem, 0, 0, SRCCOPY);
hdcMem.DeleteDC();
hBitmap.DeleteObject();
}
else
{
CDC dcBmp;
dcBmp.CreateCompatibleDC(dc);
dcBmp.SelectObject(m_bImage);
if (!DrawMode)
{
dc->BitBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx *nState,
0, SRCCOPY);
}
else
{
dc->StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
*nState, 0, m_ButtonSize.cx, m_ButtonSize.cy, SRCCOPY);
}
DeleteDC(dcBmp);
}
}
/////////////////////////////////////////////////////////////////////////////
void CVxSkinButton::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 CVxSkinButton::SetSkin(UINT nBitmap, short drawmode, short border, short
margin, BOOL bMask)
{
m_bImage.DeleteObject(); // free previous allocated bitmap
m_bImage.LoadBitmap(nBitmap);
m_DrawMode = max(0, min(drawmode, 2));
m_Border = border;
m_FocusRectMargin = max(0, margin);
m_bMask = bMask;
if (!m_bMask)
{
m_ButtonSize.cx = GetBitmapWidth(m_bImage) / 4;
//m_ButtonSize.cx = GetBitmapWidth(m_bImage);
m_ButtonSize.cy = GetBitmapHeight(m_bImage);
}
else
{
m_ButtonSize.cx = GetBitmapWidth(m_bImage) / 5;
m_ButtonSize.cy = GetBitmapHeight(m_bImage);
}
SetWindowPos(&wndTop, 0, 0, m_ButtonSize.cx, m_ButtonSize.cy, SWP_NOMOVE |
SWP_NOZORDER);
}
/////////////////////////////////////////////////////////////////////////////
HRGN CVxSkinButton::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
// (i.e. MAXBUF * sizeof(RECT) in bytes)
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
RGNDATAHEADER *pRgnData = (RGNDATAHEADER*)new BYTE[RDHDR + ++cBlocks
*MAXBUF * sizeof(RECT)];
memset(pRgnData, 0, RDHDR + cBlocks * MAXBUF * sizeof(RECT));
// fill it by default
pRgnData->dwSize = RDHDR;
pRgnData->iType = RDH_RECTANGLES;
pRgnData->nCount = 0;
for (i = 0; i < bm.bmHeight; i++)
{
for (j = 0; j < bm.bmWidth; j++)
{
// get color
ismask = (dcBmp.GetPixel(j, bm.bmHeight - i - 1) != color);
// place part of scan line as RECT region if transparent color found after mask color or
// mask color found at the end of mask image
if (wasfirst && ((ismask && (j == (bm.bmWidth - 1))) || (ismask ^
(j < bm.bmWidth))))
{
// get offset to RECT array if RGNDATA buffer
pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
// save current RECT
pRects[pRgnData->nCount++] = CRect(first, bm.bmHeight - i - 1,
j + (j == (bm.bmWidth - 1)), bm.bmHeight - i);
// if buffer full reallocate it
if (pRgnData->nCount >= cBlocks *MAXBUF)
{
LPBYTE pRgnDataNew = new BYTE[RDHDR + ++cBlocks *MAXBUF *
sizeof(RECT)];
memcpy(pRgnDataNew, pRgnData, RDHDR + (cBlocks - 1) *MAXBUF
* sizeof(RECT));
delete pRgnData;
pRgnData = (RGNDATAHEADER*)pRgnDataNew;
}
wasfirst = false;
}
else if (!wasfirst && ismask)
// set wasfirst when mask is found
{
first = j;
wasfirst = true;
}
}
}
dcBmp.DeleteDC(); //release the bitmap
// create region
/* Under WinNT the ExtCreateRegion returns NULL (by Fable@aramszu.net) */
//HRGN hRgn = ExtCreateRegion(NULL, RDHDR + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData);
/* ExtCreateRegion replacement { */
HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
ASSERT(hRgn != NULL);
pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
for (i = 0; i < (int)pRgnData->nCount; i++)
{
HRGN hr = CreateRectRgn(pRects[i].left, pRects[i].top, pRects[i].right,
pRects[i].bottom);
VERIFY(CombineRgn(hRgn, hRgn, hr, RGN_OR) != ERROR);
if (hr)
DeleteObject(hr);
}
ASSERT(hRgn != NULL);
/* } ExtCreateRegion replacement */
delete pRgnData;
return hRgn;
}
/////////////////////////////////////////////////////////////////////////////
COLORREF CVxSkinButton::SetTextColor(COLORREF new_color)
{
COLORREF tmp_color = m_TextColor;
m_TextColor = new_color;
return tmp_color; //returns the previous color
}
/////////////////////////////////////////////////////////////////////////////
/*void CVxSkinButton::SetToolTipText(CString s)
{
if (m_tooltip.m_hWnd == NULL)
{
if (m_tooltip.Create(this)) // first assignment
{
if (m_tooltip.AddTool(this, (LPCTSTR)s))
{
m_tooltip.Activate(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -