📄 spbufferwnd.cpp
字号:
// BufferWnd.cpp : 实现文件
//
#include "stdafx.h"
#include "spBufferWnd.h"
// CBufferWnd
/*
2003/08/09 by wenyy create
2003/08/14 by wenyy add function
修改了窗口创建函数,将创建子窗口和弹出窗口进行了区别 CreateChildWnd & CreateAppWnd
2003/08/16 添加 BOOL CBufferWnd::IsSecondByteOfDBCS(int iX,int iY) 从第一个自己开始计算,直到查找到指定字节
修正了PaintWnd,在窗口向右滚动后,第一个字符是中文的第二个字节时输出错误的情况
2003/08/20 添加 WM_BW_NOTIFY 消息,实现显示输出时的串行化,通过消息处理来保证多个输出请求能够按顺序处理,避免多线程时对数据的竞争
*/
IMPLEMENT_DYNAMIC(CBufferWnd, CWnd)
CBufferWnd::CBufferWnd():m_ptCaret(0,0)
{
m_fPopupWnd = FALSE;
m_fCanExit = TRUE;
m_iFontMarginX=1;
m_iFontMarginY=4;
m_iFontWidth=m_iFontHeight=0;
m_ftDraw=NULL;
m_crFont=RGB(255,255,255);
m_crBackground=RGB(0,0,0);
m_pbBuffer=NULL;
m_iWidthBuf = m_iHeightBuf=0;
m_iTabSize = 4;
m_pwndParent = NULL;
m_fCaret=FALSE;
RegisterWindowClass();
}
CBufferWnd::~CBufferWnd()
{
delete m_pbBuffer;
delete m_ftDraw;
}
BOOL CBufferWnd::RegisterWindowClass(void)
{
WNDCLASS wndcls;
HINSTANCE hInst = AfxGetInstanceHandle();
//HINSTANCE hInst = AfxGetResourceHandle();
if (!(::GetClassInfo(hInst, WYYBUFFER_WND, &wndcls)))
{
// otherwise we need to register a new class
wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndcls.lpfnWndProc = ::DefWindowProc;
wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
wndcls.hInstance = hInst;
wndcls.hIcon = AfxGetApp()->LoadStandardIcon(IDI_APPLICATION);;
wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
wndcls.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wndcls.lpszMenuName = NULL;
wndcls.lpszClassName = WYYBUFFER_WND;
if (!AfxRegisterClass(&wndcls))
{
AfxThrowResourceException();
return FALSE;
}
}
return TRUE;
}
BOOL CBufferWnd::CreateChildWnd(DWORD dwFlagsAdd, CWnd * parent, LPCSTR pszTitle,const CRect & rect,int nID,
int iTabSize, int iFontSize, int iWidthBuf, int iHeightBuf)
{
m_fPopupWnd = FALSE;
m_fCanExit = TRUE;
dwFlagsAdd |= WS_CHILD | WS_VSCROLL | WS_HSCROLL;
return CreateEx(0,dwFlagsAdd,parent,pszTitle,rect,nID,
iTabSize, iFontSize, iWidthBuf, iHeightBuf);
}
BOOL CBufferWnd::CreateAppWnd(DWORD dwFlagsAdd,LPCSTR pszTitle,const CRect & rect,
int iTabSize, int iFontSize, int iWidthBuf, int iHeightBuf)
{
m_fPopupWnd = TRUE;
m_fCanExit = FALSE;
dwFlagsAdd |= WS_OVERLAPPED | WS_VSCROLL | WS_HSCROLL;
return CreateEx(WS_EX_APPWINDOW,dwFlagsAdd,NULL,pszTitle,rect,0,
iTabSize, iFontSize, iWidthBuf, iHeightBuf);
}
BOOL CBufferWnd::CreateEx(DWORD dwFlagsEx,DWORD dwFlags,CWnd * parent, LPCSTR pszTitle,const CRect & rect,int nID,
int iTabSize, int iFontSize, int iWidthBuf, int iHeightBuf)
{
m_pwndParent = parent;
dwFlags |= WS_VSCROLL | WS_HSCROLL;
BOOL fOK = CWnd::CreateEx(dwFlagsEx,WYYBUFFER_WND,pszTitle,dwFlags,rect,parent,nID);
if(fOK)
{
m_nWndID = nID;
//设置参数
SetBaseParameter(iTabSize,iFontSize,iWidthBuf,iHeightBuf);
//调整 滚动条
ReCalcScrollSize();
//Caret
OpenCaretAsNecessary();
return TRUE;
}
return FALSE;
}
BOOL CBufferWnd::IsPosVisible(int iX,int iY)
{
if(m_iWidthBuf==0 && m_iHeightBuf==0)
return TRUE;
ASSERT(iX>=0 && iY>=0);
ASSERT(iX<m_iWidthBuf);
ASSERT(iY<m_iHeightBuf);
int iXPos= GetScrollPos(SB_HORZ );
int iYPos= GetScrollPos(SB_VERT );
CPoint ptStart(iXPos,iYPos);
CRect rcShown = CRect(ptStart,m_sizeIndeed);
return rcShown.PtInRect(CPoint(iX,iY));
}
BOOL CBufferWnd::OpenCaretAsNecessary(void)
{
// TRACE("OpenCaretAsNecessary caret(%d,%d)\n",m_ptCaret.x,m_ptCaret.y);
if(!IsPosVisible(m_ptCaret.x,m_ptCaret.y))
{
CloseCaret();
}
else
{
if(!m_fCaret)
{
CreateSolidCaret(m_iFontWidth-m_iFontMarginX,m_iFontHeight);
ShowCaret();
m_fCaret = TRUE;
}
SetCaretPoint();
}
return m_fCaret;
}
void CBufferWnd::CloseCaret(void)
{
if(m_fCaret)
{
HideCaret();
DestroyCaret();
m_fCaret = FALSE;
}
}
void CBufferWnd::SetCaretPoint(void)
{
// if(OpenCaretAsNecessary())
// {
// TRACE("caret(%d,%d)\n",m_ptCaret.x,m_ptCaret.y);
int iXPos= GetScrollPos(SB_HORZ );
int iYPos= GetScrollPos(SB_VERT );
int iX = (m_ptCaret.x-iXPos) * m_iFontWidth;
int iY = (m_ptCaret.y+1-iYPos) * m_iFontHeight - m_iFontMarginY-m_iFontHeight;
SetCaretPos(CPoint(iX,iY));
// }
}
void CBufferWnd::SetBaseParameter(int iTabSize,int iFontSize, int iWidthBuf, int iHeightBuf)
{
ASSERT(iWidthBuf>20 && iWidthBuf<=512 && iHeightBuf>4 && iHeightBuf<512 );
m_iTabSize = (iTabSize<1 || iTabSize>12)?4:iTabSize;
m_iWidthBuf = iWidthBuf;
m_iHeightBuf = iHeightBuf;
m_iLenBuffer = m_iWidthBuf* m_iHeightBuf;
m_pbBuffer = new BYTE[m_iLenBuffer];
memset(m_pbBuffer,0x20,iWidthBuf*iHeightBuf);
CPaintDC dc(this);
m_ftDraw = new CFont;
BOOL fFont = m_ftDraw->CreatePointFont(iFontSize,"宋体",&dc);
ASSERT(fFont);
CFont* pOF = dc.SelectObject(m_ftDraw);
CSize sizeEChar = dc.GetOutputTextExtent("a",1);
CSize sizeCChar = dc.GetOutputTextExtent("aM",2);
dc.SelectObject(pOF);
m_iFontWidth = sizeEChar.cx + m_iFontMarginX;
m_iFontHeight= sizeEChar.cy + m_iFontMarginY;
m_sizeNeed.cx = m_iFontWidth * m_iWidthBuf;
m_sizeNeed.cy = m_iFontHeight * m_iHeightBuf;
// TRACE("Font size=(%d,%d) Need size=(%d,%d)\n",m_iFontWidth,m_iFontHeight,m_sizeNeed.cx,m_sizeNeed.cy);
}
void CBufferWnd::ReCalcScrollSize()
{
//step 1 计算如果不需要用滚动条是否能够完全显示
EnableScrollBarCtrl(SB_HORZ,FALSE);
EnableScrollBarCtrl(SB_VERT,FALSE);
CRect rcWnd;
GetClientRect(rcWnd);
CSize sizeWnd = rcWnd.Size();
if(sizeWnd.cx >= m_sizeNeed.cx && sizeWnd.cy>=m_sizeNeed.cy)
{
EnableScrollBarCtrl(SB_HORZ,FALSE);
EnableScrollBarCtrl(SB_VERT,FALSE);
// TRACE("disabled SB_HORZ & SB_VERT\n");
}
else
{
EnableScrollBarCtrl(SB_HORZ,FALSE);
EnableScrollBarCtrl(SB_VERT,TRUE);
GetClientRect(rcWnd);
sizeWnd= rcWnd.Size();
int iHScroll=1,iVScroll=1;
if(sizeWnd.cx>=m_sizeNeed.cx)
{
EnableScrollBarCtrl(SB_HORZ,FALSE);
SetScrollRange(SB_HORZ,0,0);
iHScroll = 0;
// TRACE("disable SB_HORZ\n");
}
else
{
EnableScrollBarCtrl(SB_HORZ,TRUE);
}
EnableScrollBarCtrl(SB_VERT,FALSE);
GetClientRect(rcWnd);
sizeWnd= rcWnd.Size();
if(sizeWnd.cy>=m_sizeNeed.cy)
{
EnableScrollBarCtrl(SB_VERT,FALSE);
SetScrollRange(SB_VERT,0,0);
iVScroll = 0;
// TRACE("disable SB_VERT\n");
}
else
{
EnableScrollBarCtrl(SB_VERT,TRUE);
}
//step 2 计算添加了滚动条后能够显示的范围,并且计算滚动范围
GetClientRect(rcWnd);
CSize sizeWnd = rcWnd.Size();
if(iHScroll)
{
ASSERT(sizeWnd.cx<m_sizeNeed.cx);
iHScroll = (m_sizeNeed.cx-sizeWnd.cx)/m_iFontWidth + (((m_sizeNeed.cx-sizeWnd.cx)%m_iFontWidth)?1:0);
EnableScrollBarCtrl(SB_HORZ,TRUE);
SetScrollRange(SB_HORZ,0,iHScroll);
// TRACE("enable SB_HORZ range=%d\n",iHScroll);
}
if(iVScroll)
{
ASSERT(sizeWnd.cy<m_sizeNeed.cy);
iVScroll = (m_sizeNeed.cy-sizeWnd.cy)/m_iFontHeight + (((m_sizeNeed.cy-sizeWnd.cy)%m_iFontHeight)?1:0);
EnableScrollBarCtrl(SB_VERT,TRUE);
SetScrollRange(SB_VERT,0,iVScroll);
// TRACE("enable SB_VERT range=%d\n",iVScroll);
}
}
//step 3 计算客户区域实际能够显示的窗口尺寸
GetClientRect(rcWnd);
sizeWnd = rcWnd.Size();
m_sizeIndeed.cx=sizeWnd.cx/m_iFontWidth ;//+ ((sizeWnd.cx%m_iFontWidth)?1:0);
if(m_sizeIndeed.cx>m_iWidthBuf)
m_sizeIndeed.cx=m_iWidthBuf;
m_sizeIndeed.cy=sizeWnd.cy/m_iFontHeight;// + ((sizeWnd.cy%m_iFontHeight)?1:0);
if(m_sizeIndeed.cy>m_iHeightBuf)
m_sizeIndeed.cy=m_iHeightBuf;
m_sizeIndeedDraw.cx=sizeWnd.cx/m_iFontWidth + ((sizeWnd.cx%m_iFontWidth)?1:0);
if(m_sizeIndeedDraw.cx>m_iWidthBuf)
m_sizeIndeedDraw.cx=m_iWidthBuf;
m_sizeIndeedDraw.cy=sizeWnd.cy/m_iFontHeight + ((sizeWnd.cy%m_iFontHeight)?1:0);
if(m_sizeIndeedDraw.cy>m_iHeightBuf)
m_sizeIndeedDraw.cy=m_iHeightBuf;
// TRACE("indeed windows size(%d,%d)\n",m_sizeIndeed.cx,m_sizeIndeed.cy);
}
void CBufferWnd::ScrollTo(int iX,int iY)
{
ASSERT(iX>=0 && iY>=0);
int minpos;
int maxposX,maxposY;
GetScrollRange(SB_HORZ ,&minpos, &maxposX);
GetScrollRange(SB_VERT ,&minpos, &maxposY);
if(iX >maxposX)
iX = maxposX;
if(iY >maxposY)
iY = maxposY;
SetScrollPos(SB_HORZ,iX);
SetScrollPos(SB_VERT,iY);
Invalidate(FALSE);
}
BOOL CBufferWnd::ScrollIfPointNotShown(int iX,int iY)
{
ASSERT(iX>=0 && iY>=0);
ASSERT(iX<m_iWidthBuf);
ASSERT(iY<m_iHeightBuf);
int iXPos= GetScrollPos(SB_HORZ );
int iYPos= GetScrollPos(SB_VERT );
CPoint ptStart(iXPos,iYPos);
CRect rcShown = CRect(ptStart,m_sizeIndeed);
if(!rcShown.PtInRect(CPoint(iX,iY)) )
{
// TRACE("ScrollIfPointNotShown pt not in rect\n");
int minpos;
int maxposX,maxposY;
GetScrollRange(SB_HORZ ,&minpos, &maxposX);
GetScrollRange(SB_VERT ,&minpos, &maxposY);
int iScrollX = iXPos,iScrollY=iYPos;
if(iX< rcShown.left)
{//向左
iScrollX = iX;
}
else if (iX>= rcShown.right)
{
iScrollX = iX - m_sizeIndeed.cx+1;
}
if(iY < rcShown.top)
iScrollY =iY;
else if (iY>= rcShown.bottom)
iScrollY =iY - m_sizeIndeed.cy+1;
ScrollTo(iScrollX, iScrollY);
return TRUE;
}
return FALSE;
}
//文字功能
//在光标处添加文字
void CBufferWnd::AppendTxtAtCaret(int iTxtLen,LPCSTR pszText,BOOL fShowY,BOOL fShowX)
{
if(iTxtLen==0) return;
int iCopied=0,iLeft=iTxtLen;
while(iLeft)
{
int iEndPos = m_ptCaret.x + m_ptCaret.y * m_iWidthBuf;
int iNeedCopy = min(iLeft,m_iWidthBuf - m_ptCaret.x);
memcpy(m_pbBuffer+iEndPos,pszText+iCopied,iNeedCopy);
iCopied+= iNeedCopy;
iLeft -= iNeedCopy;
m_ptCaret.x += iNeedCopy;
if(m_ptCaret.x>= m_iWidthBuf)
{//换行
m_ptCaret.y++;
m_ptCaret.x=0;
if(m_ptCaret.y>= m_iHeightBuf)
{//向上滚动一行
ScrollTxtUp(1);
m_ptCaret.y--;
}
}
}
OpenCaretAsNecessary();
// SetCaretPoint();
int iNewY=0,iNewX=0;
if(fShowY || fShowX)
{
if(fShowY) iNewY = m_ptCaret.y;
if(fShowX) iNewX = m_ptCaret.x;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -