/*---------------------------------------------------------------------------*/ // Author : hiyohiyo // Mail : hiyohiyo@crystalmark.info // Web : https://crystalmark.info/ // License : MIT License /*---------------------------------------------------------------------------*/ #include "stdafx.h" #include "ListCtrlFx.h" #include "OsInfoFx.h" IMPLEMENT_DYNAMIC(CListCtrlFx, CListCtrl) CListCtrlFx::CListCtrlFx() { m_X = 0; m_Y = 0; m_bNT6orLater = IsNT6orLater(); m_BkDC = NULL; m_bHighContrast = FALSE; m_RenderMode = SystemDraw; m_bDarkMode = FALSE; // Color m_TextColor1 = RGB(0, 0, 0); m_TextColor2 = RGB(0, 0, 0); m_TextSelected = RGB(0, 0, 0); m_BkColor1 = RGB(255, 255, 255); m_BkColor2 = RGB(248, 248, 248); m_BkSelected = RGB(248, 248, 255); m_LineColor1 = RGB(224, 224, 224); m_LineColor2 = RGB(240, 240, 240); // Glass m_GlassColor = RGB(255, 255, 255); m_GlassAlpha = 128; } CListCtrlFx::~CListCtrlFx() { } #pragma warning( disable : 26454 ) BEGIN_MESSAGE_MAP(CListCtrlFx, CListCtrl) ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CListCtrlFx::OnCustomdraw) END_MESSAGE_MAP() #pragma warning( default : 26454 ) BOOL CListCtrlFx::InitControl(int x, int y, int width, int height, int maxWidth, int maxHeight, double zoomRatio, CDC* bkDC, int renderMode, BOOL bHighContrast, BOOL bDarkMode) { m_X = (int)(x * zoomRatio); m_Y = (int)(y * zoomRatio); m_CtrlSize.cx = (int)(width * zoomRatio); m_CtrlSize.cy = (int)(height * zoomRatio); MoveWindow(m_X, m_Y, m_CtrlSize.cx, m_CtrlSize.cy); maxWidth = (int)(maxWidth * zoomRatio); maxHeight = (int)(maxHeight * zoomRatio); m_BkDC = bkDC; m_RenderMode = renderMode; m_bHighContrast = bHighContrast; m_bDarkMode = bDarkMode; if (m_bHighContrast) { SetBkImage((LPTSTR)_T("")); } else if (renderMode & OwnerDrawGlass || renderMode & OwnerDrawTransparent) { m_BkBitmap.DeleteObject(); m_BkBitmap.CreateCompatibleBitmap(m_BkDC, maxWidth, maxHeight); CDC BkDC; BkDC.CreateCompatibleDC(m_BkDC); BkDC.SelectObject(m_BkBitmap); BkDC.BitBlt(0, 0, maxWidth, maxHeight, m_BkDC, m_X + 2, m_Y + 2, SRCCOPY); m_CtrlImage.Destroy(); m_CtrlImage.Create(maxWidth, maxHeight, 32); RECT rect{}; rect.top = 0; rect.left = 0; rect.right = maxWidth; rect.bottom = maxHeight; m_CtrlBitmap.Detach(); m_CtrlBitmap.Attach((HBITMAP)m_CtrlImage); DWORD length = maxWidth * maxHeight * 4; BYTE* bitmapBits = new BYTE[length]; m_CtrlBitmap.GetBitmapBits(length, bitmapBits); BYTE r, g, b, a; if (renderMode & OwnerDrawGlass) { r = (BYTE)GetRValue(m_GlassColor); g = (BYTE)GetGValue(m_GlassColor); b = (BYTE)GetBValue(m_GlassColor); a = m_GlassAlpha; } else // OwnerDrawTransparent { r = 0; g = 0; b = 0; a = 0; } for (int y = 0; y < maxHeight; y++) { for (int x = 0; x < maxWidth; x++) { DWORD p = (y * maxWidth + x) * 4; #pragma warning( disable : 6386 ) bitmapBits[p + 0] = b; bitmapBits[p + 1] = g; bitmapBits[p + 2] = r; bitmapBits[p + 3] = a; #pragma warning( default : 6386 ) } } m_CtrlBitmap.SetBitmapBits(length, bitmapBits); delete[] bitmapBits; SetupControlImage(m_BkBitmap, m_CtrlBitmap); if(m_bNT6orLater) { SetBkImage((HBITMAP)m_CtrlBitmap); m_Header.InitControl(x, y, zoomRatio, bkDC, &m_CtrlBitmap, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); } else { SetBkColor(m_BkColor1); m_Header.InitControl(x, y, zoomRatio, bkDC, NULL, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); } } else { if(m_bNT6orLater) { SetBkImage((LPTSTR)_T("")); SetBkColor(m_BkColor1); m_Header.InitControl(x, y, zoomRatio, bkDC, NULL, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); } else { SetBkColor(m_BkColor1); m_Header.InitControl(x, y, zoomRatio, bkDC, NULL, m_TextColor1, m_BkColor1, m_LineColor1, m_RenderMode, m_bHighContrast, m_bDarkMode); } } return TRUE; } void CListCtrlFx::SetupControlImage(CBitmap& bkBitmap, CBitmap& ctrlBitmap) { int color = m_BkDC->GetDeviceCaps(BITSPIXEL) * m_BkDC->GetDeviceCaps(PLANES); CBitmap* bk32Bitmap; CImage bk32Image; if (color == 32) { bk32Bitmap = &bkBitmap; } else { bk32Image.Create(m_CtrlSize.cx, m_CtrlSize.cy, 32); ::BitBlt(bk32Image.GetDC(), 0, 0, m_CtrlSize.cx, m_CtrlSize.cy, *m_BkDC, m_X, m_Y, SRCCOPY); bk32Bitmap = CBitmap::FromHandle((HBITMAP)bk32Image); bk32Image.ReleaseDC(); } BITMAP CtlBmpInfo, DstBmpInfo; bk32Bitmap->GetBitmap(&DstBmpInfo); DWORD DstLineBytes = DstBmpInfo.bmWidthBytes; DWORD DstMemSize = DstLineBytes * DstBmpInfo.bmHeight; ctrlBitmap.GetBitmap(&CtlBmpInfo); DWORD CtlLineBytes = CtlBmpInfo.bmWidthBytes; DWORD CtlMemSize = CtlLineBytes * CtlBmpInfo.bmHeight; BYTE* DstBuffer = new BYTE[DstMemSize]; bk32Bitmap->GetBitmapBits(DstMemSize, DstBuffer); BYTE* CtlBuffer = new BYTE[CtlMemSize]; ctrlBitmap.GetBitmapBits(CtlMemSize, CtlBuffer); int baseY = 0; for (LONG py = 0; py < DstBmpInfo.bmHeight; py++) { int dn = py * DstLineBytes; int cn = (baseY + py) * CtlLineBytes; for (LONG px = 0; px < DstBmpInfo.bmWidth; px++) { #pragma warning( disable : 6385 ) #pragma warning( disable : 6386 ) BYTE a = CtlBuffer[cn + 3]; BYTE na = 255 - a; CtlBuffer[dn + 0] = (BYTE)((CtlBuffer[cn + 0] * a + DstBuffer[dn + 0] * na) / 255); CtlBuffer[dn + 1] = (BYTE)((CtlBuffer[cn + 1] * a + DstBuffer[dn + 1] * na) / 255); CtlBuffer[dn + 2] = (BYTE)((CtlBuffer[cn + 2] * a + DstBuffer[dn + 2] * na) / 255); dn += (DstBmpInfo.bmBitsPixel / 8); cn += (CtlBmpInfo.bmBitsPixel / 8); #pragma warning( default : 6386 ) #pragma warning( default : 6385 ) } } if (color == 32) { ctrlBitmap.SetBitmapBits(CtlMemSize, CtlBuffer); } else { bk32Bitmap->SetBitmapBits(CtlMemSize, CtlBuffer); m_CtrlImage.Detach(); m_CtrlImage.Attach(ctrlBitmap); ::BitBlt(m_CtrlImage.GetDC(), 0, 0, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1, bk32Image.GetDC(), 1, 1, SRCCOPY); m_CtrlImage.ReleaseDC(); bk32Image.ReleaseDC(); } delete[] DstBuffer; delete[] CtlBuffer; } void CListCtrlFx::OnCustomdraw(NMHDR *pNMHDR, LRESULT *pResult) { LPNMLVCUSTOMDRAW lpLVCustomDraw = reinterpret_cast(pNMHDR); switch(lpLVCustomDraw->nmcd.dwDrawStage) { case CDDS_ITEMPREPAINT: case CDDS_ITEMPREPAINT | CDDS_SUBITEM: if(! m_bHighContrast) { if(lpLVCustomDraw->nmcd.dwItemSpec % 2 == 0) { lpLVCustomDraw->clrText = m_TextColor1; lpLVCustomDraw->clrTextBk = m_BkColor1; } else { lpLVCustomDraw->clrText = m_TextColor2; lpLVCustomDraw->clrTextBk = m_BkColor2; } } break; case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM: { RECT rc{}; CBrush br1(m_LineColor1); CBrush br2(m_LineColor2); CHeaderCtrl* header = this->GetHeaderCtrl(); if(header != NULL) { int count = header->GetItemCount(); for(int i = 0; i < count; i++) { ListView_GetSubItemRect(m_hWnd, lpLVCustomDraw->nmcd.dwItemSpec, i, LVIR_LABEL, &rc); LONG left = rc.left; rc.left = rc.right - 1; FillRect(lpLVCustomDraw->nmcd.hdc, &rc, (HBRUSH)br1.GetSafeHandle()); rc.left = left; rc.top = rc.bottom - 1; FillRect(lpLVCustomDraw->nmcd.hdc, &rc, (HBRUSH)br2.GetSafeHandle()); } } } break; default: break; } *pResult = 0; *pResult |= CDRF_NOTIFYPOSTPAINT; *pResult |= CDRF_NOTIFYITEMDRAW; *pResult |= CDRF_NOTIFYSUBITEMDRAW; } void CListCtrlFx::SetTextColor1(COLORREF color){m_TextColor1 = color;} void CListCtrlFx::SetTextColor2(COLORREF color){m_TextColor2 = color;} void CListCtrlFx::SetTextSelected(COLORREF color){m_TextSelected = color;} void CListCtrlFx::SetBkColor1(COLORREF color){m_BkColor1 = color;} void CListCtrlFx::SetBkColor2(COLORREF color){m_BkColor2 = color;} void CListCtrlFx::SetBkSelected(COLORREF color){m_BkSelected = color;} void CListCtrlFx::SetLineColor1(COLORREF color){m_LineColor1 = color;} void CListCtrlFx::SetLineColor2(COLORREF color){m_LineColor2 = color;} void CListCtrlFx::SetGlassColor(COLORREF glassColor, BYTE glassAlpha) { m_GlassColor = glassColor; m_GlassAlpha = glassAlpha; } COLORREF CListCtrlFx::GetTextColor1(){return m_TextColor1;} COLORREF CListCtrlFx::GetTextColor2(){return m_TextColor2;} COLORREF CListCtrlFx::GetTextSelected(){return m_TextSelected;} COLORREF CListCtrlFx::GetBkColor1(){return m_BkColor1;} COLORREF CListCtrlFx::GetBkColor2(){return m_BkColor2;} COLORREF CListCtrlFx::GetBkSelected(){return m_BkSelected;} COLORREF CListCtrlFx::GetLineColor1(){return m_LineColor1;} COLORREF CListCtrlFx::GetLineColor2(){return m_LineColor2;} void CListCtrlFx::SetFontEx(CString face, int size, double zoomRatio, double fontRatio, LONG fontWeight, BYTE fontRender) { LOGFONT logFont = { 0 }; logFont.lfCharSet = DEFAULT_CHARSET; logFont.lfHeight = (LONG)(-1 * size * zoomRatio * fontRatio); logFont.lfQuality = fontRender; logFont.lfWeight = fontWeight; if (face.GetLength() < 32) { wsprintf(logFont.lfFaceName, _T("%s"), (LPCTSTR)face); } else { wsprintf(logFont.lfFaceName, _T("")); } m_Font.DeleteObject(); m_Font.CreateFontIndirect(&logFont); SetFont(&m_Font); m_Header.SetFontEx(face, size, zoomRatio, fontRatio, fontWeight, fontRender); } void CListCtrlFx::PreSubclassWindow() { CListCtrl::PreSubclassWindow(); CHeaderCtrlFx* pHeader = (CHeaderCtrlFx*)GetHeaderCtrl(); m_Header.SubclassWindow(pHeader->GetSafeHwnd()); } void CListCtrlFx::EnableHeaderOwnerDraw(BOOL bOwnerDraw) { if (m_bHighContrast) { HDITEM hi = { 0 }; hi.mask = HDI_FORMAT; for (int i = 0; i < m_Header.GetItemCount(); i++) { m_Header.GetItem(i, &hi); hi.fmt &= ~HDF_OWNERDRAW; m_Header.SetItem(i, &hi); } return; } else if (m_RenderMode & OwnerDrawGlass) { HDITEM hi = {0}; hi.mask = HDI_FORMAT; if (bOwnerDraw) { for (int i = 0; i < m_Header.GetItemCount(); i++) { m_Header.GetItem(i, &hi); hi.fmt |= HDF_OWNERDRAW; m_Header.SetItem(i, &hi); } } else { for (int i = 0; i < m_Header.GetItemCount(); i++) { m_Header.GetItem(i, &hi); hi.fmt &= ~HDF_OWNERDRAW; m_Header.SetItem(i, &hi); } } } }