class CMySphereButtonApp : public CWinApp { public: CMySphereButtonApp(); // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMySphereButtonApp) public: virtual BOOL InitInstance(); //}}AFX_VIRTUAL // Implementation //{{AFX_MSG(CMySphereButtonApp) //}}AFX_MSG DECLARE_MESSAGE_MAP() };
// UniButton.cpp : implementation file // #include "stdafx.h" #include "MySphereButton.h" #include "UniButton.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CUniButton CUniButton::CUniButton() { m_nColor = GetSysColor(COLOR_BTNFACE); m_sColor = m_nColor; m_hColor = m_nColor; m_dColor = m_nColor; m_nBorder = 1; m_lfEscapement = 0; m_pNormal = NULL; m_pSelected = NULL; m_pHover = NULL; m_pDisabled = NULL; m_hRgn = 0; m_bHover = false; m_bCapture = false; m_bMouseDown = false; m_bNeedBitmaps = true; } CUniButton::~CUniButton() { delete m_pNormal; delete m_pSelected; delete m_pHover; delete m_pDisabled; DeleteObject(m_hRgn); } BEGIN_MESSAGE_MAP(CUniButton, CButton) //{{AFX_MSG_MAP(CUniButton) ON_WM_ERASEBKGND() ON_WM_MOUSEMOVE() ON_WM_CREATE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CUniButton message handlers BOOL CUniButton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID) { // store region in member variable DeleteObject(m_hRgn); m_hRgn = CreateRectRgn(0, 0, 31, 31); CRect box(0, 0, 0, 0); if (m_hRgn != 0) CombineRgn(m_hRgn, hRgn, 0, RGN_COPY); // make sure that region bounding rect is located in (0, 0) GetRgnBox(m_hRgn, &box); OffsetRgn(m_hRgn, -box.left, -box.top); GetRgnBox(m_hRgn, &box); // update position of region center for caption output m_CenterPoint = CPoint(box.left + box.Width() /2 , box.top + box.Height() /2); box.OffsetRect(point); return CButton::Create(lpszCaption, dwStyle, box, pParentWnd, nID); } BOOL CUniButton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID, COLORREF color) { m_sColor = color; m_hColor = color; // call another constructor return Create(lpszCaption, dwStyle, point, hRgn, pParentWnd, nID); } BOOL CUniButton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID, UINT nBorder, LONG lfEscapement, COLORREF nColor, COLORREF sColor, COLORREF hColor, COLORREF dColor) { m_lfEscapement = lfEscapement; return Create(lpszCaption, dwStyle, point, hRgn, pParentWnd, nID, nBorder, nColor, sColor, hColor, dColor); } BOOL CUniButton::Create(LPCTSTR lpszCaption, DWORD dwStyle, const CPoint point, const HRGN hRgn, CWnd* pParentWnd, UINT nID, UINT nBorder, COLORREF nColor, COLORREF sColor, COLORREF hColor, COLORREF dColor) { // change default colors m_nBorder = nBorder; m_nColor = nColor; m_sColor = sColor; m_hColor = hColor; m_dColor = dColor; // call another constructor return Create(lpszCaption, dwStyle, point, hRgn, pParentWnd, nID); } void CUniButton::PreSubclassWindow() { // change window style to allow owner draw ModifyStyle(0, BS_OWNERDRAW | BS_PUSHBUTTON); CButton::PreSubclassWindow(); } int CUniButton::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CButton::OnCreate(lpCreateStruct) == -1) return -1; // assign new region to a window m_bNeedBitmaps = true; SetWindowRgn(m_hRgn, true); return 0; } void CUniButton::OnLButtonDown(UINT nFlags, CPoint point) { // record that mouse is down m_bMouseDown = true; if (!m_bCapture) { SetCapture(); m_bCapture = true; } CButton::OnLButtonDown(nFlags, point); } void CUniButton::OnLButtonUp(UINT nFlags, CPoint point) { // record that mouse is released CButton::OnLButtonUp(nFlags, point); m_bMouseDown = false; if (m_bCapture) { ReleaseCapture(); m_bCapture = false; } CheckHover(point); } void CUniButton::OnMouseMove(UINT nFlags, CPoint point) { // Test if mouse is above the button. if (!m_bMouseDown) CheckHover(point); CButton::OnMouseMove(nFlags, point); } void CUniButton::CheckHover(CPoint point) { if (HitTest(point)) { if (!m_bCapture) { SetCapture(); m_bCapture = true; } if (!m_bHover) { m_bHover = true; RedrawWindow(); } } else { if (m_bCapture) { ReleaseCapture(); m_bCapture = false; } m_bHover = false; RedrawWindow(); } } LRESULT CUniButton::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) { // I have noticed that default windows buttons can be clicked very quickly. // Double or single click both result in a button being pushed down. // For owner drawn buttons this is not the case. Double click does // not push button down. Here is a solution for the problem: // double click message is substituted for single click. if (message == WM_LBUTTONDBLCLK) message = WM_LBUTTONDOWN; return CButton::DefWindowProc(message, wParam, lParam); } BOOL CUniButton::HitTest(CPoint point) { BOOL result = false; // Obtain handle to window region. HRGN hRgn = CreateRectRgn(0, 0, 0, 0); GetWindowRgn(hRgn); CRect rgnRect; GetRgnBox(hRgn, &rgnRect); // First check if point is in region bounding rect. // Then check if point is in the region in adition to being in the bouding rect. result = PtInRect(&rgnRect, point) && PtInRegion(hRgn, point.x, point.y); // Clean up and exit. DeleteObject(hRgn); return result; } BOOL CUniButton::OnEraseBkgnd(CDC* pDC) { // do not erase background return 1; } //////////////////////// DRAWING ROUTINES //////////////////////////// void CUniButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // prepare DC CDC* pDC = CDC::FromHandle(lpDrawItemStruct -> hDC); CRect rect; GetClientRect(rect); // prepare bitmaps they need to be prepared if (m_bNeedBitmaps) PrepareStateBitmaps(pDC, &rect); // draw button to the screen DrawButton(pDC, &rect, lpDrawItemStruct -> itemState); } void CUniButton::PrepareStateBitmaps(CDC * pDC, CRect * pRect) { // prepare memory DC CDC * pMemDC; pMemDC = new CDC; pMemDC -> CreateCompatibleDC(pDC); // prepare bitmaps for all button states and for the mask PrepareNormalState(pDC, pMemDC, pRect); PrepareSelectedState(pDC, pMemDC, pRect); PrepareHoverState(pDC, pMemDC, pRect); PrepareDisabledState(pDC, pMemDC, pRect); // clean up delete pMemDC; m_bNeedBitmaps = false; } void CUniButton::PrepareNormalState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_NORMAL state bitmap delete m_pNormal; m_pNormal = new CBitmap; PaintRgn(pDC, pMemDC, m_pNormal, m_nColor, pRect, true, false); } void CUniButton::PrepareSelectedState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_SELECTED state bitmap delete m_pSelected; m_pSelected = new CBitmap; PaintRgn(pDC, pMemDC, m_pSelected, m_sColor, pRect, true, true); } void CUniButton::PrepareHoverState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_HOVER state bitmap delete m_pHover; m_pHover = new CBitmap; PaintRgn(pDC, pMemDC, m_pHover, m_hColor, pRect, true, false); } void CUniButton::PrepareDisabledState(CDC * pDC, CDC * pMemDC, CRect * pRect) { // prepare MYBS_DISABLED state bitmap delete m_pDisabled; m_pDisabled = new CBitmap; PaintRgn(pDC, pMemDC, m_pDisabled, m_dColor, pRect, false, false); } void CUniButton::PaintRgn(CDC * pDC, CDC * pMemDC, CBitmap * pBitmap, COLORREF color, CRect * pRect, BOOL bEnabled, BOOL bSunken) { // create bitmap pBitmap -> CreateCompatibleBitmap(pDC, pRect -> Width(), pRect -> Height()); CBitmap * pOldBitmap = pMemDC -> SelectObject(pBitmap); // prepare region HRGN hRgn = CreateRectRgn(0, 0, 0, 0); GetWindowRgn(hRgn); // fill rect a with transparent color and fill rgn HBRUSH hBrush = CreateSolidBrush(color); pMemDC -> FillSolidRect(pRect, RGB(0, 0, 0)); FillRgn(pMemDC -> GetSafeHdc(), hRgn, hBrush); DeleteObject(hBrush); // draw 3D border and text DrawButtonCaption(pMemDC -> GetSafeHdc(), pRect, bEnabled, bSunken); FrameRgn3D(pMemDC -> GetSafeHdc(), hRgn, bSunken); // clean up DeleteObject(hRgn); pMemDC -> SelectObject(pOldBitmap); } void CUniButton::DrawButtonCaption(HDC hDC, CRect * pRect, BOOL bEnabled, BOOL bSunken) { // select parent font int nOldMode = SetBkMode(hDC, TRANSPARENT); CString text; GetWindowText(text); LOGFONT lf; GetParent() -> GetFont() -> GetLogFont(&lf); HFONT hFont = CreateFontIndirect(&lf); HFONT hOldFont = (HFONT) SelectObject(hDC, hFont); // determine point where to output text TEXTMETRIC tm; GetTextMetrics(hDC, &tm); CPoint p = CPoint(m_CenterPoint.x, m_CenterPoint.y + tm.tmHeight/ 2); if (bSunken) p.Offset(m_nBorder, m_nBorder); // draw button caption depending upon button state if (bEnabled) { SetTextColor(hDC, GetSysColor(COLOR_BTNTEXT)); SetTextAlign(hDC, TA_CENTER | TA_BOTTOM); TextOut(hDC, p.x, p.y, text, text.GetLength()); } else { SetTextColor(hDC, GetSysColor(COLOR_3DHILIGHT)); TextOut(hDC, p.x + 1, p.y + 1, text, text.GetLength()); SetTextColor(hDC, GetSysColor(COLOR_3DSHADOW)); TextOut(hDC, p.x, p.y, text, text.GetLength()); } SelectObject(hDC, hOldFont); DeleteObject(hFont); SetBkMode(hDC, nOldMode); } void CUniButton::FrameRgn3D(HDC hDC, const HRGN hRgn, BOOL bSunken) { // we need two differenr regions to keep base region and border region HBRUSH hBrush; HRGN hBaseRgn = CreateRectRgn(0, 0, 0, 0); COLORREF ltOuter, ltInner, rbOuter, rbInner; // colors of inner and outer shadow for top-left and right-bottom corners // decide on color scheme if (!bSunken) { ltOuter = GetSysColor(COLOR_3DLIGHT); ltInner = GetSysColor(COLOR_3DHILIGHT); rbOuter = GetSysColor(COLOR_3DDKSHADOW); rbInner = GetSysColor(COLOR_3DSHADOW); } else { rbInner = GetSysColor(COLOR_3DLIGHT); rbOuter = GetSysColor(COLOR_3DHILIGHT); ltInner = GetSysColor(COLOR_3DDKSHADOW); ltOuter = GetSysColor(COLOR_3DSHADOW); } // offset highlight and shadow regions // substract them from the base region switch (m_nBorder) { case 2: CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, 2, 2); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(ltInner); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, -2, -2); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(rbInner); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, 1, 1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(ltOuter); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, -1, -1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(rbOuter); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); break; default: CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, 1, 1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(ltInner); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); CombineRgn(hBaseRgn, hRgn, 0, RGN_COPY); OffsetRgn(hBaseRgn, -1, -1); CombineRgn(hBaseRgn, hRgn, hBaseRgn, RGN_DIFF); hBrush = CreateSolidBrush(rbOuter); FillRgn(hDC, hBaseRgn, hBrush); DeleteObject(hBrush); break; } // clean up regions DeleteObject(hBaseRgn); } void CUniButton::DrawButton(CDC * pDC, CRect * pRect, UINT state) { // create memory DC CDC * pMemDC = new CDC; pMemDC -> CreateCompatibleDC(pDC); CBitmap * pOldBitmap; // get region HRGN hRgn = CreateRectRgn(0, 0, 0, 0); GetWindowRgn(hRgn); // select bitmap to paint depending upon button state if (state & ODS_DISABLED) pOldBitmap = pMemDC -> SelectObject(m_pDisabled); else { if (state & ODS_SELECTED) pOldBitmap = pMemDC -> SelectObject(m_pSelected); else { if (m_bHover) pOldBitmap = pMemDC -> SelectObject(m_pHover); else pOldBitmap = pMemDC -> SelectObject(m_pNormal); } } // paint using region for clipping ::SelectClipRgn(pDC -> GetSafeHdc(), hRgn); pDC -> BitBlt(0, 0, pRect -> Width(), pRect -> Height(), pMemDC, 0, 0, SRCCOPY); ::SelectClipRgn(pDC -> GetSafeHdc(), NULL); // clean up DeleteObject(hRgn); pMemDC -> SelectObject(pOldBitmap); delete pMemDC; } void CUniButton::RgnPixelWork(CDC * pDC, CRgn * pRgn) { // get size of data composing region int size = pRgn -> GetRegionData(NULL, 0); HANDLE hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size); RGNDATA * pData = (RGNDATA *)GlobalLock(hData); // retrieve region data int res = pRgn -> GetRegionData(pData, size); RECT * pRect = (RECT *) pData -> Buffer; // now we know how region is represented and we are able to manipulate it as we like for (DWORD i = 0; i < pData -> rdh.nCount; i++) { RECT rect = *(pRect + i); for (int x = rect.left; x < rect.right; x++) for (int y = rect.top; y < rect.bottom; y++) { // use SetPixel(x, y, color) to do pixel work } } // free region data GlobalUnlock(hData); GlobalFree(hData); }
下载文件