HMXShapedFormView.cpp
上传用户:yinguanfa
上传日期:2022-02-19
资源大小:400k
文件大小:14k
源码类别:

ListView/ListBox

开发平台:

Visual C++

  1. // HMXShapedFormView.cpp : implementation file
  2. //
  3. /********************************************************************
  4. created: 2001/10/25
  5. file: HMXShapedFormView
  6. author: Massimo Colurcio
  7. homepage: http://www.softhor.com/developmentarea
  8. email: m.colurcio@softhor.com
  9. thanks to:
  10. purpose: use this class to create bitmap shaped formview
  11. *********************************************************************/
  12. #include "stdafx.h"
  13. #include "HMXShapedFormView.h"
  14. #ifdef _DEBUG
  15. #define new DEBUG_NEW
  16. #undef THIS_FILE
  17. static char THIS_FILE[] = __FILE__;
  18. #endif
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CHMXShapedFormView
  21. CHMXShapedFormView::CHMXShapedFormView(UINT nIDD, const CString& sFileRgn, COLORREF clr)
  22. : CFormView(nIDD)
  23. {
  24. if( !sFileRgn.IsEmpty() ) {
  25. m_sFileRgn = sFileRgn;
  26. m_clrTransp = clr;
  27. }
  28. CommonConstructor();
  29. }
  30. CHMXShapedFormView::~CHMXShapedFormView()
  31. {
  32. }
  33. void CHMXShapedFormView::DoDataExchange(CDataExchange* pDX)
  34. {
  35. CFormView::DoDataExchange(pDX);
  36. //{{AFX_DATA_MAP(CHMXShapedFormView)
  37. // NOTE: the ClassWizard will add DDX and DDV calls here
  38. //}}AFX_DATA_MAP
  39. }
  40. BEGIN_MESSAGE_MAP(CHMXShapedFormView, CFormView)
  41. //{{AFX_MSG_MAP(CHMXShapedFormView)
  42. ON_WM_CREATE()
  43. ON_WM_DESTROY()
  44. ON_WM_MOUSEMOVE()
  45. //}}AFX_MSG_MAP
  46. ON_WM_ERASEBKGND()
  47. END_MESSAGE_MAP()
  48. /////////////////////////////////////////////////////////////////////////////
  49. // CHMXShapedFormView diagnostics
  50. #ifdef _DEBUG
  51. void CHMXShapedFormView::AssertValid() const
  52. {
  53. CFormView::AssertValid();
  54. }
  55. void CHMXShapedFormView::Dump(CDumpContext& dc) const
  56. {
  57. CFormView::Dump(dc);
  58. }
  59. #endif //_DEBUG
  60. void CHMXShapedFormView::CommonConstructor()
  61. {
  62. // do nothing... now
  63. }
  64. void CHMXShapedFormView::OnDraw(CDC* pDC) 
  65. {
  66. // TODO: Add your specialized code here and/or call the base class
  67. BitBlt( pDC->m_hDC, 0, 0, m_bmInfo.bmWidth, m_bmInfo.bmHeight, m_hMemDC, 0, 0, SRCCOPY);
  68. return;
  69. }
  70. /********************************************************************
  71. created: 2001/10/25
  72. in: lpCreateStructure
  73. out: none
  74. return: see CWnd::OnCreate
  75. purpose: overrides this funcion to create the region at
  76. this time. 
  77. Special thanks to David Gallardo Llopis. He wrote
  78. the biggest part of this function
  79. *********************************************************************/
  80. int CHMXShapedFormView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  81. {
  82. if (CFormView::OnCreate(lpCreateStruct) == -1)
  83. return -1;
  84. // TODO: Add your specialized creation code here
  85. if( m_sFileRgn.IsEmpty() )
  86. return 0;
  87. // The name of the bitmap to load (if not in the same directory as the application, provide full path!)
  88. // If the bitmap is to be load from the resources, the name stands for the ressource-string identification
  89. // If you want to load the bitmap from file 
  90. m_hBmp=(HBITMAP) LoadImage(lpCreateStruct->hInstance,m_sFileRgn,IMAGE_BITMAP,0,0,LR_LOADFROMFILE | LR_CREATEDIBSECTION);
  91. if( !m_hBmp )
  92. return 0;
  93. // If you want to load the bitmap from the resources 
  94. // Uncomment the next line, and comment the previous "LoadImage()" line!
  95. // hImage=(HBITMAP) LoadImage(lpCreateStruct->hInstance,name,IMAGE_BITMAP,0,0,LR_LOADFROMFILE | LR_CREATEDIBSECTION);
  96. // Let's make this function do the hard work. You pass it the handle of the bitmap,
  97. // the color in the bitmap to be transparent, and a third boolean parameter that
  98. // tells the function whether the passed color is to be interpreted as the transparent
  99. // color or as the opaque color
  100. m_hRegion=BitmapRegion( m_hBmp, m_clrTransp, true);
  101. // If there was no problem getting the region, we make it the current clipping region
  102. // of the dialog's window
  103. if(m_hRegion) {
  104. //
  105. // THE MAGIC ONE
  106. //
  107. // I spent 2 days to find this solution. I Hope it's definitive :)
  108. //
  109. OffsetRgn( m_hRegion, 
  110. GetSystemMetrics( SM_CXFRAME ), 
  111. GetSystemMetrics( SM_CXFRAME ) );
  112. GetParent()->SetWindowRgn( m_hRegion, TRUE);
  113. }
  114. // We ask the bitmap for its size...
  115. GetObject(m_hBmp,sizeof(m_bmInfo),&m_bmInfo);
  116. // At last, we create a display-compatible memory context!
  117. m_hMemDC=CreateCompatibleDC(NULL);
  118. m_hPrevBmp=(HBITMAP)SelectObject(m_hMemDC,m_hBmp);
  119. return 0;
  120. }
  121. /********************************************************************
  122. created: 2001/10/25
  123. in: hBitmap, clrTransp, bTransp
  124. out: none
  125. return: region handle
  126. purpose: creates regin from bitmap
  127. *********************************************************************/
  128. HRGN CHMXShapedFormView::BitmapRegion(HBITMAP hBitmap,COLORREF clrTransp, bool bTransp)
  129. {
  130. // We create an empty region
  131. HRGN hRegion = NULL;
  132. // If the passed bitmap is NULL, go away!
  133. if(!hBitmap) 
  134. return hRegion;
  135. // We create a memory context for working with the bitmap
  136. // The memory context is compatible with the display context (screen)
  137. HDC hMemDC=CreateCompatibleDC(NULL);
  138. // If no context is created, go away, too!
  139. if(!hMemDC) 
  140. return hRegion;
  141. // Computation of the bitmap size
  142. BITMAP bmBitmap;
  143. GetObject(hBitmap, sizeof(bmBitmap), &bmBitmap);
  144. // In order to make the space for the region, we
  145. // create a bitmap with 32bit depth color and with the
  146. // size of the loaded bitmap!
  147. BITMAPINFOHEADER RGB32BITSBITMAPINFO=
  148. sizeof(BITMAPINFOHEADER), 
  149. bmBitmap.bmWidth, 
  150. bmBitmap.bmHeight, 
  151. 1,32,BI_RGB,0,0,0,0,0 
  152. };
  153. // Here is the pointer to the bitmap data
  154. VOID *pBits;
  155. // With the previous information, we create the new bitmap!
  156. HBITMAP hNewBitmap;
  157. hNewBitmap=CreateDIBSection(hMemDC,
  158. (BITMAPINFO *)&RGB32BITSBITMAPINFO,
  159. DIB_RGB_COLORS,&pBits,NULL,0);
  160. // If the creation process succeded...
  161. if(hNewBitmap) {
  162. // We select the bitmap onto the created memory context
  163. // and then we store the previosly selected bitmap on this context!
  164. HBITMAP hPrevBmp=(HBITMAP) SelectObject(hMemDC,hNewBitmap);
  165. // We create another device context compatible with the first!
  166. HDC hDC=CreateCompatibleDC(hMemDC);
  167. // If success...
  168. if(hDC) {
  169. // We compute the number of bytes per row that the bitmap contains, rounding to 32 bit-multiples
  170. BITMAP bmNewBitmap;
  171. GetObject(hNewBitmap,sizeof(bmNewBitmap),&bmNewBitmap);
  172. while(bmNewBitmap.bmWidthBytes % 4) 
  173. bmNewBitmap.bmWidthBytes++;
  174. // Copy of the original bitmap on the memory context!
  175. HBITMAP hPrevBmpOrg=(HBITMAP) SelectObject(hDC,hBitmap);
  176. BitBlt(hMemDC,0,0,bmBitmap.bmWidth,bmBitmap.bmHeight,hDC,0,0,SRCCOPY);
  177. // In order to optimize the code, we don't call the GDI each time we
  178. // find a transparent pixel. We use a RGN_DATA structure were we store
  179. // consecutive rectangles, until we have a large amount of them and then we crete
  180. // the composed region with ExtCreateRgn(), combining it with the main region.
  181. // Then we begin again initializing the RGN_DATA structure and doing another
  182. // iteration, until the entire bitmap is analyzed.
  183. // Also, in order to not saturate the Windows API with calls for reserving
  184. // memory, we wait until NUMRECT rectangles are stores in order to claim
  185. // for another NUMRECT memory space!
  186. #define NUMRECT 100
  187. DWORD nMaxRect = NUMRECT;
  188. // We create the memory data
  189. HANDLE hData=GlobalAlloc(GMEM_MOVEABLE,sizeof(RGNDATAHEADER)+(sizeof(RECT)*nMaxRect));
  190. RGNDATA *pData=(RGNDATA*) GlobalLock(hData);
  191. pData->rdh.dwSize=sizeof(RGNDATAHEADER);
  192. pData->rdh.iType=RDH_RECTANGLES;
  193. pData->rdh.nCount=pData->rdh.nRgnSize=0;
  194. SetRect(&pData->rdh.rcBound,MAXLONG,MAXLONG,0,0);
  195. // We study each pixel on the bitmap...
  196. BYTE *pbPixels=(BYTE*) bmNewBitmap.bmBits+(bmNewBitmap.bmHeight-1)*bmNewBitmap.bmWidthBytes;
  197. // Main loop
  198. for(int nRow=0;nRow<bmBitmap.bmHeight;nRow++) 
  199. {
  200. // Horizontal loop
  201. for(int nCol=0;nCol<bmBitmap.bmWidth;nCol++)
  202. {
  203. // We optimized searching for adyacent transparent pixels!
  204. int nXo=nCol;
  205. LONG *plPixel=(LONG*) pbPixels+nCol;
  206. while(nCol<bmBitmap.bmWidth) 
  207. {
  208. bool bInRange=false;
  209. // Massimo wrote:
  210. //
  211. // Could someone explain me why I have to 
  212. // compare colors in that way?????
  213. //
  214. // Blue/Red inversion??????
  215. //
  216. // If the color is that indicated as transparent...
  217. //
  218. /*
  219. This is the original code...
  220. if( GetRValue(*plPixel)==GetRValue(clrTransp) &&
  221. GetGValue(*plPixel)==GetGValue(clrTransp) &&
  222. GetBValue(*plPixel)==GetBValue(clrTransp) )
  223. bInRange=true;
  224. */
  225. if( GetBValue(*plPixel)==GetRValue(clrTransp) &&
  226. GetGValue(*plPixel)==GetGValue(clrTransp) &&
  227. GetRValue(*plPixel)==GetBValue(clrTransp) )
  228. bInRange=true;
  229. if((bTransp) && (bInRange)) 
  230. break;
  231. if((!bTransp) && (!bInRange)) 
  232. break;
  233. plPixel++;
  234. nCol++;
  235. } // while (nCol < bm.bmWidth) 
  236. if(nCol>nXo) 
  237. {
  238. // We add the rectangle (Xo,Row),(Column,Row+1) to the region
  239. // If the number of rectangles is greater then NUMRECT, we claim
  240. // another pack of NUMRECT memory places!
  241. if (pData->rdh.nCount>=nMaxRect)
  242. {
  243. GlobalUnlock(hData);
  244. nMaxRect+=NUMRECT;
  245. hData=GlobalReAlloc(hData,sizeof(RGNDATAHEADER)+(sizeof(RECT)*nMaxRect),GMEM_MOVEABLE);
  246. pData=(RGNDATA *)GlobalLock(hData);
  247. }
  248. RECT *pRect=(RECT*) &pData->Buffer;
  249. SetRect(&pRect[pData->rdh.nCount], nXo, nRow, nCol, nRow+1);
  250. if( nXo<pData->rdh.rcBound.left) 
  251. pData->rdh.rcBound.left=nXo;
  252. if( nRow<pData->rdh.rcBound.top) 
  253. pData->rdh.rcBound.top=nRow;
  254. if(nCol>pData->rdh.rcBound.right) 
  255. pData->rdh.rcBound.right = nCol;
  256. if(nRow+1>pData->rdh.rcBound.bottom) 
  257. pData->rdh.rcBound.bottom=nRow+1;
  258. pData->rdh.nCount++;
  259. // In Win95/08 there is a limitation on the maximum number of
  260. // rectangles a RGN_DATA can store (aprox. 4500), so we call
  261. // the API for a creation and combination with the main region
  262. // each 2000 rectangles. This is a good optimization, because
  263. // instead of calling the routines for combining for each new
  264. // rectangle found, we call them every 2000 rectangles!!!
  265. if(pData->rdh.nCount==2000)
  266. {
  267. HRGN hNewRegion=ExtCreateRegion(NULL,sizeof(RGNDATAHEADER) + (sizeof(RECT) * nMaxRect),pData);
  268. if (hNewRegion) {
  269. // Si ya existe la regi髇 principal,sumamos la nueva,
  270. // si no,entonces de momento la principal coincide con
  271. // la nueva regi髇.
  272. if (hRegion) {
  273. CombineRgn(hRegion,hRegion,hNewRegion,RGN_OR);
  274. DeleteObject(hNewRegion);
  275. } else
  276. hRegion=hNewRegion;
  277. }
  278. // Volvemos a comenzar la suma de rect醤gulos
  279. pData->rdh.nCount=0;
  280. SetRect(&pData->rdh.rcBound,MAXLONG,MAXLONG,0,0);
  281. }
  282. } // if ( nCol > nXo)
  283. } // for (int  nCol ...)
  284. // Nueva Row. Lo del negativo se debe a que el bitmap est