#include "stdafx.h" #include "BlButton.h" #define BADGE_HIDE 0 #define BADGE_DOT 1 #define BADGE_NUMBER 2 #define BADGE_DOT_WIDTH 12 #define BADGE_NUMBER_WIDTH 20 CBlButton::CBlButton() { m_nState = BS_NORMAL; m_crFrame[BS_NORMAL] = RGB(225, 225, 225); m_crFrame[BS_HOVER] = RGB(0, 120, 215); m_crFrame[BS_PRESS] = RGB(0, 84, 153); m_crFrame[BS_FOCUS] = RGB(0, 120, 215); m_crFrame[BS_DISABLE] = RGB(191, 191, 191); m_crBkgnd[BS_NORMAL] = RGB(225, 225, 225); m_crBkgnd[BS_HOVER] = RGB(229, 241, 251); m_crBkgnd[BS_PRESS] = RGB(204, 228, 247); m_crBkgnd[BS_FOCUS] = RGB(225, 225, 225); m_crBkgnd[BS_DISABLE] = RGB(204, 204, 204); m_crText[BS_NORMAL] = RGB(0, 0, 0); m_crText[BS_HOVER] = RGB(0, 0, 0); m_crText[BS_PRESS] = RGB(0, 0, 0); m_crText[BS_FOCUS] = RGB(0, 0, 0); m_crText[BS_DISABLE] = RGB(131, 131, 131); m_bHover = FALSE; m_bSelected = FALSE; m_bTracking = FALSE; memset(&m_badge, 0, sizeof(BADGE)); m_nRoundWidth = 0; m_hMenu = nullptr; m_hIcon[0] = nullptr; m_hIcon[1] = nullptr; m_nIconWidth = 0; m_nFlashState = 0; } CBlButton::~CBlButton() { } void CBlButton::SetFrameColor(int index, COLORREF color) { if (BS_NORMAL <= index && index <= BS_DISABLE) { m_crFrame[index] = color; } } void CBlButton::SetFrameColor(COLORREF color) { m_crFrame[BS_NORMAL] = color; m_crFrame[BS_HOVER] = color; m_crFrame[BS_PRESS] = color; m_crFrame[BS_FOCUS] = color; Invalidate(); } void CBlButton::SetRoundWidth(int width) { m_nRoundWidth = width; } void CBlButton::SetBkgndColor(int index, COLORREF color) { if (BS_NORMAL <= index && index <= BS_DISABLE) { m_crBkgnd[index] = color; } } void CBlButton::SetTextColor(int index, COLORREF color) { if (BS_NORMAL <= index && index <= BS_DISABLE) { m_crText[index] = color; } } void CBlButton::SetFaceColor(COLORREF color) { m_crBkgnd[BS_NORMAL] = color; m_crBkgnd[BS_HOVER] = color; m_crBkgnd[BS_PRESS] = color; m_crBkgnd[BS_FOCUS] = color; Invalidate(); } void CBlButton::SetTextColor(COLORREF color) { m_crText[BS_NORMAL] = color; m_crText[BS_HOVER] = color; m_crText[BS_PRESS] = color; m_crText[BS_FOCUS] = color; Invalidate(); } void CBlButton::SetBadgeNumber(int number) { m_badge.badgeBackground = RGB(255, 0, 0); m_badge.badgeForeground = RGB(255, 255, 255); m_badge.type = number > 0 ? BADGE_NUMBER : BADGE_HIDE; m_badge.number = number; Invalidate(); } void CBlButton::ShowDotBadge(BOOL bShow, COLORREF color) { m_badge.badgeBackground = color; m_badge.type = bShow ? BADGE_DOT : BADGE_HIDE; Invalidate(); } void CBlButton::SetBkgndBmp(const char* pszBmpFile) { m_strBkgndBmp = pszBmpFile; } void CBlButton::SetMenu(HMENU hMenu) { m_hMenu = hMenu; } void CBlButton::SetCurrentMenuItem(UINT nPosition) { char szTxt[256]; GetMenuString(::GetSubMenu(m_hMenu, 0), nPosition, szTxt, 256, MF_BYPOSITION); SetWindowText(szTxt); } HMENU CBlButton::GetMenu() { return m_hMenu; } void CBlButton::SetIcon(HICON hIcon, HICON hIconGray, int width) { m_hIcon[0] = hIcon; m_hIcon[1] = hIconGray; m_nIconWidth = width; } void CBlButton::Flash(int ms) { m_nFlashState = 1; SetTimer(1, ms, nullptr); } void CBlButton::StopFlash() { m_nFlashState = 0; KillTimer(1); Invalidate(); } BOOL CBlButton::IsFlash() { return m_nFlashState != 0; } void CBlButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { HDC hDC = lpDrawItemStruct->hDC; RECT rcClient; GetClientRect(&rcClient); // ±ß¿ò+±³¾° int state = GetDrawState(); if (m_nFlashState != 0) { if (state != BS_DISABLE) { state = m_nFlashState == 1 ? BS_NORMAL : BS_PRESS; } } HBRUSH hBrush = CreateSolidBrush(m_crBkgnd[state]); HPEN hPen = CreatePen(PS_SOLID, state == BS_FOCUS ? 2 : 1, m_crFrame[state]); HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen); HPEN hOldBrush = (HPEN)::SelectObject(hDC, hBrush); ::RoundRect(hDC, state == BS_FOCUS ? rcClient.left + 1 : rcClient.left, state == BS_FOCUS ? rcClient.top + 1 : rcClient.top, rcClient.right, rcClient.bottom, m_nRoundWidth, m_nRoundWidth); ::SelectObject(hDC, hOldPen); ::SelectObject(hDC, hOldBrush); ::DeleteObject(hBrush); ::DeleteObject(hPen); // Ìùͼ CustomBitBlt(hDC, &rcClient, m_strBkgndBmp, state, 5, 2, 2, 2, 2, RGB(255,0,255)); // »ñµÃÎı¾ char szText[64]; int nTextLen = GetWindowText(szText, 64); // ͼ±ê RECT rcText = rcClient; HICON hIcon = this->IsWindowEnabled() ? m_hIcon[0] : m_hIcon[01]; if (hIcon != nullptr) { int xIcon = (rcClient.right - rcClient.top - m_nIconWidth) / 2; if (m_hMenu != nullptr) xIcon -= 10; int yIcon = (rcClient.bottom - rcClient.top - m_nIconWidth) / 2; if (nTextLen != 0) { yIcon -= 8; } DrawIconEx(hDC, xIcon, yIcon, hIcon, m_nIconWidth, m_nIconWidth, 0, 0, DI_NORMAL); rcText.top = yIcon + m_nIconWidth + 2; } // Îı¾ HFONT hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); CFont* pFont = GetFont(); if (pFont != nullptr) { hFont = (HFONT)pFont->GetSafeHandle(); } HFONT hOldFont = (HFONT)::SelectObject(hDC, hFont); ::SetBkMode(hDC, TRANSPARENT); ::SetTextColor(hDC, m_crText[state]); if ((BS_MULTILINE & GetStyle()) == BS_MULTILINE) { CRect rcBound; int height = DrawTextA(hDC, szText, (int)strlen(szText), &rcBound, DT_CENTER | DT_CALCRECT | DT_EDITCONTROL); rcText.top = rcBound.top + (rcClient.bottom - rcClient.top - height) / 2; rcText.bottom = rcText.top + height; DrawTextA(hDC, szText, (int)strlen(szText), &rcText, DT_CENTER | DT_EDITCONTROL); } else { if (m_hMenu != nullptr) { rcText.right -= (10); } DrawTextA(hDC, szText, (int)strlen(szText), &rcText, DT_VCENTER | DT_CENTER | DT_SINGLELINE | DT_END_ELLIPSIS); } ::SelectObject(hDC, hOldFont); // ÊÇ·ñÓÐСԲµã if (m_badge.type == BADGE_DOT) { Gdiplus::Graphics graphics(hDC); graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); Gdiplus::SolidBrush brush(Gdiplus::Color(GetRValue(m_badge.badgeBackground), GetGValue(m_badge.badgeBackground), GetBValue(m_badge.badgeBackground))); int x = rcClient.right - 8 - BADGE_DOT_WIDTH; int y = rcClient.top + 8; graphics.FillEllipse(&brush, x, y, BADGE_DOT_WIDTH, BADGE_DOT_WIDTH); } else if (m_badge.type == BADGE_NUMBER) { Gdiplus::Graphics graphics(hDC); graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias); Gdiplus::SolidBrush brush(Gdiplus::Color(GetRValue(m_badge.badgeBackground), GetGValue(m_badge.badgeBackground), GetBValue(m_badge.badgeBackground))); int x = rcClient.right - 8 - BADGE_NUMBER_WIDTH; int y = rcClient.top + 8; graphics.FillEllipse(&brush, x, y, BADGE_NUMBER_WIDTH, BADGE_NUMBER_WIDTH); RECT rcBadge; rcBadge.left = x; rcBadge.right = rcBadge.left + BADGE_NUMBER_WIDTH; rcBadge.top = y; rcBadge.bottom = rcBadge.top + BADGE_NUMBER_WIDTH; ::SetTextColor(hDC, m_badge.badgeForeground); char szBuffer[32]; sprintf_s(szBuffer, 32, "%d%s", min(m_badge.number, 9), m_badge.number > 9 ? "+" : ""); DrawText(hDC, szBuffer, (int)strlen(szBuffer), &rcBadge, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } // ²Ëµ¥ÏîСÈý½Ç if (m_hMenu != nullptr) { HPEN hPenDrop = CreatePen(PS_SOLID, 1, m_crText[state]); HBRUSH hbrDrop = CreateSolidBrush(m_crText[state]); HBRUSH hOldBrush = (HBRUSH)::SelectObject(hDC, hbrDrop); HPEN hOldPen = (HPEN)::SelectObject(hDC, hPenDrop); POINT pt[3]; pt[0].x = rcClient.right - 20; pt[0].y = rcClient.top + (rcClient.bottom - rcClient.top - 5) / 2; pt[1].x = pt[0].x + 10; pt[1].y = pt[0].y; pt[2].x = pt[0].x + (pt[1].x - pt[0].x) / 2; pt[2].y = pt[0].y + 5; ::Polygon(hDC, pt, 3); ::SelectObject(hDC, hOldBrush); ::SelectObject(hDC, hOldPen); ::DeleteObject(hbrDrop); // ÕýÈ·ÊÍ·ÅСÈý½ÇʹÓõĻ­Ë¢ ::DeleteObject(hPenDrop); // ÕýÈ·ÊÍ·ÅСÈý½ÇµÄ±Ê } } int CBlButton::GetDrawState() { if (!IsWindowEnabled()) { return BS_DISABLE; } //if (GetFocus() == this) { // return BS_FOCUS; //} return m_nState; } void CBlButton::PreSubclassWindow() { m_bHover = false; m_bSelected = false; m_bTracking = FALSE; ModifyStyle(0, BS_OWNERDRAW); CButton::PreSubclassWindow(); } BEGIN_MESSAGE_MAP(CBlButton, CButton) ON_WM_MOUSEMOVE() ON_WM_MOUSEHOVER() ON_WM_MOUSELEAVE() ON_WM_LBUTTONDOWN() ON_CONTROL_REFLECT_EX(BN_CLICKED, &CBlButton::OnBnClicked) ON_WM_LBUTTONUP() ON_WM_TIMER() END_MESSAGE_MAP() void CBlButton::OnMouseMove(UINT nFlags, CPoint point) { if (!m_bTracking) { TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.dwFlags = TME_HOVER | TME_LEAVE; // ·¢ËÍWM_MOUSEHOVERºÍWM_MOUSELEAVE tme.hwndTrack = m_hWnd; // Ö¸¶¨Òª×·×ٵĴ°¿Ú tme.dwHoverTime = 10; // Êó±êÔÚ°´Å¥ÉÏÍ£Áô³¬¹ý10ms£¬²ÅÈÏΪ״̬ΪHOVER m_bTracking = _TrackMouseEvent(&tme); // ¿ªÆôWindowsµÄWM_MOUSELEAVEWM_MOUSEHOVERʼþÖ§³Ö } CButton::OnMouseMove(nFlags, point); } void CBlButton::OnMouseHover(UINT nFlags, CPoint point) { m_bHover = true; m_nState = BS_HOVER; InvalidateRect(NULL); return; // CButton::OnMouseHover(nFlags, point); } void CBlButton::OnMouseLeave() { m_bHover = false; m_bTracking = FALSE; // ÈôÒѾ­À뿪£¬ÔòÍ£Ö¹×·×Ù m_nState = BS_NORMAL; InvalidateRect(NULL); CButton::OnMouseLeave(); } BOOL CBlButton::CustomBitBlt(HDC hDC, LPRECT lprc, CString& strBkgndBmp, int nFrame, int nAllFrame, int nB0, int nB1, int nB2, int nB3, COLORREF crTransparent) { // ÔØÈëBMP HBITMAP hBmpTemp = (HBITMAP)LoadImage(AfxGetInstanceHandle(), strBkgndBmp, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE); if (hBmpTemp == NULL) return FALSE; HDC hDCTemp = ::CreateCompatibleDC(hDC); ::SelectObject(hDCTemp, hBmpTemp); BITMAP bitmap; ::GetObject(hBmpTemp, sizeof(BITMAP), &bitmap); int nFrameWidth = bitmap.bmWidth / nAllFrame; // ÿ֡µÄ¿í int nFrameX = nFrameWidth*nFrame; // Ö¸¶¨Ö¡ÏàËØÆðµã // Èç¹û½Ç»ò±ßºñΪ0 if (nB0 == 0 && nB1 == 0 && nB2 == 0 && nB3 == 0) { ::TransparentBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top, hDCTemp, nFrameX, 0, nFrameWidth, bitmap.bmHeight, crTransparent); ::DeleteObject(hBmpTemp); ::DeleteDC(hDCTemp); return TRUE; } // ÆäËü int x = lprc->left + nB3; int y = lprc->top + nB0; ::TransparentBlt(hDC, x, y, lprc->right - lprc->left - (nB1 + nB3), lprc->bottom - lprc->top - (nB0 + nB2), hDCTemp, nFrameX + nB3, nB0, nFrameWidth - (nB1 + nB3), bitmap.bmHeight - (nB0 + nB2), crTransparent); x = lprc->left; y = lprc->top; ::TransparentBlt(hDC, x, y, nB3, nB0, hDCTemp, nFrameX + 0, 0, nB3, nB0, crTransparent); x += nB3; y = lprc->top; ::TransparentBlt(hDC, x, y, lprc->right - lprc->left - (nB1 + nB3), nB0, hDCTemp, nFrameX + nB3, 0, nFrameWidth - (nB1 + nB3), nB0, crTransparent); x = lprc->right - nB1; y = lprc->top; ::TransparentBlt(hDC, x, y, nB1, nB0, hDCTemp, nFrameX + nFrameWidth - nB1, 0, nB1, nB0, crTransparent); x = lprc->right - nB1; y = lprc->top + nB0; ::TransparentBlt(hDC, x, y, nB1, lprc->bottom - lprc->top - (nB0 + nB2), hDCTemp, nFrameX + nFrameWidth - nB1, nB0, nB1, bitmap.bmHeight - (nB0 + nB2), crTransparent); x = lprc->right - nB1; y = lprc->bottom - nB2; ::TransparentBlt(hDC, x, y, nB1, nB2, hDCTemp, nFrameX + nFrameWidth - nB1, bitmap.bmHeight - nB2, nB1, nB2, crTransparent); x = lprc->left + nB3; y = lprc->bottom - nB2; ::TransparentBlt(hDC, x, y, lprc->right - lprc->left - (nB1 + nB3), nB2, hDCTemp, nFrameX + nB3, bitmap.bmHeight - nB2, nFrameWidth - (nB1 + nB3), nB2, crTransparent); x = lprc->left; y = lprc->bottom - nB2; ::TransparentBlt(hDC, x, y, nB3, nB2, hDCTemp, nFrameX + 0, bitmap.bmHeight - nB2, nB3, nB2, crTransparent); x = lprc->left; y = lprc->top + nB0; ::TransparentBlt(hDC, x, y, nB3, lprc->bottom - lprc->top - (nB0 + nB2), hDCTemp, nFrameX + 0, nB0, nB3, bitmap.bmHeight - (nB0 + nB2), crTransparent); ::DeleteObject(hBmpTemp); ::DeleteDC(hDCTemp); return TRUE; } void CBlButton::OnLButtonDown(UINT nFlags, CPoint point) { m_nState = BS_PRESS; CButton::OnLButtonDown(nFlags, point); } void CBlButton::OnLButtonUp(UINT nFlags, CPoint point) { m_nState = BS_HOVER; CButton::OnLButtonUp(nFlags, point); } BOOL CBlButton::OnBnClicked() { if (m_hMenu != NULL) { RECT rect; GetWindowRect(&rect); int cmd = ::TrackPopupMenu(::GetSubMenu(m_hMenu, 0), TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, rect.left, rect.bottom, 0, m_hWnd, NULL); if (cmd > 0) { int position = cmd - GetMenuItemID(::GetSubMenu(m_hMenu, 0), 0); Notify((int)BLBUTTON_MENU_ITEM_CLICKED, position); } } return FALSE; } void CBlButton::Notify(int nCode, DWORD_PTR dwData, DWORD_PTR dwData1/* = 0*/, DWORD_PTR dwData2/* = 0*/) { CWnd* pParent; pParent = GetParent(); if (pParent != nullptr) { BLBUTTON_NMHDR blbNmhdr; blbNmhdr.nmhdr.code = nCode; blbNmhdr.nmhdr.idFrom = GetWindowLong(m_hWnd, GWL_ID); blbNmhdr.nmhdr.hwndFrom = m_hWnd; blbNmhdr.dwData = dwData; blbNmhdr.dwData1 = dwData1; blbNmhdr.dwData2 = dwData2; pParent->SendMessage(WM_NOTIFY, (WPARAM)blbNmhdr.nmhdr.idFrom, (LPARAM)&blbNmhdr); } } void CBlButton::OnTimer(UINT_PTR nIDEvent) { if (1 == nIDEvent) { m_nFlashState++; if (m_nFlashState > 2) m_nFlashState = 1; Invalidate(); } CButton::OnTimer(nIDEvent); }