使用白色作为透明色Mask创建不规则region
发几张图片(程序以bmp做例子,但是论坛不能传bmp)上来做个具体例子:
normal
down
focus
diable
mask
1 //Header File 2 3 #pragma once 4 5 6 // CRgnButton 7 8 #define WM_CXSHADE_RADIO WM_USER+0x100 9 #define ALLOC_UNIT 10010 11 class CRgnButton : public CButton12 {13 DECLARE_DYNAMIC(CRgnButton)14 15 public:16 CRgnButton();17 virtual ~CRgnButton();18 19 enum DRAW_MODE { DRAW_NORMAL, DRAW_STRETCH, DRAW_TILED };20 public:21 void SetToolTipText(const CString &strTip);22 COLORREF SetTextColor(COLORREF colorNew);23 void SetSkin(UINT normal, UINT down, UINT over=0, UINT disabled=0, UINT focus=0,UINT mask=0,24 DRAW_MODE drawmode=DRAW_NORMAL,short border=0,short margin=0);25 public:26 virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);27 protected:28 virtual void PreSubclassWindow();29 30 afx_msg BOOL OnEraseBkgnd(CDC* pDC);31 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);32 afx_msg void OnLButtonUp(UINT nFlags, CPoint point);33 afx_msg void OnMouseMove(UINT nFlags, CPoint point);34 afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);35 afx_msg void OnKillFocus(CWnd* pNewWnd);36 afx_msg BOOL OnBnClicked();37 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);38 39 afx_msg HRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);40 afx_msg HRESULT OnRadioInfo(WPARAM wParam, LPARAM lParam);41 afx_msg HRESULT OnBMSetCheck(WPARAM wParam, LPARAM lParam);42 afx_msg HRESULT OnBMGetCheck(WPARAM wParam, LPARAM lParam);43 DECLARE_MESSAGE_MAP()44 45 protected:46 HRGN CreateRgnFromBitmap(CBitmap &bmp, COLORREF cTransColor);47 void FillWithBitmap(CDC* dc, CBitmap &bmp, RECT rc);48 void DrawBitmap(CDC* dc, CBitmap &bmp, RECT rc, DRAW_MODE DrawMode);49 int GetBitmapWidth (CBitmap *bmp);50 int GetBitmapHeight (CBitmap *bmp);51 void RelayEvent(UINT message, WPARAM wParam, LPARAM lParam);52 private:53 bool m_bCheck;54 DWORD m_Style;55 bool m_bTrack;56 bool m_bBtnDown;57 CToolTipCtrl m_Tooltip;58 CBitmap m_bNormal, m_bDown, m_bDisable, m_bMask, m_bOver, m_bFocus;59 short m_nFocusRectMargin;60 COLORREF m_cTextColor;61 HRGN m_hClipRgn;62 bool m_bHasBorder;63 DRAW_MODE m_DrawMode;64 65 BYTE MinByte(BYTE a, BYTE b) { return (0xff < (a + b) )? 0xff : (a + b); }66 };
1 //Source Code 2 // RgnButton.cpp : 实现文件 3 // 4 5 #include "stdafx.h" 6 #include "RegionWnd.h" 7 #include "RgnButton.h" 8 9 10 // CRgnButton 11 12 IMPLEMENT_DYNAMIC(CRgnButton, CButton) 13 14 CRgnButton::CRgnButton() 15 : m_bCheck(false), m_bBtnDown(false), m_bTrack(false) 16 , m_DrawMode(DRAW_STRETCH) 17 , m_hClipRgn(NULL), m_nFocusRectMargin(0) 18 { 19 m_cTextColor = GetSysColor(COLOR_BTNTEXT); 20 } 21 22 CRgnButton::~CRgnButton() 23 { 24 if(m_hClipRgn) 25 DeleteObject(m_hClipRgn); 26 } 27 28 29 BEGIN_MESSAGE_MAP(CRgnButton, CButton) 30 ON_WM_ERASEBKGND() 31 ON_WM_LBUTTONDOWN() 32 ON_WM_LBUTTONUP() 33 ON_WM_MOUSEMOVE() 34 ON_WM_LBUTTONDBLCLK() 35 ON_WM_KILLFOCUS() 36 // ON_CONTROL_REFLECT_EX(BN_CLICKED, &CRgnButton::OnBnClicked) 37 ON_WM_KEYDOWN() 38 39 ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) 40 ON_MESSAGE(WM_CXSHADE_RADIO, OnRadioInfo) 41 ON_MESSAGE(BM_SETCHECK, OnBMSetCheck) 42 ON_MESSAGE(BM_GETCHECK, OnBMGetCheck) 43 END_MESSAGE_MAP() 44 45 46 47 // CRgnButton 消息处理程序 48 49 50 51 void CRgnButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 52 { 53 ASSERT(lpDrawItemStruct); 54 55 //Check if the button state is not in inconsistent mode... 56 POINT mouse_position; 57 if ( (m_bBtnDown) && (::GetCapture() == m_hWnd) && (::GetCursorPos(&mouse_position))) { 58 if (::WindowFromPoint(mouse_position) == m_hWnd){ 59 if ((GetState() & BST_PUSHED) != BST_PUSHED) { 60 SetState(TRUE); 61 return; 62 } 63 } else { 64 if ((GetState() & BST_PUSHED) == BST_PUSHED) { 65 SetState(FALSE); 66 return; 67 } 68 } 69 } 70 71 CString strCaption; 72 CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC); 73 CRect rc=lpDrawItemStruct->rcItem; 74 int cx = rc.Width(); 75 int cy = rc.Height(); 76 // get text box position 77 RECT tr={ rc.left + m_nFocusRectMargin +2, rc.top, rc.right - m_nFocusRectMargin -2, rc.bottom }; 78 79 GetWindowText(strCaption); // get button text 80 pDC->SetBkMode(TRANSPARENT); 81 82 // Select the correct skin 83 if (lpDrawItemStruct->itemState & ODS_DISABLED){ // DISABLED BUTTON 84 if(m_bDisable.m_hObject == NULL) 85 // no skin selected for disabled state -> standard button 86 pDC->FillSolidRect(&rc, GetSysColor(COLOR_BTNFACE)); 87 else // paint the skin 88 DrawBitmap(pDC, m_bDisable, rc, m_DrawMode); 89 // if needed, draw the standard 3D rectangular border 90 if (m_bHasBorder) 91 pDC->DrawEdge(&rc, EDGE_RAISED, BF_RECT); 92 // paint the etched button text 93 pDC->SetTextColor(GetSysColor(COLOR_3DHILIGHT)); 94 pDC->DrawText(strCaption, &tr, DT_SINGLELINE|DT_VCENTER|DT_CENTER); 95 pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT)); 96 OffsetRect(&tr, -1, -1); 97 pDC->DrawText(strCaption, &tr, DT_SINGLELINE|DT_VCENTER|DT_CENTER); 98 } else { // SELECTED (DOWN) BUTTON 99 if ( (lpDrawItemStruct->itemState & ODS_SELECTED) || m_bCheck ) {100 if(m_bDown.m_hObject==NULL) // no skin selected for selected state -> standard button101 pDC->FillSolidRect(&rc, GetSysColor(COLOR_BTNFACE));102 else { // paint the skin103 DrawBitmap(pDC, m_bDown, rc, m_DrawMode);104 }105 OffsetRect(&tr, 1, 1); //shift text106 // if needed, draw the standard 3D rectangular border107 if (m_bHasBorder) 108 pDC->DrawEdge(&rc, EDGE_SUNKEN, BF_RECT);109 } else { // DEFAULT BUTTON110 if(m_bNormal.m_hObject==NULL) // no skin selected for normal state -> standard button 111 {112 CString strRect;113 strRect.Format(L"Rect: %d, %d, %d, %d\n", rc.left, rc.top, rc.right, rc.bottom);114 OutputDebugString(strRect);115 pDC->FillSolidRect(&rc, GetSysColor(COLOR_BTNFACE));116 }117 else if ( (m_bTrack) && (m_bOver.m_hObject != NULL)) { // paint the skin118 DrawBitmap(pDC, m_bOver, rc, m_DrawMode);119 } else {120 if ((lpDrawItemStruct->itemState & ODS_FOCUS)&&(m_bFocus.m_hObject != NULL)) {121 DrawBitmap(pDC, m_bFocus, rc, m_DrawMode);122 } else {123 DrawBitmap(pDC, m_bNormal, rc, m_DrawMode);124 }125 }126 // if needed, draw the standard 3D rectangular border127 if (m_bHasBorder) 128 pDC->DrawEdge(&rc, EDGE_RAISED,BF_RECT);129 }130 // paint the focus rect131 if ((lpDrawItemStruct->itemState & ODS_FOCUS) && (m_nFocusRectMargin > 0)){132 rc.left += m_nFocusRectMargin ;133 rc.top += m_nFocusRectMargin ;134 rc.right -= m_nFocusRectMargin ;135 rc.bottom -= m_nFocusRectMargin ;136 DrawFocusRect (lpDrawItemStruct->hDC, &rc) ;137 }138 // paint the enabled button text139 pDC->SetTextColor(m_cTextColor);140 pDC->DrawText(strCaption,&tr,DT_SINGLELINE|DT_VCENTER|DT_CENTER);141 }142 }143 144 int CRgnButton::GetBitmapWidth(CBitmap *bmp)145 {146 if(!bmp)147 return -1;148 149 BITMAP bm;150 bmp->GetBitmap(&bm);151 152 return bm.bmWidth;153 }154 155 int CRgnButton::GetBitmapHeight(CBitmap *bmp)156 {157 if(!bmp)158 return -1;159 160 BITMAP bm;161 bmp->GetBitmap(&bm);162 163 return bm.bmHeight;164 }165 166 void CRgnButton::DrawBitmap(CDC* dc, CBitmap &bmp, RECT rc, DRAW_MODE DrawMode)167 {168 if(DrawMode == DRAW_TILED){169 FillWithBitmap(dc, bmp, rc);170 return;171 }172 if(!bmp.GetSafeHandle()) 173 return; //safe check174 175 CRect cr = rc;176 int cx=cr.Width();177 int cy=cr.Height();178 CDC dcBmp,dcMask;179 dcBmp.CreateCompatibleDC(dc);180 dcBmp.SelectObject(bmp);181 182 if (m_bMask.m_hObject!=NULL){183 dcMask.CreateCompatibleDC(dc);184 dcMask.SelectObject(m_bMask);185 186 CDC dcMem;187 dcMem.CreateCompatibleDC(dc);188 CBitmap bmpMem;189 bmpMem.CreateCompatibleBitmap(dc,cx,cy);190 CBitmap *oldBmp = dcMem.SelectObject(&bmpMem);191 192 dcMem.BitBlt(cr.left, cr.top, cx, cy, dc, 0, 0, SRCCOPY);193 if(DrawMode == DRAW_NORMAL){194 dcMem.BitBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, SRCINVERT);195 dcMem.BitBlt(cr.left, cr.top, cx, cy, &dcMask, 0, 0, SRCAND);196 dcMem.BitBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, SRCINVERT);197 } else {198 int bx=GetBitmapWidth(&bmp);199 int by=GetBitmapHeight(&bmp);200 dcMem.StretchBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, bx, by, SRCINVERT);201 dcMem.StretchBlt(cr.left, cr.top, cx, cy, &dcMask, 0, 0, bx, by, SRCAND);202 dcMem.StretchBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, bx, by, SRCINVERT);203 }204 dc->BitBlt(cr.left, cr.top, cx, cy, &dcMem, 0, 0, SRCCOPY);205 206 dcMem.SelectObject(oldBmp);207 dcMem.DeleteDC();208 bmpMem.DeleteObject();209 210 DeleteDC(dcMask);211 } else {212 if( DrawMode == DRAW_NORMAL){213 dc->BitBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, SRCCOPY);214 } else {215 int bx=GetBitmapWidth(&bmp);216 int by=GetBitmapHeight(&bmp);217 dc->StretchBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, bx, by, SRCCOPY);218 }219 }220 dcBmp.DeleteDC();221 }222 223 void CRgnButton::FillWithBitmap(CDC* dc, CBitmap &bmp, RECT rc)224 {225 if(!bmp.GetSafeHandle()) 226 return;227 228 CDC dcMem;229 dcMem.CreateCompatibleDC(dc);230 CBitmap *oldBmp = dcMem.SelectObject(&bmp);231 232 int w = rc.right - rc.left;233 int h = rc.bottom - rc.top;234 int x, y, z;235 int bx=GetBitmapWidth(&bmp);236 int by=GetBitmapHeight(&bmp);237 238 for (y = rc.top ; y < h ; y += by){239 if ( (y + by) > h) 240 by = h - y;241 z=bx;242 for (x = rc.left ; x < w ; x += z){243 if ( (x + z) > w) 244 z = w - x;245 dc->BitBlt(x, y, z, by, &dcMem, 0, 0, SRCCOPY);246 }247 }248 249 dcMem.SelectObject(oldBmp);250 dcMem.DeleteDC();251 }252 253 void CRgnButton::PreSubclassWindow()254 {255 m_Style=GetButtonStyle(); ///get specific BS_ styles256 if ( (m_Style & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX)257 m_Style=BS_CHECKBOX;258 else if ((m_Style & BS_AUTORADIOBUTTON)==BS_AUTORADIOBUTTON)259 m_Style=BS_RADIOBUTTON;260 else { m_Style=BS_PUSHBUTTON; }261 262 CButton::PreSubclassWindow();263 ModifyStyle(0, BS_OWNERDRAW);264 }265 266 BOOL CRgnButton::OnEraseBkgnd(CDC* pDC)267 {268 return TRUE;269 270 // return CButton::OnEraseBkgnd(pDC);271 }272 273 void CRgnButton::OnLButtonDown(UINT nFlags, CPoint point)274 {275 RelayEvent(WM_LBUTTONDOWN, (WPARAM)nFlags, MAKELPARAM(LOWORD(point.x), LOWORD(point.y)));276 277 //If we are tracking this button, cancel it278 if (m_bTrack) {279 TRACKMOUSEEVENT t = {280 sizeof(TRACKMOUSEEVENT),281 TME_CANCEL | TME_LEAVE,282 m_hWnd,283 0 284 };285 if (::_TrackMouseEvent(&t)) {286 m_bTrack = false;287 }288 }289 290 CButton::OnLButtonDown(nFlags, point);291 m_bBtnDown = true;292 }293 294 void CRgnButton::OnLButtonUp(UINT nFlags, CPoint point)295 {296 if (m_Style){ //track mouse for radio & check buttons297 POINT p2 = point;298 ::ClientToScreen(m_hWnd, &p2);299 HWND mouse_wnd = ::WindowFromPoint(p2);300 if (mouse_wnd == m_hWnd){ // mouse is in button301 if (m_Style==BS_CHECKBOX) 302 SetCheck(m_bCheck ? 0 : 1);303 if (m_Style==BS_RADIOBUTTON) 304 SetCheck(1);305 }306 }307 //Pass this message to the ToolTip control308 RelayEvent(WM_LBUTTONUP,(WPARAM)nFlags,MAKELPARAM(LOWORD(point.x),LOWORD(point.y)));309 310 //Default-process the message311 m_bBtnDown = false;312 CButton::OnLButtonUp(nFlags, point);313 }314 315 void CRgnButton::OnMouseMove(UINT nFlags, CPoint point)316 {317 RelayEvent(WM_MOUSEMOVE,(WPARAM)nFlags,MAKELPARAM(LOWORD(point.x),LOWORD(point.y)));318 319 if ( (m_bBtnDown) && (::GetCapture() == m_hWnd)) {320 POINT p2 = point;321 ::ClientToScreen(m_hWnd, &p2);322 HWND mouse_wnd = ::WindowFromPoint(p2);323 324 bool bPressed = ((GetState() & BST_PUSHED) == BST_PUSHED);325 bool bNeedPressed = (mouse_wnd == m_hWnd);326 if (bPressed != bNeedPressed) {327 SetState(bNeedPressed ? TRUE : FALSE);328 Invalidate();329 }330 } else {331 if (!m_bTrack) {332 TRACKMOUSEEVENT t = {333 sizeof(TRACKMOUSEEVENT),334 TME_LEAVE,335 m_hWnd,336 0337 };338 if (::_TrackMouseEvent(&t)) {339 m_bTrack = true;340 Invalidate();341 }342 }343 }344 345 CButton::OnMouseMove(nFlags, point);346 }347 348 void CRgnButton::OnLButtonDblClk(UINT nFlags, CPoint point)349 {350 SendMessage(WM_LBUTTONDOWN, nFlags, MAKELPARAM(point.x, point.y));351 352 // CButton::OnLButtonDblClk(nFlags, point);353 }354 355 void CRgnButton::OnKillFocus(CWnd* pNewWnd)356 {357 if (::GetCapture() == m_hWnd) {358 ::ReleaseCapture();359 ASSERT (!m_bTrack);360 m_bBtnDown = false;361 }362 363 CButton::OnKillFocus(pNewWnd);364 }365 366 BOOL CRgnButton::OnBnClicked()367 {368 if (::GetCapture() == m_hWnd) {369 ::ReleaseCapture();370 ASSERT (!m_bTrack);371 }372 373 m_bBtnDown = false;374 return FALSE;375 }376 377 void CRgnButton::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)378 {379 if ( (m_Style) && (nChar==' ') ){ //needed stuff for check & radio buttons380 if (m_Style == BS_CHECKBOX) 381 SetCheck(m_bCheck ? 0 : 1);382 if (m_Style == BS_RADIOBUTTON) 383 SetCheck(1);384 }385 386 CButton::OnKeyDown(nChar, nRepCnt, nFlags);387 }388 389 HRESULT CRgnButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)390 {391 ASSERT(m_bTrack);392 393 m_bTrack = false;394 Invalidate();395 396 return 0;397 }398 399 HRESULT CRgnButton::OnRadioInfo(WPARAM wParam, LPARAM lParam)400 {401 if (m_bCheck){ //only checked buttons need to be unchecked402 m_bCheck = false;403 Invalidate();404 }405 return 0;406 }407 408 HRESULT CRgnButton::OnBMSetCheck(WPARAM wParam, LPARAM lParam)409 {410 m_bCheck = (wParam != 0);411 412 switch (m_Style)413 {414 case BS_RADIOBUTTON:415 if (m_bCheck) { //uncheck the other radio buttons (in the same group)416 HWND hthis,hwnd2,hpwnd;417 hpwnd=GetParent()->GetSafeHwnd(); //get button parent handle418 hwnd2=hthis=GetSafeHwnd(); //get this button handle419 if (hthis && hpwnd){ //consistency check420 for( ; ; ){ //scan the buttons within the group421 hwnd2=::GetNextDlgGroupItem(hpwnd, hwnd2, 0);422 //until we reach again this button423 if ( (hwnd2 == hthis) || (hwnd2 == NULL) ) 424 break;425 //post the uncheck message426 ::PostMessage(hwnd2, WM_CXSHADE_RADIO, 0, 0);427 }428 }429 }430 break;431 case BS_PUSHBUTTON:432 m_bCheck=false;433 ASSERT(false); // Must be a Check or Radio button to use this function434 }435 436 Invalidate();437 return 0;438 }439 440 HRESULT CRgnButton::OnBMGetCheck(WPARAM wParam, LPARAM lParam)441 {442 return m_bCheck;443 }444 445 void CRgnButton::SetSkin(UINT normal, UINT down, UINT over/* =0 */, 446 UINT disabled/* =0 */, UINT focus/* =0 */,UINT mask/* =0 */, 447 DRAW_MODE drawmode/* =1 */,short border/* =1 */,short margin/* =4 */)448 {449 m_bNormal.DeleteObject(); //free previous allocated bitmap450 m_bDown.DeleteObject();451 m_bOver.DeleteObject();452 m_bDisable.DeleteObject();453 m_bMask.DeleteObject();454 m_bFocus.DeleteObject();455 456 if (normal>0) m_bNormal.LoadBitmap(normal);457 if (down>0) m_bDown.LoadBitmap(down);458 if (over>0) m_bOver.LoadBitmap(over);459 if (focus>0) m_bFocus.LoadBitmap(focus);460 461 if (disabled>0) 462 m_bDisable.LoadBitmap(disabled);463 else if (normal>0) 464 m_bDisable.LoadBitmap(normal);465 466 m_DrawMode = (DRAW_MODE)max(0,min(drawmode, DRAW_TILED));467 m_bHasBorder = (border > 0);468 m_nFocusRectMargin = max(0, margin);469 470 if (mask>0){471 m_bMask.LoadBitmap(mask);472 if (m_hClipRgn) 473 DeleteObject(m_hClipRgn);474 m_hClipRgn = CreateRgnFromBitmap(m_bMask, RGB(255,255,255));475 if (m_hClipRgn){476 SetWindowRgn(m_hClipRgn, TRUE);477 GetDC()->SelectClipRgn(CRgn::FromHandle(m_hClipRgn));478 }479 if (m_DrawMode == 0){480 SetWindowPos(NULL, 0, 0, GetBitmapWidth(&m_bMask),481 GetBitmapHeight(&m_bMask), SWP_NOZORDER|SWP_NOMOVE);482 }483 }484 }485 486 HRGN CRgnButton::CreateRgnFromBitmap(CBitmap &bmp, COLORREF cTransColor)487 {488 HRGN hRgn = NULL;489 COLORREF cTolerance = RGB(0, 0, 0);490 BITMAP bm;491 492 bmp.GetBitmap(&bm);493 CDC dcMem;494 dcMem.CreateCompatibleDC(NULL);495 496 BITMAPINFOHEADER bInfoHead;497 bInfoHead.biSize = sizeof(BITMAPINFOHEADER);498 bInfoHead.biWidth = bm.bmWidth;499 bInfoHead.biHeight = bm.bmHeight; 500 bInfoHead.biPlanes = 1; 501 bInfoHead.biBitCount = 32; 502 bInfoHead.biCompression = BI_RGB; 503 bInfoHead.biSizeImage = 0; 504 bInfoHead.biXPelsPerMeter = 0; 505 bInfoHead.biYPelsPerMeter = 0; 506 bInfoHead.biClrUsed = 0; 507 bInfoHead.biClrImportant = 0; 508 509 void *pBit32 = NULL;510 HBITMAP hBmp32 = CreateDIBSection(dcMem.GetSafeHdc(), (BITMAPINFO *)&bInfoHead, DIB_RGB_COLORS, &pBit32, NULL, 0);511 if(hBmp32) {512 CBitmap *pBmp32 = CBitmap::FromHandle(hBmp32);513 BITMAP bm32;514 pBmp32->GetBitmap(&bm32);515 while(bm32.bmWidthBytes % 4) //round to even516 bm32.bmWidthBytes++;517 518 CBitmap *oldBmp1 = dcMem.SelectObject(pBmp32);519 CDC dcTmp;520 dcTmp.CreateCompatibleDC(&dcMem);521 CBitmap *oldBmp2 = dcTmp.SelectObject(&bmp);522 523 dcMem.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcTmp, 0, 0, SRCCOPY);524 525 DWORD maxRects = ALLOC_UNIT; 526 HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects)); 527 RGNDATA *pData = (RGNDATA *)GlobalLock(hData); 528 pData->rdh.dwSize = sizeof(RGNDATAHEADER); 529 pData->rdh.iType = RDH_RECTANGLES; 530 pData->rdh.nCount = pData->rdh.nRgnSize = 0; 531 SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);532 533 BYTE lr = GetRValue(cTransColor);534 BYTE lg = GetGValue(cTransColor);535 BYTE lb = GetBValue(cTransColor);536 BYTE hr = MinByte(lr, GetRValue(cTolerance));537 BYTE hg = MinByte(lg, GetGValue(cTolerance));538 BYTE hb = MinByte(lb, GetBValue(cTolerance));539 540 BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes; 541 for (int y = 0; y < bm.bmHeight; y++) 542 { 543 // Scan each bitmap pixel from left to right 544 for (int x = 0; x < bm.bmWidth; x++) 545 { 546 // Search for a continuous range of "non transparent pixels" 547 int x0 = x; 548 LONG *p = (LONG *)p32 + x; 549 while (x < bm.bmWidth) 550 { 551 BYTE b = GetRValue(*p); 552 if (b >= lr && b <= hr) 553 { 554 b = GetGValue(*p); 555 if (b >= lg && b <= hg) 556 { 557 b = GetBValue(*p); 558 if (b >= lb && b <= hb) 559 // This pixel is "transparent" 560 break; 561 } 562 } 563 p++; 564 x++; 565 } 566 567 if (x > x0) 568 {569 // Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region 570 if (pData->rdh.nCount >= maxRects) 571 { 572 GlobalUnlock(hData); 573 maxRects += ALLOC_UNIT; 574 hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE); 575 pData = (RGNDATA *)GlobalLock(hData); 576 } 577 RECT *pr = (RECT *)&pData->Buffer; 578 SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1); 579 if (x0 < pData->rdh.rcBound.left) 580 pData->rdh.rcBound.left = x0; 581 if (y < pData->rdh.rcBound.top) 582 pData->rdh.rcBound.top = y; 583 if (x > pData->rdh.rcBound.right) 584 pData->rdh.rcBound.right = x; 585 if (y+1 > pData->rdh.rcBound.bottom) 586 pData->rdh.rcBound.bottom = y+1; 587 pData->rdh.nCount++; 588 589 // On Windows98, ExtCreateRegion() may fail if the number of rectangles is too 590 // large (ie: > 4000). Therefore, we have to create the region by multiple steps. 591 if (pData->rdh.nCount == 2000) 592 { 593 HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); 594 if (hRgn) 595 { 596 CombineRgn(hRgn, hRgn, h, RGN_OR); 597 DeleteObject(h); 598 } 599 else 600 hRgn = h; 601 pData->rdh.nCount = 0; 602 SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0); 603 } 604 } 605 } 606 607 // Go to next row (remember, the bitmap is inverted vertically) 608 p32 -= bm32.bmWidthBytes; 609 } 610 611 HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData); 612 if (hRgn) 613 { 614 CombineRgn(hRgn, hRgn, h, RGN_OR); 615 DeleteObject(h); 616 } 617 else 618 hRgn = h; 619 620 // Clean up 621 GlobalFree(hData);622 dcMem.SelectObject(oldBmp1);623 DeleteObject(hBmp32);624 dcTmp.SelectObject(oldBmp2);625 dcTmp.DeleteDC();626 }627 dcMem.DeleteDC();628 629 return hRgn;630 }631 632 COLORREF CRgnButton::SetTextColor(COLORREF colorNew)633 {634 COLORREF colorTmp = m_cTextColor;635 m_cTextColor = colorNew;636 637 return colorTmp;638 }639 640 void CRgnButton::SetToolTipText(const CString &strTip)641 {642 if(m_Tooltip.m_hWnd==NULL){643 if(m_Tooltip.Create(this)) //first assignment644 if(m_Tooltip.AddTool(this, strTip))645 m_Tooltip.Activate(1);646 } else {647 m_Tooltip.UpdateTipText(strTip,this);648 }649 }650 651 void CRgnButton::RelayEvent(UINT message, WPARAM wParam, LPARAM lParam)652 {653 if(NULL != m_Tooltip.m_hWnd){654 MSG msg;655 msg.hwnd = m_hWnd;656 msg.message = message;657 msg.wParam = wParam;658 msg.lParam = lParam;659 msg.time = 0;660 msg.pt.x = LOWORD(lParam);661 msg.pt.y = HIWORD(lParam);662 663 m_Tooltip.RelayEvent(&msg);664 }665 }