📄 htricheditctrl.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include <share.h>
#include "emule.h"
#include "HTRichEditCtrl.h"
#include "OtherFunctions.h"
#include "Preferences.h"
#include "MenuCmds.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNAMIC(CHTRichEditCtrl, CRichEditCtrl)
BEGIN_MESSAGE_MAP(CHTRichEditCtrl, CRichEditCtrl)
ON_WM_CONTEXTMENU()
ON_WM_KEYDOWN()
ON_WM_PAINT()
ON_CONTROL_REFLECT(EN_ERRSPACE, OnEnErrspace)
ON_CONTROL_REFLECT(EN_MAXTEXT, OnEnMaxtext)
ON_NOTIFY_REFLECT_EX(EN_LINK, OnEnLink)
ON_WM_CREATE()
ON_WM_SYSCOLORCHANGE()
END_MESSAGE_MAP()
CHTRichEditCtrl::CHTRichEditCtrl()
{
m_bRichEdit = true;
m_bAutoScroll = true;
m_bNoPaint = false;
m_bEnErrSpace = false;
m_bRestoreFormat = false;
memset(&m_cfDefault, 0, sizeof m_cfDefault);
}
CHTRichEditCtrl::~CHTRichEditCtrl(){
}
void CHTRichEditCtrl::Localize(){
}
void CHTRichEditCtrl::Init(LPCTSTR pszTitle, LPCTSTR pszSkinKey)
{
SetProfileSkinKey(pszSkinKey);
SetTitle(pszTitle);
m_LogMenu.CreatePopupMenu();
m_LogMenu.AddMenuTitle(GetResString(IDS_LOGENTRY));
m_LogMenu.AppendMenu(MF_STRING, MP_COPYSELECTED, GetResString(IDS_COPY));
m_LogMenu.AppendMenu(MF_SEPARATOR);
m_LogMenu.AppendMenu(MF_STRING, MP_SELECTALL, GetResString(IDS_SELECTALL));
m_LogMenu.AppendMenu(MF_STRING, MP_REMOVEALL, GetResString(IDS_PW_RESET));
m_LogMenu.AppendMenu(MF_STRING, MP_SAVELOG, GetResString(IDS_SAVELOG) + _T("..."));
m_LogMenu.AppendMenu(MF_SEPARATOR);
m_LogMenu.AppendMenu(MF_STRING, MP_AUTOSCROLL, GetResString(IDS_AUTOSCROLL));
VERIFY( SendMessage(EM_SETUNDOLIMIT, 0, 0) == 0 );
int iMaxLogBuff = thePrefs.GetMaxLogBuff();
if (afxData.bWin95)
LimitText(iMaxLogBuff > 0xFFFF ? 0xFFFF : iMaxLogBuff);
else
LimitText(iMaxLogBuff ? iMaxLogBuff : 128*1024);
VERIFY( GetSelectionCharFormat(m_cfDefault) );
}
void CHTRichEditCtrl::SetProfileSkinKey(LPCTSTR pszSkinKey)
{
m_strSkinKey = pszSkinKey;
}
void CHTRichEditCtrl::SetTitle(LPCTSTR pszTitle)
{
m_strTitle = pszTitle;
}
int CHTRichEditCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CRichEditCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
Init(NULL);
return 0;
}
LRESULT CHTRichEditCtrl::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) {
case WM_ERASEBKGND:
if (m_bNoPaint)
return TRUE;
case WM_PAINT:
if (m_bNoPaint)
return TRUE;
}
return CRichEditCtrl::WindowProc(message, wParam, lParam);
}
void CHTRichEditCtrl::FlushBuffer()
{
if (m_astrBuff.GetSize() > 0){ // flush buffer
for (int i = 0; i < m_astrBuff.GetSize(); i++)
AddLine(m_astrBuff[i], m_astrBuff[i].GetLength());
m_astrBuff.RemoveAll();
}
}
void CHTRichEditCtrl::AddEntry(LPCTSTR pszMsg)
{
CString strLine(pszMsg);
strLine += _T("\n");
if (m_hWnd == NULL){
m_astrBuff.Add(strLine);
}
else{
FlushBuffer();
AddLine(strLine, strLine.GetLength());
}
}
void CHTRichEditCtrl::Add(LPCTSTR pszMsg, int iLen)
{
if (m_hWnd == NULL){
CString strLine(pszMsg);
m_astrBuff.Add(strLine);
}
else{
FlushBuffer();
AddLine(pszMsg, iLen);
}
}
void CHTRichEditCtrl::AddLine(LPCTSTR pszMsg, int iLen, bool bLink, COLORREF cr)
{
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 iStartChar, iEndChar;
GetSel(iStartChar, iEndChar);
long iSize = GetWindowTextLength();
if (iStartChar == iSize && iSize == 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(iSize, pszMsg, iStartChar, iEndChar, bLink, cr);
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(iSize, pszMsg, iStartChar, iEndChar, bLink, cr);
SetSel(iStartChar, iEndChar); // 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;
POINT ptPos;
if (!m_bAutoScroll)
SendMessage(EM_GETSCROLLPOS, 0, (LPARAM)&ptPos);
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(iSize, pszMsg, iStartChar, iEndChar, bLink, cr);
SetSel(iStartChar, iEndChar); // Restore our previous selection
if (!m_bAutoScroll){
//LineScroll(nFirstLine - GetFirstVisibleLine());
SendMessage(EM_SETSCROLLPOS, 0, (LPARAM)&ptPos);
}
else
ScrollToLastLine();
m_bNoPaint = false;
if (bIsVisible){
SetRedraw();
if (m_bRichEdit)
Invalidate();
}
}
}
void CHTRichEditCtrl::OnEnErrspace()
{
m_bEnErrSpace = true;
}
void CHTRichEditCtrl::OnEnMaxtext()
{
m_bEnErrSpace = true;
}
void CHTRichEditCtrl::ScrollToLastLine()
{
// WM_VSCROLL does not work correctly under Win98 (or older version of comctl.dll)
SendMessage(WM_VSCROLL, SB_BOTTOM);
if (afxData.bWin95){
// older version of comctl.dll seem to need this to properly update the display
int iPos = GetScrollPos(SB_VERT);
SendMessage(WM_VSCROLL, MAKELONG(SB_THUMBPOSITION, iPos));
SendMessage(WM_VSCROLL, SB_ENDSCROLL);
}
}
void CHTRichEditCtrl::AddString(int nPos, LPCTSTR pszString, bool bLink, COLORREF cr)
{
bool bRestoreFormat = false;
m_bEnErrSpace = false;
SetSel(nPos, nPos);
if (bLink)
{
CHARFORMAT2 cf;
memset(&cf, 0, sizeof cf);
GetSelectionCharFormat(cf);
cf.dwMask |= CFM_LINK;
cf.dwEffects |= CFE_LINK;
SetSelectionCharFormat(cf);
}
else if (cr != CLR_DEFAULT)
{
CHARFORMAT cf;
GetSelectionCharFormat(cf);
cf.dwMask |= CFM_COLOR;
cf.dwEffects &= ~CFE_AUTOCOLOR;
cf.crTextColor = cr;
SetSelectionCharFormat(cf);
bRestoreFormat = true;
}
else if (m_bRestoreFormat)
{
SetSelectionCharFormat(m_cfDefault);
}
ReplaceSel(pszString);
m_bRestoreFormat = bRestoreFormat;
}
void CHTRichEditCtrl::SafeAddLine(int nPos, LPCTSTR pszLine, long& iStartChar, long& iEndChar, bool bLink, COLORREF cr)
{
AddString(nPos, pszLine, bLink, cr);
if (m_bEnErrSpace)
{
bool bOldNoPaint = m_bNoPaint;
m_bNoPaint = true;
BOOL bIsVisible = IsWindowVisible();
if (bIsVisible)
SetRedraw(FALSE);
// remove the first line as long as we are capable of adding the new line
int iSafetyCounter = 0;
while (m_bEnErrSpace && iSafetyCounter < 10)
{
// delete the previous partially added line
SetSel(nPos, -1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -