/*---------------------------------------------------------------------------*/ // Author : hiyohiyo // Mail : hiyohiyo@crystalmark.info // Web : https://crystalmark.info/ // License : MIT License /*---------------------------------------------------------------------------*/ #include "stdafx.h" #include "EditFx.h" ////------------------------------------------------ // CEditFx ////------------------------------------------------ CEditFx::CEditFx() { // Control m_X = 0; m_Y = 0; m_bHighContrast = FALSE; m_bDarkMode = FALSE; m_bDrawFrame = FALSE; m_FrameColor = RGB(128, 128, 128); m_RenderMode = OwnerDrawImage; m_bMultiLine = FALSE; m_BkColor = RGB(255, 255, 255); // Glass m_GlassColor = RGB(255, 255, 255); m_GlassAlpha = 128; // Image m_ImageCount = 0; m_BkDC = NULL; m_bBkBitmapInit = FALSE; m_bBkLoad = FALSE; // Font m_TextAlign = SS_LEFT; m_TextColor = RGB(0, 0, 0); // Margin m_Margin.top = 0; m_Margin.left = 0; m_Margin.bottom = 0; m_Margin.right = 0; } CEditFx::~CEditFx() { } IMPLEMENT_DYNAMIC(CEditFx, CEdit) BEGIN_MESSAGE_MAP(CEditFx, CEdit) //{{AFX_MSG_MAP(CEditFx) ON_WM_CTLCOLOR_REFLECT() ON_CONTROL_REFLECT(EN_CHANGE, OnEnChange) ON_WM_KEYDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() //------------------------------------------------ // Control //------------------------------------------------ BOOL CEditFx::InitControl(int x, int y, int width, int height, double zoomRatio, CDC* bkDC, LPCTSTR imagePath, int imageCount, DWORD textAlign, int renderMode, BOOL bHighContrast, BOOL bDarkMode, BOOL bDrawFrame, BOOL bMultiLine) { 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); m_bMultiLine = bMultiLine; m_BkDC = bkDC; m_ImagePath = imagePath; m_ImageCount = imageCount; m_RenderMode = renderMode; if (ES_LEFT <= textAlign && textAlign <= ES_RIGHT) { m_TextAlign = textAlign; ModifyStyle(0, m_TextAlign); } if (m_ToolTip.m_hWnd != NULL) { if (m_ToolTip.GetToolCount() != 0) { m_ToolTip.DelTool(this, 1); } CRect rect; GetClientRect(rect); m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); } m_bHighContrast = bHighContrast; m_bDarkMode = bDarkMode; m_bDrawFrame = bDrawFrame; if (m_bHighContrast) { return TRUE; } else if (renderMode & SystemDraw) { return TRUE; } else { SetBkReload(); LoadCtrlBk(m_BkDC); } if (renderMode & OwnerDrawImage) { if (!LoadBitmap(imagePath)) { } } else { m_ImageCount = 1; m_CtrlImage.Destroy(); m_CtrlImage.Create(m_CtrlSize.cx, m_CtrlSize.cy * m_ImageCount, 32); m_CtrlBitmap.Detach(); m_CtrlBitmap.Attach((HBITMAP)m_CtrlImage); DWORD length = m_CtrlSize.cx * m_CtrlSize.cy * m_ImageCount * 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 < (int)(m_CtrlSize.cy * m_ImageCount); y++) { for (int x = 0; x < m_CtrlSize.cx; x++) { DWORD p = (y * m_CtrlSize.cx + x) * 4; #if _MSC_VER > 1310 #pragma warning( disable : 6386 ) #endif bitmapBits[p + 0] = b; bitmapBits[p + 1] = g; bitmapBits[p + 2] = r; bitmapBits[p + 3] = a; #if _MSC_VER > 1310 #pragma warning( default : 6386 ) #endif } } m_CtrlBitmap.SetBitmapBits(length, bitmapBits); delete[] bitmapBits; } SetupControlImage(m_BkBitmap, m_CtrlBitmap); m_BkBrush.DeleteObject(); m_BkBrush.CreatePatternBrush(&m_CtrlBitmap); Invalidate(); return TRUE; } void CEditFx::SetMargin(int top, int left, int bottom, int right, double zoomRatio) { m_Margin.top = (int)(top * zoomRatio); m_Margin.left = (int)(left * zoomRatio); m_Margin.bottom = (int)(bottom * zoomRatio); m_Margin.right = (int)(right * zoomRatio); if (GetWindowLongPtr(m_hWnd, GWL_STYLE) & ES_MULTILINE) { CRect rectGet, rectSet; GetRect(rectGet); rectSet.top = m_Margin.top; rectSet.bottom = rectGet.bottom - m_Margin.bottom - m_Margin.top; rectSet.left = m_Margin.left; rectSet.right = rectGet.right - m_Margin.right - m_Margin.left; SetRect(rectSet); } else { SetMargins(m_Margin.left, m_Margin.right); } } CSize CEditFx::GetSize(void) { return m_CtrlSize; } void CEditFx::SetDrawFrame(BOOL bDrawFrame) { #if _MSC_VER > 1310 if (bDrawFrame) { ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_DRAWFRAME); } else { ModifyStyleEx(WS_EX_STATICEDGE, 0, SWP_DRAWFRAME); } #else if (bDrawFrame) { if (IsNT3()) { ModifyStyle(0, WS_BORDER, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); } else { ModifyStyleEx(0, WS_EX_STATICEDGE, SWP_DRAWFRAME); } } else { if (IsNT3()) { ModifyStyle(WS_BORDER, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED); } else { ModifyStyleEx(WS_EX_STATICEDGE, 0, SWP_DRAWFRAME); } } #endif m_bDrawFrame = bDrawFrame; } void CEditFx::SetGlassColor(COLORREF glassColor, BYTE glassAlpha) { m_GlassColor = glassColor; m_GlassAlpha = glassAlpha; } void CEditFx::SetBkColor(COLORREF bkColor) { m_BkColor = bkColor; } void CEditFx::Adjust() { CRect rectGet, rectSet; GetRect(rectGet); CClientDC dc(this); HGDIOBJ oldFont = dc.SelectObject(&m_Font); #ifdef UNICODE CSize size = dc.GetTextExtent(L"ÁAaPpQqYy8!"); #else CSize size = dc.GetTextExtent("AaPpQqYy8!"); #endif dc.SelectObject(oldFont); rectSet.top = (m_CtrlSize.cy - size.cy) / 2; rectSet.bottom = rectSet.top + size.cy; rectSet.left = rectGet.left; rectSet.right = rectGet.right; SetRect(rectSet); } HBRUSH CEditFx::CtlColor(CDC* pDC, UINT nCtlColor) { if (m_bHighContrast) { pDC->SetBkMode(TRANSPARENT); return NULL; } else { #ifdef UNICODE pDC->SetTextColor(m_TextColor); pDC->SetBkMode(TRANSPARENT); return m_BkBrush; #else pDC->SetTextColor(m_TextColor); pDC->SetBkColor(m_BkColor); pDC->SetBkMode(OPAQUE); return CreateSolidBrush(m_BkColor); #endif } } //------------------------------------------------ // Image //------------------------------------------------ BOOL CEditFx::LoadBitmap(LPCTSTR fileName) { if (m_bHighContrast) { return FALSE; } if (fileName == NULL) { return FALSE; } m_CtrlImage.Destroy(); m_CtrlImage.Load(fileName); if (m_CtrlImage.IsNull()) { return FALSE; } return LoadBitmap((HBITMAP)m_CtrlImage); } BOOL CEditFx::LoadBitmap(HBITMAP hBitmap) { if (m_bHighContrast) { return FALSE; } m_CtrlBitmap.Detach(); m_CtrlBitmap.Attach(hBitmap); return SetBitmap(m_CtrlBitmap); } void CEditFx::SetBkReload(void) { m_bBkBitmapInit = FALSE; m_bBkLoad = FALSE; } BOOL CEditFx::SetBitmap(CBitmap& bitmap) { if (m_bHighContrast) { return FALSE; } BITMAP bitmapInfo; bitmap.GetBitmap(&bitmapInfo); if (m_CtrlSize.cx != bitmapInfo.bmWidth || m_CtrlSize.cy != bitmapInfo.bmHeight / m_ImageCount) { return FALSE; } else { return TRUE; } } void CEditFx::LoadCtrlBk(CDC* drawDC) { if (m_bHighContrast) { SetBkReload(); return; } if (m_BkBitmap.m_hObject != NULL) { BITMAP bitmapInfo; m_BkBitmap.GetBitmap(&bitmapInfo); if (bitmapInfo.bmBitsPixel != drawDC->GetDeviceCaps(BITSPIXEL)) { SetBkReload(); } } if (&m_CtrlBitmap != NULL) { if (!m_bBkBitmapInit) { m_BkBitmap.DeleteObject(); m_BkBitmap.CreateCompatibleBitmap(drawDC, m_CtrlSize.cx, m_CtrlSize.cy); m_bBkBitmapInit = TRUE; } if (!m_bBkLoad) { CBitmap* pOldBitmap; CDC* pMemDC = new CDC; pMemDC->CreateCompatibleDC(drawDC); pOldBitmap = pMemDC->SelectObject(&m_BkBitmap); pMemDC->BitBlt(0, 0, m_CtrlSize.cx, m_CtrlSize.cy, m_BkDC, m_X, m_Y, SRCCOPY); pMemDC->SelectObject(pOldBitmap); pMemDC->DeleteDC(); delete pMemDC; m_bBkLoad = TRUE; } } } void CEditFx::SetupControlImage(CBitmap& bkBitmap, CBitmap& ctrlBitmap) { int color = m_BkDC->GetDeviceCaps(BITSPIXEL) * m_BkDC->GetDeviceCaps(PLANES); if (!m_CtrlImage.IsNull()) { if (m_CtrlImage.GetBPP() == 32) { 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; if ((DstBmpInfo.bmWidthBytes != CtlBmpInfo.bmWidthBytes) || (DstBmpInfo.bmHeight != CtlBmpInfo.bmHeight / m_ImageCount)) { // Error Check // } else { 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++) { #if _MSC_VER > 1310 #pragma warning( disable : 6385 ) #pragma warning( disable : 6386 ) #endif 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); #if _MSC_VER > 1310 #pragma warning( default : 6386 ) #pragma warning( default : 6385 ) #endif } } 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, m_CtrlSize.cy, bk32Image.GetDC(), 0, 0, SRCCOPY); m_CtrlImage.ReleaseDC(); bk32Image.ReleaseDC(); ctrlBitmap.SetBitmapBits(CtlMemSize, CtlBuffer); } if (m_bDrawFrame) { HGDIOBJ oldPen; POINT point; CPen pen1; pen1.CreatePen(PS_SOLID, 1, RGB(0xF8, 0xF8, 0xF8)); CPen pen2; pen2.CreatePen(PS_SOLID, 1, RGB(0x98, 0x98, 0x98)); HDC hDC = m_CtrlImage.GetDC(); oldPen = SelectObject(hDC, pen1); MoveToEx(hDC, 0, m_CtrlSize.cy - 1, &point); LineTo(hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); LineTo(hDC, m_CtrlSize.cx - 1, 0); LineTo(hDC, m_CtrlSize.cx - 1, m_CtrlSize.cy - 1); SelectObject(hDC, pen2); MoveToEx(hDC, 0, m_CtrlSize.cy - 2, &point); LineTo(hDC, 0, 0); LineTo(hDC, m_CtrlSize.cx - 1, 0); SelectObject(hDC, oldPen); pen1.DeleteObject(); pen2.DeleteObject(); m_CtrlImage.ReleaseDC(); } delete[] DstBuffer; delete[] CtlBuffer; } } } } //------------------------------------------------ // Font //------------------------------------------------ void CEditFx::SetFontEx(CString face, int size, int sizeToolTip, double zoomRatio, double fontRatio, COLORREF textColor, 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); logFont.lfHeight = (LONG)(-1 * sizeToolTip * zoomRatio); m_FontToolTip.DeleteObject(); m_FontToolTip.CreateFontIndirect(&logFont); m_TextColor = textColor; if (m_ToolTip.m_hWnd != NULL) { m_ToolTip.SetFont(&m_FontToolTip); } } //------------------------------------------------ // Message Map //------------------------------------------------ void CEditFx::OnEnChange() { Invalidate(); } void CEditFx::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { if (nChar == VK_RETURN && m_bMultiLine == FALSE) { return ; } else { CEdit::OnKeyDown(nChar, nRepCnt, nFlags); } } //------------------------------------------------ // ToolTip //------------------------------------------------ void CEditFx::SetToolTipText(LPCTSTR text) { if (text == NULL) { return; } InitToolTip(); m_ToolTipText = text; if (m_ToolTip.GetToolCount() == 0) { CRect rect; GetClientRect(rect); m_ToolTip.AddTool(this, m_ToolTipText, rect, 1); } else { m_ToolTip.UpdateTipText(m_ToolTipText, this, 1); } SetToolTipActivate(TRUE); } void CEditFx::SetToolTipActivate(BOOL bActivate) { if (m_ToolTip.GetToolCount() == 0) { return; } m_ToolTip.Activate(bActivate); } void CEditFx::SetToolTipWindowText(LPCTSTR text) { SetToolTipText(text); SetWindowText(text); } CString CEditFx::GetToolTipText() { return m_ToolTipText; } void CEditFx::InitToolTip() { if (m_ToolTip.m_hWnd == NULL) { m_ToolTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON | TTS_NOANIMATE | TTS_NOFADE); m_ToolTip.Activate(FALSE); m_ToolTip.SetFont(&m_FontToolTip); m_ToolTip.SendMessage(TTM_SETMAXTIPWIDTH, 0, 1024); m_ToolTip.SetDelayTime(TTDT_AUTOPOP, 8000); m_ToolTip.SetDelayTime(TTDT_INITIAL, 500); m_ToolTip.SetDelayTime(TTDT_RESHOW, 100); } } BOOL CEditFx::PreTranslateMessage(MSG* pMsg) { InitToolTip(); m_ToolTip.RelayEvent(pMsg); return CEdit::PreTranslateMessage(pMsg); }