void CHTRichEditCtrl::AddLine(LPCTSTR pszMsg, int iLen, bool bLink, COLORREF cr, COLORREF bk, DWORD mask) { int iMsgLen = (iLen == -1) ? _tcslen(pszMsg) : iLen; if (iMsgLen == 0) return; // Get Edit contents dimensions and cursor position long lStartChar, lEndChar; GetSel(lStartChar, lEndChar); int iSize = GetWindowTextLength(); // Get Auto-AutoScroll state depending on scrollbar position bool bAutoAutoScroll = m_bAutoScroll; // Use the 'ScrollInfo' only, if there is a scrollbar available, otherwise we would // use a scrollinfo which points to the top and we would thus stay at the top. bool bScrollInfo = false; SCROLLINFO si; si.cbSize = sizeof si; si.fMask = SIF_ALL; if ((GetStyle() & WS_VSCROLL) && GetScrollInfo(SB_VERT, &si)) { bScrollInfo = true; // use some threshold to determine if at end or "very near" at end, unfortunately // this is needed to get around richedit specific stuff. this threshold (pixels) // should somewhat reflect the font size used in the control. bAutoAutoScroll = (si.nPos >= (int)(si.nMax - si.nPage - 20)); } // Reduce flicker by ignoring WM_PAINT m_bNoPaint = true; BOOL bIsVisible = IsWindowVisible(); if (bIsVisible) SetRedraw(FALSE); // Remember where we are //int iFirstLine = !bAutoAutoScroll ? GetFirstVisibleLine() : 0; POINT ptScrollPos; SendMessage(EM_GETSCROLLPOS, 0, (LPARAM)&ptScrollPos); // Select at the end of text and replace the selection SafeAddLine(iSize, pszMsg, iMsgLen, lStartChar, lEndChar, bLink, cr, bk, mask); SetSel(lStartChar, lEndChar); // Restore previous selection if (bAutoAutoScroll) ScrollToLastLine(); else { //LineScroll(iFirstLine - GetFirstVisibleLine()); SendMessage(EM_SETSCROLLPOS, 0, (LPARAM)&ptScrollPos); } m_bNoPaint = false; if (bIsVisible) { SetRedraw(); Invalidate(); } }
void CHTRichEditCtrl::OnSize(UINT nType, int cx, int cy) { // Use the 'ScrollInfo' only, if there is a scrollbar available, otherwise we would // use a scrollinfo which points to the top and we would thus stay at the top. bool bAtEndOfScroll; SCROLLINFO si; si.cbSize = sizeof si; si.fMask = SIF_ALL; if ((GetStyle() & WS_VSCROLL) && GetScrollInfo(SB_VERT, &si)) bAtEndOfScroll = (si.nPos >= (int)(si.nMax - si.nPage)); else bAtEndOfScroll = true; CRichEditCtrl::OnSize(nType, cx, cy); if (bAtEndOfScroll) ScrollToLastLine(); }
void CHTRichEditCtrl::AddLine(LPCTSTR pszMsg, int iLen, bool bLink, COLORREF cr, COLORREF bk, DWORD mask) { int iMsgLen = (iLen == -1) ? _tcslen(pszMsg) : iLen; if (iMsgLen == 0) return; #ifdef _DEBUG // if (pszMsg[iMsgLen - 1] == _T('\n')) // ASSERT( iMsgLen >= 2 && pszMsg[iMsgLen - 2] == _T('\r') ); #endif // Get Edit contents dimensions and cursor position long lStartChar, lEndChar; GetSel(lStartChar, lEndChar); int iSize = GetWindowTextLength(); if (lStartChar == iSize && iSize == lEndChar) { // The cursor resides at the end of text SCROLLINFO si; si.cbSize = sizeof si; si.fMask = SIF_ALL; if (m_bAutoScroll && GetScrollInfo(SB_VERT, &si) && si.nPos >= (int)(si.nMax - si.nPage + 1)) { // Not scrolled away SafeAddLine(iSize, pszMsg, iLen, lStartChar, lEndChar, bLink, cr, bk, mask); if (m_bAutoScroll && !IsWindowVisible()) ScrollToLastLine(); } else { // Reduce flicker by ignoring WM_PAINT m_bNoPaint = true; BOOL bIsVisible = IsWindowVisible(); if (bIsVisible) SetRedraw(FALSE); // Remember where we are int iFirstLine = !m_bAutoScroll ? GetFirstVisibleLine() : 0; // Select at the end of text and replace the selection // This is a very fast way to add text to an edit control SafeAddLine(iSize, pszMsg, iLen, lStartChar, lEndChar, bLink, cr, bk, mask); //if (m_bAutoScroll && lStartChar == lEndChar) // lStartChar = lEndChar = -1; SetSel(lStartChar, lEndChar); // Restore our previous selection if (!m_bAutoScroll) LineScroll(iFirstLine - GetFirstVisibleLine()); else ScrollToLastLine(); m_bNoPaint = false; if (bIsVisible){ SetRedraw(); if (m_bRichEdit) Invalidate(); } } } else { // We should add the text anyway... // Reduce flicker by ignoring WM_PAINT m_bNoPaint = true; BOOL bIsVisible = IsWindowVisible(); if (bIsVisible) SetRedraw(FALSE); // Remember where we are int iFirstLine = !m_bAutoScroll ? GetFirstVisibleLine() : 0; // Very annoying problems with EM_GETSCROLLPOS/EM_SETSCROLLPOS. Depending // on the amount of data in the control, the control may start to scroll up // by itself(!!) -- obviously because of some internal rounding errors.. // // Using 'LineScroll' also gives glitches (also depending on the amount of // data stored in the control), but at least it doesn't start to show some 'life' /*POINT ptScrollPos; if (!m_bAutoScroll) SendMessage(EM_GETSCROLLPOS, 0, (LPARAM)&ptScrollPos);*/ if (lStartChar != lEndChar) { // If we are currently selecting some text, we have to find out // if the caret is near the beginning of this block or near the end. // Note that this does not always work. Because of the EM_CHARFROMPOS // message returning only 16 bits this will fail if the user has selected // a block with a length dividable by 64k. // NOTE: This may cause a lot of terrible CRASHES within the RichEdit control when used for a RichEdit control!? // To reproduce the crash: click in the RE control while it's drawing a line and start a selection! if (!m_bRichEdit){ CPoint pt; ::GetCaretPos(&pt); int iCaretPos = CharFromPos(pt); if (abs((lStartChar % 0xffff - iCaretPos)) < abs((lEndChar % 0xffff - iCaretPos))) { iCaretPos = lStartChar; lStartChar = lEndChar; lEndChar = iCaretPos; } } } // Note: This will flicker, if someone has a good idea how to prevent this - let me know // Select at the end of text and replace the selection // This is a very fast way to add text to an edit control SafeAddLine(iSize, pszMsg, iLen, lStartChar, lEndChar, bLink, cr, bk, mask); //if (m_bAutoScroll && lStartChar == lEndChar) // lStartChar = lEndChar = -1; SetSel(lStartChar, lEndChar); // Restore our previous selection if (!m_bAutoScroll){ LineScroll(iFirstLine - GetFirstVisibleLine()); //SendMessage(EM_SETSCROLLPOS, 0, (LPARAM)&ptScrollPos); } else ScrollToLastLine(); m_bNoPaint = false; if (bIsVisible){ SetRedraw(); if (m_bRichEdit) Invalidate(); } } }
void CHTRichEditCtrl::ApplySkin() { if (!m_strSkinKey.IsEmpty()) { // Use the 'ScrollInfo' only, if there is a scrollbar available, otherwise we would // use a scrollinfo which points to the top and we would thus stay at the top. bool bAtEndOfScroll; SCROLLINFO si; si.cbSize = sizeof si; si.fMask = SIF_ALL; if ((GetStyle() & WS_VSCROLL) && GetScrollInfo(SB_VERT, &si)) bAtEndOfScroll = (si.nPos >= (int)(si.nMax - si.nPage)); else bAtEndOfScroll = true; COLORREF cr; if (theApp.LoadSkinColor(m_strSkinKey + _T("Fg"), cr)) { m_bDfltForeground = false; m_crForeground = cr; } else { m_bDfltForeground = m_crDfltForeground == CLR_DEFAULT; m_crForeground = m_bDfltForeground ? GetSysColor(COLOR_WINDOWTEXT) : m_crDfltForeground; } bool bSetCharFormat = false; CHARFORMAT cf; GetDefaultCharFormat(cf); if (!m_bDfltForeground && (cf.dwEffects & CFE_AUTOCOLOR)) { cf.dwEffects &= ~CFE_AUTOCOLOR; bSetCharFormat = true; } else if (m_bDfltForeground && !(cf.dwEffects & CFE_AUTOCOLOR)) { cf.dwEffects |= CFE_AUTOCOLOR; bSetCharFormat = true; } if (bSetCharFormat) { cf.dwMask |= CFM_COLOR; cf.crTextColor = m_crForeground; VERIFY( SetDefaultCharFormat(cf) ); VERIFY( GetSelectionCharFormat(m_cfDefault) ); } if (theApp.LoadSkinColor(m_strSkinKey + _T("Bk"), cr)) { m_bDfltBackground = false; m_crBackground = cr; SetBackgroundColor(FALSE, m_crBackground); } else { m_bDfltBackground = m_crDfltBackground == CLR_DEFAULT; m_crBackground = m_bDfltBackground ? GetSysColor(COLOR_WINDOW) : m_crDfltBackground; SetBackgroundColor(m_bDfltBackground, m_crBackground); } if (bAtEndOfScroll) ScrollToLastLine(); } else { m_bDfltForeground = m_crDfltForeground == CLR_DEFAULT; m_crForeground = m_bDfltForeground ? GetSysColor(COLOR_WINDOWTEXT) : m_crDfltForeground; m_bDfltBackground = m_crDfltBackground == CLR_DEFAULT; m_crBackground = m_bDfltBackground ? GetSysColor(COLOR_WINDOW) : m_crDfltBackground; VERIFY( GetSelectionCharFormat(m_cfDefault) ); } PurgeSmileyCaches(); }
void CHTRichEditCtrl::SetFont(CFont* pFont, BOOL bRedraw) { // Use the 'ScrollInfo' only, if there is a scrollbar available, otherwise we would // use a scrollinfo which points to the top and we would thus stay at the top. bool bAtEndOfScroll; SCROLLINFO si; si.cbSize = sizeof si; si.fMask = SIF_ALL; if ((GetStyle() & WS_VSCROLL) && GetScrollInfo(SB_VERT, &si)) bAtEndOfScroll = (si.nPos >= (int)(si.nMax - si.nPage)); else bAtEndOfScroll = true; LOGFONT lf = {0}; pFont->GetLogFont(&lf); CHARFORMAT cf = {0}; cf.cbSize = sizeof cf; cf.dwMask |= CFM_BOLD; cf.dwEffects |= (lf.lfWeight == FW_BOLD) ? CFE_BOLD : 0; cf.dwMask |= CFM_ITALIC; cf.dwEffects |= (lf.lfItalic) ? CFE_ITALIC : 0; cf.dwMask |= CFM_UNDERLINE; cf.dwEffects |= (lf.lfUnderline) ? CFE_UNDERLINE : 0; cf.dwMask |= CFM_STRIKEOUT; cf.dwEffects |= (lf.lfStrikeOut) ? CFE_STRIKEOUT : 0; cf.dwMask |= CFM_SIZE; HDC hDC = ::GetDC(HWND_DESKTOP); int iPointSize = -MulDiv(lf.lfHeight, 72, GetDeviceCaps(hDC, LOGPIXELSY)); cf.yHeight = iPointSize * 20; ::ReleaseDC(NULL, hDC); cf.dwMask |= CFM_FACE; cf.bPitchAndFamily = lf.lfPitchAndFamily; _tcsncpy(cf.szFaceName, lf.lfFaceName, _countof(cf.szFaceName)); cf.szFaceName[_countof(cf.szFaceName) - 1] = _T('\0'); // although this should work correctly (according SDK) it may give false results (e.g. the "click here..." text // which is shown in the server info window may not be entirely used as a hyperlink???) // cf.dwMask |= CFM_CHARSET; // cf.bCharSet = lf.lfCharSet; cf.yOffset = 0; VERIFY( SetDefaultCharFormat(cf) ); // copy everything except the color m_cfDefault.dwMask = (cf.dwMask & ~CFM_COLOR) | (m_cfDefault.dwMask & CFM_COLOR); m_cfDefault.dwEffects = cf.dwEffects; m_cfDefault.yHeight = cf.yHeight; m_cfDefault.yOffset = cf.yOffset; //m_cfDefault.crTextColor = cf.crTextColor; m_cfDefault.bCharSet = cf.bCharSet; m_cfDefault.bPitchAndFamily = cf.bPitchAndFamily; memcpy(m_cfDefault.szFaceName, cf.szFaceName, sizeof(m_cfDefault.szFaceName)); PurgeSmileyCaches(); if (bAtEndOfScroll) ScrollToLastLine(); if (bRedraw) { Invalidate(); UpdateWindow(); } }
////////////////////////////////////////////////////////////////////////////// // This function is based on Daniel Lohmann's article "CEditLog - fast logging // into an edit control with cout" at http://www.codeproject.com void CLogEditCtrl::AddLine(LPCTSTR pszMsg, int iLen) { int iMsgLen = (iLen == -1) ? _tcslen(pszMsg) : iLen; if (iMsgLen == 0) return; #ifdef _DEBUG if (pszMsg[iMsgLen - 1] == _T('\n')) ASSERT( iMsgLen >= 2 && pszMsg[iMsgLen - 2] == _T('\r') ); #endif // Get Edit contents dimensions and cursor position int iStartChar, iEndChar; GetSel(iStartChar, iEndChar); int iWndTxtLen = GetWindowTextLength(); if (iStartChar == iWndTxtLen && iWndTxtLen == iEndChar) { // The cursor resides at the end of text SCROLLINFO si; si.cbSize = sizeof si; si.fMask = SIF_ALL; if (m_bAutoScroll && GetScrollInfo(SB_VERT, &si) && si.nPos >= (int)(si.nMax - si.nPage + 1)) { // Not scrolled away SafeAddLine(iWndTxtLen, iMsgLen, pszMsg, iStartChar, iEndChar); if (m_bAutoScroll && !IsWindowVisible()) ScrollToLastLine(); } else { // Reduce flicker by ignoring WM_PAINT m_bNoPaint = true; BOOL bIsVisible = IsWindowVisible(); if (bIsVisible) SetRedraw(FALSE); // Remember where we are int nFirstLine = !m_bAutoScroll ? GetFirstVisibleLine() : 0; // Select at the end of text and replace the selection // This is a very fast way to add text to an edit control SafeAddLine(iWndTxtLen, iMsgLen, pszMsg, iStartChar, iEndChar); SetSel(iStartChar, iEndChar, TRUE); // Restore our previous selection if (!m_bAutoScroll) LineScroll(nFirstLine - GetFirstVisibleLine()); else ScrollToLastLine(); m_bNoPaint = false; if (bIsVisible){ SetRedraw(); if (m_bRichEdit) Invalidate(); } } } else { // We should add the text anyway... // Reduce flicker by ignoring WM_PAINT m_bNoPaint = true; BOOL bIsVisible = IsWindowVisible(); if (bIsVisible) SetRedraw(FALSE); // Remember where we are int nFirstLine = !m_bAutoScroll ? GetFirstVisibleLine() : 0; if (iStartChar != iEndChar) { // If we are currently selecting some text, we have to find out // if the caret is near the beginning of this block or near the end. // Note that this does not always work. Because of the EM_CHARFROMPOS // message returning only 16 bits this will fail if the user has selected // a block with a length dividable by 64k. // NOTE: This may cause a lot of terrible CRASHES within the RichEdit control when used for a RichEdit control!? // To reproduce the crash: click in the RE control while it's drawing a line an start a selection! if (!m_bRichEdit){ CPoint pt; ::GetCaretPos(&pt); int nCaretPos = CharFromPos(pt); if (abs((iStartChar % 0xffff - nCaretPos)) < abs((iEndChar % 0xffff - nCaretPos))) { nCaretPos = iStartChar; iStartChar = iEndChar; iEndChar = nCaretPos; } } } // Note: This will flicker, if someone has a good idea how to prevent this - let me know // Select at the end of text and replace the selection // This is a very fast way to add text to an edit control SafeAddLine(iWndTxtLen, iMsgLen, pszMsg, iStartChar, iEndChar); SetSel(iStartChar, iEndChar, TRUE); // Restore our previous selection if (!m_bAutoScroll) LineScroll(nFirstLine - GetFirstVisibleLine()); else ScrollToLastLine(); m_bNoPaint = false; if (bIsVisible){ SetRedraw(); if (m_bRichEdit) Invalidate(); } } }