📄 tw2.cpp
字号:
/********************************************
Tw2.cpp文件
定义了本软件中最重要的文本编辑窗类TextWindows
通过该类,用户可以完成插入、删除和块操作等编辑
功能。
*********************************************/
#define mINITBUF 20
#define mADDBUF 15
#define mREFRESHALL 0
#define mREFRESHLINE 1
#define mWINCOLOR (BLUE<<12)|(WHITE<<8)
#define mWINCOLOR2 (BLUE<<12)|(LIGHTGRAY<<8)
#define mTEXTCOLOR (BLUE<<12)|(YELLOW<<8)
#define mBLOCKCOLOR (LIGHTGRAY<<12)|(BLUE<<8)
#define mF1 0xff3b
#define mF2 0xff3c
#define mF3 0xff3d
#define mF4 0xff3e
#define mF5 0xff3f
#define mF6 0xff40
#define mF7 0xff41
#define mF8 0xff42
#define mF9 0xff43
#define mF10 0xff44
typedef struct TextLine
{
char *TheLine; //该行字符串指针
int iLinelen; //字符数
int iBuflen; //该行字符串存储空间总数
TextLine *NextLine; //下一行指针
}Textline;
class TextWindows:public Item
{
private:
TextLine *Head; //行结构体指针
char CurrentFile[256]; //文件名
char cState; // wwwwbn0c B n:New,b:block defining,c:Change,wwww:windows number
//窗口状态字,高四位表示窗口号,第3位为1时表示块定义状态,
//第2位为1时表示是新文件,第1位未使用,
//第0位为1时表示文件被修改
int iAbsPrex,iAbsPrey; //前次光标在整个文件中的(逻辑)位置
int iAbsCurx,iAbsCury; //当前光标在整个文件中的(逻辑)位置
int iBlockTop,iBlockLeft,iBlockBottom,iBlockRight; //块位置
int iStartRow,iStartColm; //文件在窗口中显示的开始行、开始列
int iTotalLine; //文件总行数
void BlockCopy(); //块复制函数
void BlockDef(); //块定义函数
void BlockDel(); //块删除函数
void BlockInsert(); //块插入函数
void BlockSelAll(); //全选
void CurMov(int cInChar); //光标移动函数
void DrawWin(int iMode); //窗口边框绘制函数
void GetCurPose(Textline* &CurRow,char* &CurColm); //得到光标所在处的行、列指针
void InsertChar(int cInChar); //插入字符函数
void MouseButtonDown(int iScrPose,char cButton); //鼠标按键按下响应
void MouseClick(int iScrPose,char cButton); //鼠标点击响应
void MouseMove(int iScrPose,char cButton); //鼠标移动响应
void TextNew(); //新建窗口函数
int TextLoad(); //文件调入函数
int TextSave(char cSaveMode=0); //文件保存函数
void TextSearch(int iMode); //字符串查找函数
void TextRefresh(int iMode=mREFRESHALL); //窗口内容刷新函数
public:
char cTop,cLeft,cHeight,cWidth; //窗口位置
TextWindows(char cWinNum); //窗口初始化
~TextWindows();
void ComMsg(Msg TheMsg); //消息接口函数
};
//文本编辑框构造函数
TextWindows::TextWindows(char cWinNum)
{
Head=NULL; //清空行链表
*CurrentFile='\0'; //清空文件名
iBlockTop=1; //清除块
iBlockLeft=1;
iBlockBottom=0;
iBlockRight=0;
cState=cWinNum<<4; //设定窗口号
cTop=2;cLeft=1;
cHeight=25-cTop+1;
cWidth=80-cLeft+1;
TextNew(); //新建窗口
}
//窗口析构函数
TextWindows::~TextWindows()
{
TextNew(); //清除文本框内容
free(Head->TheLine); //释放第一行结点所占用的空间
free(Head);
textattr(BLACK<<4|LIGHTGRAY);
}
//块定义函数
void TextWindows::BlockDef()
{
//根据光标的位置和块位置之间的关系判断块的新位置
//如果光标的前次位置在块的头
if(iAbsPrex==iBlockLeft&&iAbsPrey==iBlockTop)
{
if(iAbsCury<iBlockBottom||
iAbsCury==iBlockBottom&&
iAbsCurx<=iBlockRight) //如果光标当前的位置在块尾的前面
{
iBlockLeft=iAbsCurx; //那么改变块头的位置
iBlockTop=iAbsCury;
}
else
{
iBlockRight=iAbsCurx-1; //否则改变块尾的位置
iBlockBottom=iAbsCury;
}
}
//如果光标的前次位置在块的尾
else if(iAbsPrex==iBlockRight+1&&iAbsPrey==iBlockBottom)
{
if(iAbsCury>iBlockTop||
iAbsCury==iBlockTop&&
iAbsCurx>=iBlockLeft) //如果光标当前的位置在块头的后面
{
iBlockRight=iAbsCurx-1; //那么改变块尾的位置
iBlockBottom=iAbsCury;
}
else
{
iBlockLeft=iAbsCurx; //否则改变块头的位置
iBlockTop=iAbsCury;
}
}
//其他情况重新定义块
else
{ //根据光标前次的位置和当前的位置,设定块的位置。
if(iAbsPrey<iAbsCury)
{
iBlockLeft=iAbsPrex;
iBlockTop=iAbsPrey;
iBlockBottom=iAbsCury;
iBlockRight=iAbsCurx-1;
}
else if(iAbsPrey>iAbsCury)
{
iBlockLeft=iAbsCurx;
iBlockTop=iAbsCury;
iBlockBottom=iAbsPrey;
iBlockRight=iAbsPrex-1;
}
else
{
iBlockLeft=iAbsPrex<iAbsCurx?iAbsPrex:iAbsCurx;
iBlockRight=iAbsPrex<iAbsCurx?iAbsCurx-1:iAbsPrex-1;
iBlockTop=iBlockBottom=iAbsPrey;
}
}
}
//块复制函数
void TextWindows::BlockCopy()
{
TextLine *CurLine;
int iCountLine,iCountColm;
char *cTmp;
//打开剪切板
ClipBoard.ClpOpen();
//找到块头对应的行
for(iCountLine=1,CurLine=Head;
iCountLine!=iBlockTop&&CurLine;
iCountLine++,CurLine=CurLine->NextLine);
//将块头行和块尾行之间的字符存储到剪切板
for(;iCountLine<=iBlockBottom&&CurLine;
iCountLine++,CurLine=CurLine->NextLine)
{
cTmp=CurLine->TheLine;
for(iCountColm=0;cTmp[iCountColm];iCountColm++)
{
if(iCountLine==iBlockTop&&
iCountColm+1<iBlockLeft||
iCountLine==iBlockBottom&&
iCountColm+1>iBlockRight)
continue;
else //如果字符的位置在块内,那么将字符复制到剪切板
ClipBoard.ClpWrite(cTmp[iCountColm]);
}
}
ClipBoard.ClpClose();
}
//块删除函数
void TextWindows::BlockDel()
{
TextLine *TopLine,*ButtonLine,*TmpLine;
char *cLeft,*cRight;
//如果块位置不合适,函数返回
if(iBlockTop>iBlockBottom) return;
if(iBlockTop==iBlockBottom&&iBlockRight<iBlockLeft) return;
//寻找到块尾指针
iAbsPrex=iAbsCurx;iAbsPrey=iAbsCury;
iAbsCurx=iBlockRight;iAbsCury=iBlockBottom;
GetCurPose(ButtonLine,cRight);
//寻找到块头指针
iAbsCurx=iBlockLeft;iAbsCury=iBlockTop;
GetCurPose(TopLine,cLeft);
//截断块头行
*cLeft='\0';
//如果块头行的存储空间不够用,那么就开辟新空间
if(TopLine->iBuflen<=strlen(TopLine->TheLine)+strlen(cRight))
{
TopLine->TheLine=(char*)realloc(TopLine->TheLine,
TopLine->iBuflen=strlen(TopLine->TheLine)+strlen(cRight)+mADDBUF);
}
strcat(TopLine->TheLine,cRight+1); //将块尾行的剩余字符追加到块头行
TopLine->iLinelen=strlen(TopLine->TheLine);
if(TopLine->TheLine[TopLine->iLinelen-1]!='\n') //加行结尾符
TopLine->TheLine[TopLine->iLinelen++]='\n';
TopLine->TheLine[TopLine->iLinelen]='\0';
TopLine->iLinelen++;
//释放块头和块尾之间的行结点所占用的空间
TmpLine=TopLine->NextLine;
if(iBlockTop!=iBlockBottom)
{
//将块头行结点和块尾行结点后面结点连接起来
TopLine->NextLine=ButtonLine->NextLine;
//释放中间结点空间
for(TopLine=TmpLine;TopLine!=ButtonLine;TopLine=TmpLine)
{
TmpLine=TopLine->NextLine;
free(TopLine->TheLine);
free(TopLine);
}
free(TopLine->TheLine);
free(TopLine);
}
//修改有关参数
iTotalLine-=iBlockBottom-iBlockTop;
iBlockBottom=iBlockTop;
iBlockRight=iBlockLeft-1;
if(iAbsCury>=cHeight-2) iStartRow=iAbsCury-(cHeight>>1);
else iStartRow=1;
if(iAbsCurx>=cWidth-2) iStartColm=iAbsCurx-(cWidth>>1);
else iStartColm=1;
cState|=1;
cState&=0xf7;
}
//块插入函数
void TextWindows::BlockInsert()
{
TextLine *TopLine,*Tmp;
char *cLeft,*cNewLine,cChar;
int iCountLine,i;
//打开剪切板
ClipBoard.ClpOpen();
//寻找插入点
iAbsPrex=iAbsCurx;iAbsPrey=iAbsCury;
GetCurPose(TopLine,cLeft);
Tmp=TopLine->NextLine;
if(*cLeft=='\n') //如果插入位置在插入行的结尾以后
{
if(iAbsCurx+1>=TopLine->iBuflen) //那么如果有必要,要开辟内存空间
{
TopLine->iBuflen=iAbsCurx+mADDBUF;
TopLine->TheLine=(char*)realloc(TopLine->TheLine,TopLine->iBuflen);
}
//改变cLeft指向新的行尾
cLeft=TopLine->TheLine;
for(i=1;*cLeft!='\n';i++) cLeft++;
for(;i<iAbsCurx;i++) *cLeft++=' '; //将行尾和插入点之间添入空格符
*(cLeft)='\n';*(cLeft+1)='\0';
}
//保存插入点后面的字符串
cNewLine=(char*)malloc(strlen(cLeft)+1);
strcpy(cNewLine,cLeft);
iBlockTop=iAbsCury;
iBlockLeft=iAbsCurx;
for(i=cLeft-TopLine->TheLine,iCountLine=0;
(cChar=ClipBoard.ClpRead())!='\0';i++) //循环从剪切板中读出字符
{
if(i+2>=TopLine->iBuflen) //如果插入行空间不够
{
TopLine->iBuflen+=mADDBUF; //开辟新空间
TopLine->TheLine=(char*)realloc(TopLine->TheLine,TopLine->iBuflen);
}
TopLine->TheLine[i]=cChar; //插入字符
if(cChar=='\n') //如果遇到回车符,建立新的行结点
{
TopLine->TheLine[++i]='\0'; //结束当前行
TopLine->iLinelen=i+1;
TopLine->NextLine=(TextLine*)malloc(sizeof(TextLine)); //建立新结点
TopLine->NextLine->iBuflen=mINITBUF;
TopLine->NextLine->TheLine=(char*)malloc(mINITBUF); //为一行字符串开辟空间
TopLine=TopLine->NextLine;
iCountLine++;
i=-1;
}
}
TopLine->TheLine[i]='\0';
//将插入点后面的字符串追加到最后新建行的末尾
if(strlen(TopLine->TheLine)+strlen(cNewLine)+1>=TopLine->iBuflen)
{//如果空间不够,开辟新空间
TopLine->iBuflen+=mADDBUF;
TopLine->TheLine=(char*)realloc(TopLine->TheLine,TopLine->iBuflen);
}
strcat(TopLine->TheLine,cNewLine);
free(cNewLine);
TopLine->iLinelen=strlen(TopLine->TheLine)+1;
TopLine->NextLine=Tmp; //将插入点后面的行链入
//窗口参数做相应调整
iTotalLine+=iCountLine;
iAbsCury=iBlockBottom=iBlockTop+iCountLine;
iAbsCurx=(iBlockRight=i)+1;
if(iAbsCury>=cHeight-2) iStartRow=iAbsCury-(cHeight>>1);
else iStartRow=1;
if(iAbsCurx>=cWidth-2) iStartColm=iAbsCurx-(cWidth>>1);
else iStartColm=1;
cState|=1;
}
//全选函数
void TextWindows::BlockSelAll()
{
TextLine *CurLine;
char *CurColm;
//改变状态字
cState|=8;
//改变光标位置
iAbsPrex=iAbsCurx;
iAbsPrey=iAbsCury;
iAbsCury=iTotalLine;
//定义块
GetCurPose(CurLine,CurColm);
iAbsCurx=CurLine->iLinelen-1;
iBlockTop=iBlockLeft=1;
iBlockBottom=iAbsCury;
iBlockRight=iAbsCurx-1;
}
//消息接口函数
void TextWindows::ComMsg(Msg TheMsg)
{
switch(TheMsg.iOpera)
{
case mITEMREFRESH: //刷新
TextRefresh(0);
break;
case mWINNEW: //新建文件
TextNew();
TextRefresh(mREFRESHALL);
break;
case mWINLOAD: //调入文件
TextLoad();
TextRefresh(mREFRESHALL);
break;
case mWINSAVE: //保存文件
TextSave();
break;
case mWINSAVEAS: //文件另存为
TextSave(1);
break;
case mKEY: //键盘有键入
InsertChar(TheMsg.iAgu2);
case mCURMOV: //光标移动
CurMov(TheMsg.iAgu2);
break;
case mWINBLOCKDEF: //块定义
CurMov(TheMsg.iAgu2);
BlockDef();
TextRefresh();
break;
case mWINCOPY: //块复制
BlockCopy();
break;
case mWINCUT: //块剪切
BlockCopy();
BlockDel();
TextRefresh();
break;
case mWINPASTE: //块粘贴
BlockInsert();
TextRefresh();
break;
case mWINBLOCKDEL: //块删除
BlockDel();
TextRefresh();
break;
case mWINSEARCHFOR: //查找新字符串
TextSearch(mWINSEARCHFOR);
break;
case mWINSEARCHNEXT: //查找下一个匹配字符串
TextSearch(mWINSEARCHNEXT);
break;
case mWINGETFOCUS: //文本框得到焦点
DrawWin(1);
_setcursortype(_NORMALCURSOR);
break;
case mWINLOSFOCUS: //文本框得到焦点
DrawWin(0);
_setcursortype(_NOCURSOR);
break;
case mWINSELALL: //全选
BlockSelAll();
TextRefresh();
break;
case mMOUSECLICK: //鼠标点击
MouseClick(TheMsg.iAgu1,TheMsg.iAgu2);
cState&=0xf7;
break;
case mMOUSEBUTTONDOWN: //鼠标左键按下
MouseButtonDown(TheMsg.iAgu1,TheMsg.iAgu2);
break;
case mMOUSEMOVE: //鼠标移动
MouseMove(TheMsg.iAgu1,TheMsg.iAgu2);
}
}
//光标移动
void TextWindows::CurMov(int cInChar)
{
char cKey=cInChar>>8,cExKey=cInChar&0xff;
int iNeedRefresh=0;
TextLine *CurLine;
char *CurColm;
GetCurPose(CurLine,CurColm);
if(!cKey) //如果是非扩展字符键入
iNeedRefresh=1;
else
{
iAbsPrex=iAbsCurx;
iAbsPrey=iAbsCury;
switch(cExKey) //如果是扩展字符键入,那么分析键码
{
case 72:iAbsCury-=1;break; //分别是上下左右键键入
case 75:iAbsCurx-=1;break;
case 77:iAbsCurx+=1;break;
case 80:iAbsCury+=1;break;
case 73: //PageUp键键入
iAbsCury-=cHeight-3;
iStartRow-=cHeight-3;
iNeedRefresh=1;
break;
case 81: //PageDown键键入
iAbsCury+=cHeight-3;
iStartRow+=cHeight-3;
iNeedRefresh=1;
break;
case 71:iAbsCurx=1;break; //Home键键入
case 79: //End键键入
iAbsCurx=CurLine->iLinelen-1;
break;
case 83: //Del键键入,将光标移动到当前位置的后面一个位置
if(*CurColm=='\n') //如果是行尾,那么将光标转移到下一行行首
{iAbsCury++;iAbsCurx=1;}
else iAbsCurx++;
InsertChar(8); //调用字符插入函数,插入字符尾退格键
iNeedRefresh=1;
};
}
//修改窗口参数
if(iAbsCury>iTotalLine) iAbsCury=iTotalLine;
if(iAbsCurx<iStartColm||
iAbsCurx>iStartColm+cWidth-3||
iAbsCury<iStartRow||
iAbsCury>iStartRow+cHeight-3)
iNeedRefresh=1;
else
gotoxy(iAbsCurx-iStartColm+cLeft+1,
iAbsCury-iStartRow+cTop+1);
if(iNeedRefresh) TextRefresh(mREFRESHALL);
}
//绘制文本编辑窗边框函数
void TextWindows::DrawWin(int iMode)
{
int x,y;
int iShowBuf[78];
//根据不同的模式选择不同的屏幕显示模式
iShowBuf[0]=iMode?0xff&'
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -