tslediter/funcext/tvclib/utslmemo.tsf

4283 lines
126 KiB
Plaintext

unit UTslMemo;
{**
@explan(说明) 文本控件库 %%
**}
{$ifdef linux}
{$define linuxpop123}
{$endif}
interface
uses utslvclauxiliary,utslvclmemstruct,utslvclgdi,utslvclstdctl;
type TMemoLineItem=class() //编辑字符串行对象
function Create(s);
begin
if ifstring(s)then FStr := s;
else FStr := "";
end
function StrLength();
begin
return length(FStr);
end
FMarked;
FStr;
end
TYPE TMemoLineList=class(tnumindexarray) //编辑器行集合
function Create(Aedit);override;
begin
FEdit := Aedit;
class(tnumindexarray).create();
FRowMaxLength := 1;
Flock := true;
end
function Clear();
begin
splices(nil,nil,array(new TMemoLineItem("")));
FRowMaxLength := 1;
end
function SetStringByIndex(idx,v);virtual; //设置行
begin
if not ifstring(v)then return;
o := GetValueByIndex(idx);
if o then
begin
o.FStr := v;
UpDateMaxStringLength(length(v));
if Flock then
begin
FEdit.InvalidateLines(idx+1,idx+1);
end
end
end
function SetLineNumByIndex(idx,v);virtual;
begin
end
function GetLineNumByIndex(idx,v);virtual;
begin
end
function SetValueByIndex(idx,v);override;//设置行内人
begin
if ifstring(v)then return SetStringByIndex(idx,v);
//inherited;
//if Flock then FEdit.InvalidateLines(idx+1,idx+1);
end
function GetStringByIndex(idx);virtual; //获得行内容
begin
o := GetValueByIndex(idx);
if o then return o.FStr;
end
function LengthChanged(n);override; //长度改变
begin
if(Flock)then
begin
//echo "+++\r\n";
FEdit.UpDateScroll();
end
end
function ModifyMaxRowLength(); //修正宽度
begin
fRowMaxLength := 1;
for i := 0 to self.Length()-1 do
begin
vi := GetStringByIndex(i);
fRowMaxLength := max(fRowMaxLength,length(vi));
end
end
function UpDateMaxStringLength(L); //最大宽度改变
begin
if FRowMaxLength<L then
begin
FRowMaxLength := L;
DoColumnIncreased();
end
end
property Text read GetText write SetText;
property OnAdded read FOnAdded write FOnAdded;
property OnChange read FOnChange write FOnChange;
property OnChanging read FOnChanging write FOnChanging;
property OnCleared read FOnCleared write FOnCleared;
Property OnDeleted read FOnDeleted write FOnDeleted;
PROPERTY OnPutted READ fOnPutted write fOnPutted;
//property OnMaxLengthIncrease read FOnMaxLengthIncrease write FOnMaxLengthIncrease;
Property RowMaxLength read fRowMaxLength;
private
Flock;
FRowMaxLength;
weakref
FOnAdded;
FOnChange;
FOnChanging;
FOnCleared;
FOnDeleted;
fOnPutted;
FOnMaxLengthIncrease;
FEdit;
autoref
function DoColumnIncreased();
begin
//echo "\r\nIncreate:",FRowMaxLength;
//if iffuncptr(FOnMaxLengthIncrease) then Call(FOnMaxLengthIncrease);
//echo "\r\nincrease:",FRowMaxLength;
end
function SetText(s);
begin
Clear();
//push(new TMemoLineItem(""));
//return FEdit.ExecuteCommand(ecString,s);
if not(s and ifstring(s))then return;
vs := str2array(s,"\n");
if not vs then vs := array("");
Flock := false;
for i,vi in vs do
begin
if vi="\r" then continue;
if not vi then
begin
push(new TMemoLineItem(vi));
end else
begin
lv := length(vi);
UpDateMaxStringLength(lv);
if vi[lv]="\r" then
begin
push(new TMemoLineItem(vi[1:lv-1]));
end else
begin
Push(new TMemoLineItem(vi));
end
end
end
Flock := true;
end
function GetText();
begin
r := "";
d := Data;
len := Length(d)-1;
for i,v in d do
begin
r += v.FStr;
if i <> len then r += "\r\n";
end
return r;
end
end
type TMemoGutter=class() //行号列
function Create(AEdit);
begin
FWidth := 60;
FEdit := AEdit;
end
function PaintLiens(rc,FirstLine,LastLine);
begin
end
property Width read FWidth write FWidth;
private
function GetWidth();
begin
return 20+FEdit.Font.width * 5;
end
FWidth;
[weakref]FEdit;
end
type TTslMemoUndoItem=class
FReason;
FSelMode;
FStartPos;
FEndPos;
FStr;
FLinkItem; //两步操作的项目
function Create(AReason:TSynChangeReason;AStart,AEnd:TPoint;ChangeText:string;SelMode:TSynSelectionMode);
begin
FReason := AReason;
FSelMode := SelMode;
FStartPos := AStart;
FEndPos := AEnd;
FStr := ChangeText;
end
function Clone();
begin
return new TTslMemoUndoItem(FReason,FStartPos,FEndPos,FStr,FSelMode);
end
end
type TTslMenoUndoList=class() //undolist
private //sbs 2000-11-19
fBlockCount:integer; //sbs 2000-11-19
fFullUndoImposible:boolean; //mh 2000-10-03
fItems:TList;
fLockCount:integer;
fMaxUndoActions;
function GetCanUndo():boolean;
begin
return fItems.length()>0;
end
procedure EnsureMaxEntries(); //达到最大数量处理
begin
if fItems.length()>fMaxUndoActions then
begin //mh 2000-10-03
fFullUndoImposible := TRUE; //mh 2000-10-03
while fItems.length()>fMaxUndoActions do
begin
fItems.Unshift();
end;
end;
end
function GetItemCount():integer;//数量
begin
return fItems.length();
end
procedure SetMaxUndoActions(Value:integer);
begin
if not(Value>0)then Value := 0;
if Value <> fMaxUndoActions then
begin
fMaxUndoActions := Value;
EnsureMaxEntries();
end;
end
public
function Create();
begin
fLockCount := 0;
fItems := new tnumindexarray();
fMaxUndoActions := 1024;
fBlockChangeNumber := 0;
fNextChangeNumber := 1;
end
function Destroy();
begin
Clear();
end
procedure AddChange(AReason:TSynChangeReason;AStart,AEnd:TPoint;ChangeText:string;SelMode:TSynSelectionMode);
begin
if fLockCount=0 then
begin
if ifobj(AReason)then
begin
PushItem(AReason.Clone());
end else
PushItem(CreateATslMemoUndoItem(AReason,AStart,AEnd,ChangeText,SelMode));
end;
end
procedure Clear();
begin
if fItems.length()>0 then
fItems.splices(nil,nil,array());
fFullUndoImposible := FALSE;
end
procedure Lock();//锁住
begin
fLockCount++;
end
procedure Unlock(); //解锁
begin
if fLockCount>0 then fLockCount--;
return fLockCount;
end
function PeekItem():TSynEditUndoItem; //取得
begin
iLast := fItems.length()-1;
if iLast >= 0 then return fItems[iLast];
return nil;
end
function PopItem():TSynEditUndoItem;//弹出
begin
if fLockCount>0 then return nil;
if fItems.length()then return fItems.Pop();
return nil;
end
procedure PushItem(Item); //插入
begin
if fLockCount>0 then return nil;
fItems.push(Item);
if iffuncptr(fOnAdded) then call(fOnAdded,Self(true));
end
public
function MergeReplaceItem(); //合并操作
begin
if fItems.Length()>= 2 then
begin
it := PopItem();
pit := PeekItem();
pitl := pit.FLinkItem;
while pitl do
begin
pit := pitl;
pitl := pit.FLinkItem;
end
pit.FLinkItem := it;
end
end
property LockCount read fLockCount;
property CanUndo:boolean read GetCanUndo;
property ItemCount:integer read GetItemCount;
property MaxUndoActions:integer read fMaxUndoActions write SetMaxUndoActions;
// property OnAddedUndo: TNotifyEvent read fOnAdded write fOnAdded;
end;
type TCustomMemoCmd=class() //编辑器操作码类
{**
@explan(说明)编辑器控件操作码类%%
**}
public
{**
@ignoremembers(
ecNone ,
ecViewCommandFirs ,
ecViewCommandLast ,
ecEditCommandFirs ,
ecEditCommandLast ,
ecPageLeft ,
ecPageRight ,
ecPageTop ,
ecPageBottom ,
ecEditorBottom ,
ecSelPageUp ,
ecSelPageDown ,
ecSelPageLeft ,
ecSelPageRight ,
ecSelPageBottom ,
ecScrollUp ,
ecScrollDown ,
ecScrollLeft ,
ecScrollRight ,
ecInsertMode ,
ecOverwriteMode ,
ecToggleMode ,
ecNormalSelect ,
ecColumnSelect ,
ecLineSelect ,
ecMatchBracket ,
ecGotoMarker0 ,
ecGotoMarker1 ,
ecGotoMarker2 ,
ecGotoMarker3 ,
ecGotoMarker4 ,
ecGotoMarker5 ,
ecGotoMarker6 ,
ecGotoMarker7 ,
ecGotoMarker8 ,
ecGotoMarker9 ,
ecSetMarker0 ,
ecSetMarker1 ,
ecSetMarker2 ,
ecSetMarker3 ,
ecSetMarker4 ,
ecSetMarker5 ,
ecSetMarker6 ,
ecSetMarker7 ,
ecSetMarker8 ,
ecSetMarker9 ,
ecDeleteLastChar ,
ecDeleteChar ,
ecDeleteWord ,
ecDeleteLastWord ,
ecDeleteBOL ,
ecDeleteEOL ,
ecLineBreak ,
ecInsertLine ,
ecChar ,
ecImeStr ,
ecBlockIndent ,
ecBlockUnindent ,
ecTab ,
ecShiftTab ,
ecAutoCompletion ,
ecComment ,
ecUnComment ,
ecNextBlock ,
ecPrevBlock ,
ecNextJumpOut ,
ecPrevJumpOut ,
ecUserFirst ,
ecFind ,
ecReplace ,
ecSearchAgain ,
ecFindAll ,
ecSearchUpAgain ,
)
**}
{**
@param(ecGotoXY)() 跳转光标到指定位置,对应参数为 array(y,x) %%
@param(ecSelGotoXY)() 选中文本到指定位置,对应参数为 array(y,x) %%
@param(ecCopy)() 复制选中文本到剪切板,无对应参数 %%
@param(ecPaste)() 粘贴剪切板文本,无对应参数 %%
@param(ecString)() 插入字符串,对应参数为 字符串 %%
**}
{static ecGotoMarker0;
static ecGotoMarker1;
static ecGotoMarker2;
static ecGotoMarker3;
static ecGotoMarker4;
static ecGotoMarker5;
static ecGotoMarker6;
static ecGotoMarker7;
static ecGotoMarker8;
static ecGotoMarker9;
static ecSetMarker0;
static ecSetMarker1;
static ecSetMarker2;
static ecSetMarker3;
static ecSetMarker4;
static ecSetMarker5;
static ecSetMarker6;
static ecSetMarker7;
static ecSetMarker8;
static ecSetMarker9;}
static const ecNone=0x0;static const ecViewCommandFirs=NIL;
static const ecViewCommandLast=0x1F4;static const ecEditCommandFirs=NIL;static const ecEditCommandLast=0x3E8;
static const ecLeft=0x1;static const ecRight=0x2;static const ecUp=0x3;
static const ecDown=0x4;static const ecWordLeft=0x5;static const ecWordRight=0x6;
static const ecLineStart=0x7;static const ecLineEnd=0x8;static const ecPageUp=0x9;
static const ecPageDown=0xA;static const ecPageLeft=0xB;static const ecPageRight=0xC;
static const ecPageTop=0xD;static const ecPageBottom=0xE;static const ecEditorTop=0xF;
static const ecEditorBottom=0x10;static const ecGotoXY=0x11;static const ecSelection=0x64;
static const ecSelLeft=0x65;static const ecSelRight=0x66;static const ecSelUp=0x67;
static const ecSelDown=0x68;static const ecSelWordLeft=0x69;static const ecSelWordRight=0x6A;
static const ecSelLineStart=0x6B;static const ecSelLineEnd=0x6C;static const ecSelPageUp=0x6D;
static const ecSelPageDown=0x6E;static const ecSelPageLeft=0x6F;static const ecSelPageRight=0x70;
static const ecSelPageTop=0x71;static const ecSelPageBottom=0x72;static const ecSelEditorTop=0x73;
static const ecSelEditorBottom=0x74;static const ecSelGotoXY=0x75;static const ecSelectAll=0xC7;
static const ecCopy=0xC9;static const ecScrollUp=0xD3;static const ecScrollDown=0xD4;
static const ecScrollLeft=0xD5;static const ecScrollRight=0xD6;static const ecInsertMode=0xDD;
static const ecOverwriteMode=0xDE;static const ecToggleMode=0xDF;static const ecNormalSelect=0xE7;
static const ecColumnSelect=0xE8;static const ecLineSelect=0xE9;static const ecMatchBracket=0xFA;
static const ecDeleteLastChar=0x1F5;static const ecDeleteChar=0x1F6;static const ecDeleteWord=0x1F7;
static const ecDeleteLastWord=0x1F8;static const ecDeleteBOL=0x1F9;static const ecDeleteEOL=0x1FA;
static const ecDeleteLine=0x1FB;static const ecClearAll=0x1FC;static const ecLineBreak=0x1FD;
static const ecInsertLine=0x1FE;static const ecChar=0x1FF;static const ecImeStr=0x226;
static const ecUndo=0x259;static const ecRedo=0x25A;static const ecCut=0x25B;
static const ecPaste=0x25C;static const ecBlockIndent=0x262;static const ecBlockUnindent=0x263;
static const ecTab=0x264;static const ecShiftTab=0x265;static const ecAutoCompletion=0x28A;
static const ecComment=0x28B;static const ecUnComment=0x28C;static const ecNextBlock=0x2BD;
static const ecPrevBlock=0x2BE;static const ecNextJumpOut=0x2BF;static const ecPrevJumpOut=0x2C0;
static const ecUserFirst=0x3E9;static const ecFind=0x3EA;static const ecReplace=0x3EB;
static const ecSearchAgain=0x3EC;static const ecFindAll=0x3ED;static const ecString=0x3EE;
static const ecSearchUpAgain=0x3EF;
end
type TCustomMemo = class(TCustomScrollControl,TCustomMemoCmd) //编辑器基类
{**
@explan(说明) 带滚动条的编辑控件 %%
**}
private
FSymchars;
[weakref]fongutterclick;//点击
[weakref]fonchanged;//文本改变
[weakref]foncaretposchanged;//光标位置改变
ftmemlockv;
fundoing; //清空unredo标记
fredoing; //清空unredo标记
fselectbkcolor;//rgb(192,192,192);
fcurrentLineColor;//rgb(232,232,255);
fguttercolor;
Fecruningto; //调试运行到行
FLineInterval; //行间距
FSetPostioned; //位置改变
FIsCaretShow; //光标可见
fcaretcreated; //光标已经构造成功
fForceCaret;
FCharsInWindow; //
fTextHeight; //行高
fLinesInWindow; //能显示的行数
fMaxCharsInRow; //行容纳字符数目
FCharHeight; //字符高度
FCharWidth; //字符宽度
FLeftChar; //左边隐藏的字符数
FTopLine; //首行
FScroolChanged; //滚动了
FGutterCharCount; //gutter 字符个数
Fautogutterwidth; //自动设置gutter宽度
FGutter; //gutter
FLines;
fLastCaretY; //最新y位置
//fCaretLineNeedPaint;
fCaretX; //光标位置
fCaretY; //光标位置
fBlockBegin:TPoint; //选中位置
fBlockEnd:TPoint; //选中位置
//FScrollTimer;
FMouseIsDown;
FInPutCache; //汉字输入缓存
FSelectionMode; //选中模式
[weakref]FCopyer; //剪切板
FReadOnly; //只读
fUndoList; //撤销
fRedoList; //反撤销
//******操作标记********
static const crInsert = 1;
static const crPaste = 2;
static const crDragDropInsert = 3;
static const crDeleteAfterCursor = 4;
static const crDelete = 5;
static const crLineBreak = 6;
static const crIndent = 6;
static const crUnindent = 7;
static const crSilentDelete = 8;
static const crSilentDeleteAfterCursor = 9;
static const crNothing = 10;
static const smNormal = 0;
static const smLine = 1;
static const smColumn = 2;
//****************
protected
{function SetControlFont(v);override;
begin
inherited;
FCharWidth := Font.width;
FGutter.Width := (5*(FGutterCharCount>0))+FGutterCharCount * FCharWidth+1;
FCharHeight := Font.Height;
fTextHeight := FCharHeight+FLineInterval;
UpDateScroll();
end}
function GetClientXCapacity();override; //宽度容量
begin
c := ClientRect;
return integer((c[2]-c[0])/GetXScrollDelta());
end
function GetClientYCapacity();override; //高度容量
begin
c := ClientRect;
return integer((c[3]-c[1])/GetYScrollDelta());
end
function GetClientXCount();override; //宽度间隔
begin
return integer((GetMaxCharsInRow()* FCharWidth+FGutter.Width)/GetXScrollDelta());
end
function GetYScrollDelta();virtual;
begin
return fTextHeight;
end
function GetXScrollDelta();virtual; //水平间隔
begin
return FCharWidth;
end
function GetClientYCount();virtual; //高度项
begin
h := fTextHeight * fLines.Length;
return integer(h/GetYScrollDelta());
end
function DoEndUpDate();override;
begin
if not(IsUpDating())then
begin
if FScroolChanged then
begin
FScroolChanged := false;
UpDateScroll();
end
if fForceCaret then
begin
fForceCaret := false;
UpDateCaret();
end
end
inherited;
end
function Paint();override;
begin
xpos := GetXpos();
ypos := GetYPos();
// 计算需要重绘的区域
ps := PAINTSTRUCT().rcPaint;
tp := ps[1];
bo := ps[3];
FirstLine := integer(max(0,yPos+(tp)/GetYScrollDelta()));
LastLine := integer(min(FLines.Length()-1,yPos+(bo)/GetYScrollDelta()));
if FGutterCharCount>0 and(ps[0]<FGutter.Width)then
begin
rc := ps;
rc[2]:= FGutter.Width;
PaintGutter(rc,FirstLine,LastLine);
end
if ps[2]>FGutter.Width then
begin
FirstCol := integer(max(0,xPos+(ps[0]-FGutter.Width)/GetXScrollDelta()));
LastCol := integer(min(GetMaxCharsInRow()-1,xPos+(ps[2]-FGutter.Width)/GetXScrollDelta()));
rc := ps;
rc[0]:= Max(rc[0],FGutter.Width);
//echo tostn(array(FirstLine, LastLine, FirstCol, LastCol));
cvs := Canvas;
cvs.Font := font;
bcvs := new TCanvsRgnClipAutoSave(cvs,rc);
PaintTextLines(RC,FirstLine,LastLine,FirstCol,LastCol);
end
PluginsAfterPaint(self.Canvas,ps,FirstLine,LastLine);
inherited;
end
function PaintGutter(rcDraw,nL1,nL2);
begin
dc := Canvas;
if ifnumber(FGutterColor) then
begin
c := FGutterColor;
end else
if ifobj(FGutterColor) then c := FGutterColor.color;
else c := rgb(228,228,228);
dc.brush.Color :=c ;//rgb(228,228,228);
rc := rcDraw;
rc[2]-= 6;
dc.FillRect(rc);
cvs := Canvas;
iy := 0;
cvs.Font := font;
//cvs.Font.Color := 1;
for i := nL1 to nL2 do
begin
r := rc;//rcDraw;
r[1]:= rcDraw[1]+fTextHeight * iy;
r[2]-= 4;
r[3]:= r[1]+fTextHeight;
it := flines[i];
if it and it.FMarked then
begin
dc.brush.Color := 0x12a4f6;//0xFF00FF;
tr := r;
tr[0]+= 1;
tr[1]+= 2;
tr[3]-= 4;
dc.FillRect(tr);
end
if i=Fecruningto then
begin
dc.brush.Color := 0x00ff00;
tr := r;
tr[2]+= 2;
tr[0]:= tr[2]-(tr[3]-tr[1]);
tr[1]+= 2;
tr[3]-= 2;
dc.draw("ellipse",array(tr[0:1],tr[2:3]))
end
cvs.DrawText(inttostr(i+1),r,DT_RIGHT);
iy++;
end
end
function PluginsAfterPaint(cvs,rcDraw,FirstLine,LastLine);
begin
end
function PaintTextLines(RC,FirstLine,LastLine,FirstCol,LastCol);//virtual;
begin
cvs := Canvas;
iy := 0;
cvs.TextTabLength := 1;
if fBlockBegin <> fBlockEnd and fBlockBegin and fBlockEnd then
begin
bb := GetBlockBegin();
ee := GetBlockEnd();
end
//rcs := rc;
//rcs := FGutter.width-(FLeftChar-1)*FCharWidth;
for i := FirstLine to LastLine do
begin
r := RC;
r[0]:= FGutter.width-(FLeftChar-1)* FCharWidth;
r[1]:= RC[1]+fTextHeight * iy;
iy++;
r[3]:= r[1]+fTextHeight;
if (i+1=fCaretY) and (fBlockBegin = fBlockEnd) then
begin
//echo tostn(array(fBlockBegin ,fBlockEnd));
if Color<>fcurrentLineColor then
begin
cvs.Brush.Color := fcurrentLineColor;//rgb(232,232,255);
cvs.FillRect(r);
end
end
if bb then
begin
if i >= bb[0]-1 and i <= ee[0]-1 then
begin
cvs.Brush.Color := fselectbkcolor;//rgb(192,192,192);
src := r;
if FSelectionMode=smLine then
begin
end else
begin
if bb[0]=ee[0]then //同一行
begin
src[0]+= fCharWidth *(bb[1]-1);
src[2]:= src[0]+fCharWidth *(ee[1]-bb[1]);
end else
begin
if bb[0]-1=i then
begin
src[0]+= fCharWidth *(bb[1]-1);
end
if ee[0]-1=i then
begin
src[2]:= src[0]+fCharWidth *(ee[1]-1);
end
end
end
cvs.FillRect(src);
end
end
end
paintlinestext(RC,FirstLine,LastLine,FirstCol,LastCol);
end
function DrawLongString(cvs,dtx,tl,r,rnzf);
begin
bn := 100000;
ft := cvs.Font;
if rnzf>tl then
begin
for i := 1 to tl step 2 do
begin
if bytetype(dtx,i)<> 0 then
begin
bn := ft.charset;
ft.charset := 134;
break;
end
end
cvs.DrawText(dtx,r,DT_NOPREFIX);
end else
begin
qmzfs := max(1,integer((0-r[0])/FCharWidth));
if qmzfs>3 and qmzfs<tl then
begin
if bytetype(dtx,qmzfs)=2 then qmzfs -= 1;
end
ct := min(tl-qmzfs+1,rnzf);
for i := qmzfs to qmzfs+ct step 2 do
begin
if bytetype(dtx,i)<> 0 then
begin
bn := ft.charset;
ft.charset := 134;
break;
end
end
dtx2 := copy(dtx,qmzfs,ct);
r[0]+=(qmzfs-1)* FCharWidth;
r[2]:= r[0]+ct * FCharWidth;
cvs.DrawText(dtx2,r,DT_NOPREFIX);
end
if bn <> 100000 then
begin
ft.charset := bn;
end
end
function paintlinestext(RC,FirstLine,LastLine,FirstCol,LastCol);virtual;
begin
cvs := canvas;
cvs.font := font;
crect := ClientRect;
rnzf := integer(crect[2]/FCharWidth)+10;
for i := FirstLine to LastLine do
begin
r := RC;
r[0]:= FGutter.width-(FLeftChar-1)* FCharWidth;
r[1]:= RC[1]+fTextHeight * iy;
iy++;
r[3]:= r[1]+fTextHeight;
dtx := fLines.GetStringByIndex(i);
tl := length(dtx);
DrawLongString(cvs,dtx,tl,r,rnzf);
end
end
function PositionChanged();virtual;
begin
tp := GetYpos();
flg := false;
if FTopLine <> tp+1 then
begin
FTopLine := tp+1;
flg .|= 1;
end
tp := GetXpos();
if tp+1 <> FLeftChar then
begin
FLeftChar := tp+1;
flg .|= 2;
end
if flg or FSetPostioned then
begin
//echo "\r\nupdate:",flg," ",datetimetostr(now());
UpdateCaret();
end
FSetPostioned := 0;
InvalidateRect(nil,false);
end
public //滚动刷新,构造
function IncPaintLock();
begin
BeginUpdate();
end
function DecPaintLock();
begin
EndUpdate();
end
function UpDateScroll();
begin
DoControlAlign();
end
Function DoControlAlign();override;
begin
if(IsUpDating())then
begin
FScroolChanged := true;
end else
begin
rc := ClientRect;
fCharsInWindow := integer((rc[2]-rc[0]-FGutter.width)/FCharWidth);
fLinesInWindow := integer((rc[3]-rc[1])/fTextHeight);
InitialScroll();
CaretXY := CaretXY;
UpdateCaret();
end
end
function Create(AOwner);override;
begin
inherited;
FSymchars := array();
ftmemlockv := new tcountkernel();
FGutterColor := rgb(228,228,228);
fcurrentLineColor := rgb(232,232,255);
fselectbkcolor := rgb(192,192,192);
FReadOnly := false;
FLineInterval := 4;
FGutterCharCount := 4;
Fautogutterwidth := false;
FSelectionMode := smNormal;
FGutter := new TMemoGutter(self);
FGutter.Width := 5+Font.Width * FGutterCharCount+1;
fLines := new TMemoLineList(self(true));
FInPutCache := 0;
fLines.Text := "";
AutoScroll := 3;
ThumbTrack := TRUE;
fMaxCharsInRow := 64; //128; //默认宽度
FCharHeight := Font.Height;
FCharWidth := Font.Width;
fTextHeight := FCharHeight+6;
rc := ClientRect;
fCharsInWindow := integer((rc[2]-rc[0])/FCharWidth);
fLinesInWindow := integer((rc[3]-rc[1])/fTextHeight);
FTopLine := 1;
FLeftChar := 1;
fCaretX := 1;
fCaretY := 1;
FSetPostioned := 0;
fBlockBegin := array(1,1);
fBlockEnd := array(1,1);
//*********************************
fUndoList := new TTslMenoUndoList();
fRedoList := new TTslMenoUndoList();
ParentFont := false;
end
function ClipCursor(); //固定光标区域
begin
FMouseIsDown := true;
crect := ClientRect;
ps := array(clienttoscreen(crect[0],crect[1]),clienttoscreen(crect[2],crect[3]));
_wapi.clipcursor(ps);
end
function UnClipCursor(); //解除固定区域
begin
if FMouseIsDown then
begin
FMouseIsDown := false;
_wapi.ClipCursor(0);
end
end
function ComputeAndSelToCaret(y,x);//计算光标位置
begin
xy := PixelsToRowColumn(x,y);
ExecuteCommand(ecSelGotoXY,xy);
end
function ClearSelBlock(); //清楚选中
begin
bg := BlockBegin;
ed := BlockEnd;
fBlockBegin := array(FCaretY,FCaretX);
fBlockEnd := array(FCaretY,FCaretX);
if (bg and ed) and bg<>ed then
begin
//InvalidateLines(bg[0],ed[0]);
InvalidateRect(nil,false);
end
end
function TrySetFoucs(); //设置focus
begin
if not FHasFocus then SetFocus();
end
function MouseMoveSel(x,y);//移动鼠标选择
begin
if FMouseIsDown then
begin
rc := ClientRect;
//x := e.xpos;
if x>rc[2]-5 then
begin
x +=FCharWidth+5;
end else
if x<5 then
begin
x-=FCharWidth-5;
end
//y := e.ypos;
if y>rc[3]-5 then
begin
y +=FCharWidth+5;
end else
if y<5 then
begin
y-=fTextHeight;
end
MoveCaretAndSelection(fBlockBegin,PixelsToRowColumn(x,y),true);
return ;
end
end
function MouseDown(o,e);override; //按下鼠标
begin
if ftmemlockv.locked then return ;
inherited;
if e.skip then return ;
IncPaintLock();
try
if e.Button() = mbLeft then
begin
if ssShift in e.Shiftstate() then
begin
ComputeAndSelToCaret(e.ypos,e.xpos);
end else
begin
x := e.xpos;
if fongutterclick and x>2 and x<(GutterWidth-10) then
begin
callgcall := true;
end
ComputeCaret(x,e.ypos);
ClearSelBlock();
ClipCursor();
end
TrySetFoucs();
UpDateCaret();
end else
if e.Button()=mbRight then
begin
ComputeCaret(e.xpos,e.ypos);
end
finally
DecPaintLock();
end ;
if callgcall then
begin
if fongutterclick then
begin
CallMessgeFunction(fongutterclick,o,e);
end
//echo "\r\n callgutter->:",CaretY;
end
end
function MouseMove(o,e);override;//移动
begin
return MouseMOVESel(e.xpos,e.ypos);
end
function WMIMECHAR(o,e):WM_IME_CHAR;//imechar处理,无用到
begin
return;
r := " ";
w := e.wparam;
msk :=(_shl(1,8)-1);
r[2]:= chr(w .& msk);
r[1]:= chr(_shr(w,8).& msk);
//echo r,"\r\n";
//ExecuteCommand(ecString,r);
//echo "\r\nime:",e.wparam;
end
function MouseUp(o,e);override;
begin
if ftmemlockv.locked then return ;
inherited;
if e.skip then return;
UnClipCursor();
end
function dosetfocus(o,e);override; //获得焦点
begin
FHasFocus := true;
CreateCaret();
UpDateCaret();
end
function dokillfocus(o,e);override; //失却焦点
begin
FHasFocus := false;
DestroyCaret();
end
function ReCreateCaret();
begin
if FHasFocus then
begin
DestroyCaret();
CreateCaret();
UpDateCaret();
end
end
function keypress(o,e);override; //输入字符
begin
if ftmemlockv.locked then return ;
if e.skip then return;
c := e.wparam;
if ReadOnly then return;
if c=13 then return CharInput("\r\n");
if c<32 and not(c in array(9))then return;
cc := e.char;
//if e.CharCode=VK_TAB then return inherited;
/////////////////处理特殊的gbk编码的字符比如:弢//20240429////////////////////////////
if FInPutCache then
begin
cc := FInPutCache+cc;
FInPutCache:=0;
end else
if (c .& 0x80)<> 0 then
begin
FInPutCache := cc;
return ;
end
CharInput(cc);
return inherited;
/////////////gbk汉字编码可能存在不全面/////////////////////////////////////
if(c .& 0x80)<> 0 then
begin
if FInPutCache then
begin
cc := FInPutCache+cc;
FInPutCache := 0;
CharInput(cc);
end else
begin
FInPutCache := cc;
return;
end
end else
begin
FInPutCache := 0; //修正char 猜可能出现问题
CharInput(cc);
end
inherited;
//////////////////////////////////////////////////
end
function InsertChars(s);virtual;//当前位置插入字符
begin
if not(ifstring(s) {and s})then return;
if SelAvail then
begin
SelText := s;
return;
end
if not s then return;
bb := array(fCaretY,fCaretX);
r := buffer_InsertChars(bb,s);
fUndoList.AddChange(crInsert,bb,r,s,0);
SetCaretXY(r);
UpdateCaret();
memtextchanged(bb);
end
function DoTextChanged(p);virtual;//文本改变
begin
//改变
if fonchanged then
begin
e := new tuieventbase(0,0,0,0);
CallMessgeFunction(fonchanged,self(true),e);
end
end
function DoCaretPosChanged();virtual;//caret位置改变
begin
if foncaretposchanged and ( fcaretcreated or ReadOnly) then
begin
e := new tuieventbase(0,0,0,0);
CallMessgeFunction(foncaretposchanged,self(true),e);
end
end
function ClearUndo(); //清空undo
begin
fUndoList.Clear();
fRedoList.Clear();
end
function ClearAll();//清空
begin
fLines.text := "";
FCaretX := FCaretY := 1;
fBlockBegin := array(1,1);
fBlockEnd := array(1,1);
ClearUndo();
memtextchanged(array(1,1));
end
function Undo();
begin
if fUndoList.CanUndo then
begin
lk := new tcountlocker(ftmemlockv);
try
UndoItem();
except
ClearUndo();
end
end
end
function Redo();
begin
if fRedoList.CanUndo then
begin
lk := new tcountlocker(ftmemlockv);
try
RedoItem();
except
ClearUndo();
end
end
end
function CharInput(c);virtual;//插入字符
begin
if not ReadOnly then return InsertChars(c);
end
function ExecuteCommand(cmd,data);override;//执行命令
begin
{**
@explan(说明) 执行操作 %%
@param(cmd)(TCustomMemoCmd) 操作码 %%
@param(data)(any) 操作码对应的数据 %%
**}
IncPaintLock();
try
case cmd of
"symchars":
begin
if ifstring(data) then
begin
FSymchars := array();
for i := 1 to length(data) do
begin
vi := data[i];
if vi= "\t" or vi="\r" or vi="\n" or vi="\b" then
begin
continue;
end
FSymchars[vi] := true;
end
return ;
end
r := "";
for i,v in FSymchars do r+=i;
return r;
end
"ecruningto":
begin
if Fecruningto <> data then
begin
Fecruningto := data;
InvalidateRect(nil,false);
end
end
ecTab:
begin
if ifstring(data)and data then
begin
b1 := BlockBegin;
b2 := BlockEnd;
endb := 1;
if ifarray(b1)and ifarray(b2)and b2[0]>b1[0]then
begin
odm := FSelectionMode;
FSelectionMode := smLine;
s := SelText;
ss := str2array(s,"\r\n");
ins := "";
len := length(ss)-1;
for i,v in ss do
begin
ins += data+v;
if i<len then ins += "\r\n";
else
begin
endb := length(v)+length(data)+1;
end
end
SelText := ins;
FSelectionMode := odm;
fBlockBegin := array(b1[0],1);
fBlockEnd := array(b2[0],endb);
end
end
end
ecShiftTab:
begin
if formatShiftTab(data)then
begin
b1 := BlockBegin;
b2 := BlockEnd;
if ifarray(b1)and ifarray(b2)and b2[0]>b1[0]then
begin
odm := FSelectionMode;
FSelectionMode := smLine;
s := SelText;
ss := str2array(s,"\r\n");
ins := "";
len := length(ss)-1;
endb := 1;
for i,v in ss do
begin
lv := length(v);
indata := false;
for idata,vdata in data do
begin
if pos(vdata,v)=1 then
begin
ldata := length(vdata);
if ldata=lv then
begin
end else
begin
ins += v[ldata+1:];
end
endb := lv-ldata+1;
indata := true;
break;
end
end
if not indata then
begin
ins += v;
endb := lv+1;
end
if i<len then ins += "\r\n";
end
if s=ins then return FSelectionMode := odm;
SelText := ins;
FSelectionMode := odm;
fBlockBegin := array(b1[0],1);
fBlockEnd := array(b2[0],endb);
end
end
end
ecClearAll:
begin
ClearAll();
end
ecLineBreak:
begin
InsertChars("\r\n");
end
ecEditorTop,ecSelEditorTop:
begin
MoveCaretAndSelection(array(fCaretY,fCaretX),array(1,1),ecSelEditorTop=cmd);
end
ecEditorBottom,ecSelEditorBottom:
begin
cn := array(fLines.length(),1);
cn[1]:= fLines[cn[0]-1].StrLength()+1;
MoveCaretAndSelection(array(fCaretY,fCaretX),cn,ecSelEditorBottom=cmd);
end
ecString:
begin
InsertChars(data);
end
ecLineEnd,ecSelLineEnd:
begin
s := fLines.GetStringByIndex(fCaretY-1); //[fCaretY-1];
if not ifstring(s)then return;
MoveCaretAndSelection(array(fCaretY,fCaretX),array(fCaretY,length(s)+1),ecSelLineEnd=cmd);
end
ecLineStart,ecSelLineStart:
begin
nx := 1;
//////////////20230323 回到非空白行首/////////////////////////////////
if FSelectionMode=smNormal then
begin
s := fLines.GetStringByIndex(fCaretY-1); //[fCaretY-1];
if ifstring(s) and s then
begin
for i := 1 to length(s) do
begin
vi := s[i];
if vi<>" " or vi="\t" then
begin
nx := i;
if fCaretX = nx then nx := 1;
break;
end
end
end
end
//////////////////////////////
MoveCaretAndSelection(array(fCaretY,fCaretX),array(fCaretY,nx),ecSelLineStart=cmd);
end
ecLeft,ecSelLeft:
begin
MoveCaretHorz(-1,ecSelLeft=cmd);
end
ecRight,ecSelRight:
begin
MoveCaretHorz(1,ecSelRight=cmd);
end
ecDown,ecSelDown:
begin
MoveCaretVert(1,cmd=ecSelDown);
end
ecUp,ecSelUp:
begin
MoveCaretVert(-1,cmd=ecSelUp);
end
ecPageTop,ecSelPageTop:
begin
MoveCaretAndSelection(self.CaretXY,array(fCaretY,FTopLine),cmd=ecSelPageTop);
end
ecPageDown:
begin
MoveCaretVert(GetClientYCapacity(),nil);
end
ecPageUp:
begin
MoveCaretVert(0-GetClientYCapacity(),nil);
end
ecGotoXY,ecSelGotoXY:
begin
MoveCaretAndSelection(GetCaretXY(),data,cmd=ecSelGotoXY);
end
ecWordLeft,ecSelWordLeft:
begin
nxy := PrevWordPos();
MoveCaretAndSelection(GetCaretXY(),nxy,cmd=ecSelWordLeft);
end
ecWordRight,ecSelWordRight:
begin
nxy := NextWordPos();
MoveCaretAndSelection(GetCaretXY(),nxy,cmd=ecSelWordRight);
end
ecSelectAll:
begin
SelectAll();
end
ecDeleteLastChar:
begin
if SelAvail then return SelText := "";
else
begin
ofsm := FSelectionMode;
FSelectionMode := smNormal;
SelectPrevChar();
SelText := "";
FSelectionMode := ofsm;
end
end
ecDeleteChar:
begin
if SelAvail then return SelText := "";
else
begin
ofsm := FSelectionMode;
FSelectionMode := smNormal;
SelectNextChar();
SelText := "";
FSelectionMode := ofsm;
end
end
ecDeleteLine:
begin
LL := fLines.Length();
if fCaretY=1 and LL=1 then
begin
SelectAll();
//ECHO "==",tostn(array(fBlockBegin,fBlockEnd));
SelText := "";
end else
if LL>1 then
begin
if fCaretY<LL then
begin
fBlockBegin := array(fCaretY,1);
fBlockEnd := array(fCaretY+1,1);
end else
begin
fBlockBegin := array(fCaretY-1,(fLines[fCaretY-2].StrLength())+1);
fBlockEnd := array(fCaretY,(fLines[fCaretY-1].StrLength())+1);
//echo tostn(array(fBlockBegin,fBlockEnd));
end
SelText := "";
//fLines.splices(fCaretY-1,1,array());
//SetCaretXY(array(fCaretY,1));
end
UpdateCaret();
end
ecUndo:
begin
Undo();
end
ecRedo:
begin
Redo();
end
ecCut:
begin
CutToClipboard();
end
ecPaste:
begin
PasteFromClipboard();
end
ecCopy:
begin
CopyToClipboard();
end
end
finally
DecPaintLock();
end;
end
function MoveCaretAndSelection(p1,p2,sel);//移动选择
begin
if not(ifarray(p2)and ifarray(p1)and p2[0]>= 1 and p2[1]>= 1)then return;
IncPaintLock();
SetCaretXY(p2);
if Sel then
begin
if not SelAvail then fBlockBegin := p1;
fBlockEnd := CaretXY;
InvalidateRect(nil,false); //20220729 修改刷新
{bg := GetBlockBegin();
ed := GetBlockEnd();
if ifarray(bg) and ifarray(ed) then
InvalidateLines(bg[0],ed[0]);}
end else
begin
if SelAvail then
begin
bg := GetBlockBegin()[0];
ed := GetBlockEnd()[0];
InvalidateLines(bg,ed);
end
fBlockBegin := CaretXY;
fBlockEnd := CaretXY;
end
UpDateCaret();
DecPaintLock();
end
published
property ReadOnly:bool read FReadOnly write setreadolny; //只读
property SelAvail read GetSelAvail;
property Text:text read GetMemoText write SetMemoText; //文本
property TopLine read FTopLine write SetTopLine; //首行
property LeftChar read FLeftChar write SetLeftChar;
property CharsInWindow:Integer read fCharsInWindow;
property LinesInWindow:Integer read fLinesInWindow;
property LineHeight read fTextHeight; //行高
property BlockBegin:TPoint read GetBlockBegin write SetBlockBegin;
property BlockEnd:TPoint read GetBlockEnd write SetBlockEnd;
property CaretX:Integer read fCaretX write SetCaretX;
property CaretY:Integer read fCaretY write SetCaretY;
property CaretXY:TPoint read GetCaretXY write SetCaretXY;
property SelText read GetSelText write SetSelTextExternal; //选中文本
property LineText:AnsiString read GetLineText write SetLineText; //当前行
property Lines read fLines; //文本集合
property SelectionMode read FSelectionMode write SetSelectionMode;
property GutterWidth read GetGutterWidth;
property LineInterval read FLineInterval write SetLineInterval;//行间距
property GutterCharCnt:integer read FGutterCharCount write SetGutterCharCnt;
property autogutterwidth:bool read Fautogutterwidth write setautogutterwidth;
property currentLineColor:color read fcurrentLineColor write setcurrentLineColor;
property guttercolor:color read fguttercolor write setguttercolor; //行标颜色
property selectbkcolor:color read fselectbkcolor write setselectbkcolor; //选中的颜色
property ongutterclick:eventhandler read fongutterclick write fongutterclick;
property onchanged:eventhandler read fonchanged write fonchanged;
property oncaretposchanged:eventhandler read foncaretposchanged write foncaretposchanged;
{**
@param(ReadOnly)(bool) 是否只读%%
@param(Text)(string) 文本%%
@param(CaretX)(integer) 光标x坐标%%
@param(CaretY)(integer) 光标y坐标%%
@param(SelText)(string) 选中的字符串%%
@param(LineText)(string) 当前行字符串%%
@param(GutterCharCnt)(integer) 行号的宽度%%
**}
public
function FontChanged(o);override;
begin
inherited;
ft := Font;
if not FGutter then return ;
FCharWidth := ft.width;
FGutter.Width := (5*(FGutterCharCount>0))+FGutterCharCount * FCharWidth+1;
FCharHeight := ft.Height;
fTextHeight := FCharHeight+FLineInterval;
ReCreateCaret();
UpDateScroll();
end
function UpDateCaret(); //更新光标
begin
if IsUpDating()then return fForceCaret := true;
fForceCaret := false;
if not fcaretcreated then return;
if HandleAllocated()then
begin
if fCaretX >= fLeftChar and(fCaretX<fCharsInWindow+fLeftChar)and FTopLine <= fCaretY and fCaretY<FTopLine+fLinesInWindow then
begin
_wapi.SetCaretPos(FGutter.Width+FCharWidth *(FCaretX-FLeftChar),(fTextHeight *(fCaretY-FTopLine)+3));
//_wapi.ShowCaret(self.Handle);
if not FIsCaretShow then
begin
_wapi.ShowCaret(self.Handle);
FIsCaretShow := true;
end
end else
begin
if FIsCaretShow then
begin
_wapi.HideCaret(self.Handle);
FIsCaretShow := false;
end
end
end
end
function InvalidateLines(FirstLine,LastLine:integer);virtual;//刷新行
begin
if not HandleAllocated()then return;
fy :=(FirstLine-FTopLine)* fTextHeight;
ly :=(LastLine-FTopLine+1)* fTextHeight;
r := ClientRect;
if ly<(r[1]-2) then return;
if fy>(r[3]+2) then return;
r[0]:= FGutter.Width;
r[1]:= max(0,fy);
r[3]:= min(r[3],ly);
InvalidateRect(r,false);
end
function DestroyHandle();override; //销毁句柄
begin
DestroyCaret();
FHasFocus := false;
inherited;
end
function MergeLastUndo(); //合并最近的两次操作
begin
fUndoList.MergeReplaceItem(); //
end
function Recycling();override;
begin
fongutterclick := nil;
inherited;
end
protected
function PrevWordPos(); //处理选择截断
begin
cy := FCaretY;
cx := FCaretX;
bx := cx;
if cy<1 then cy := 1;
if cy>fLines.Length()then cy := fLines.Length();
s := fLines[cy-1].FStr;
ls := length(s);
cx := min(ls+1,cx);
ci := 0;
while cx>1 do
begin
cx--;
//vi := s[cx];
//if FSymchars[vi] then continue;
//ivi := ord(vi);
ivi := getchar(s,cx);
{if (ivi<=0x2f) or (ivi>122 and ivi<=127) then
begin
ci++;
break;
end }
if if_c_sym(s,cx,ls,lx) then //处理中文符号
begin
cx++;
ci--;
break;
end
if(ivi<48)or(ivi>57 and ivi<65)or(ivi>90 and ivi<95)or(ivi>95 and ivi<97)or(ivi>122 and ivi <= 127)then
begin
ci++;
break;
end
end
rcx := cx+(ci?1:0);
if rcx=bx and rcx>1 then rcx--;
return array(cy,rcx);
end
function NextWordPos(); //处理选择截断
begin
cy := FCaretY;
cx := FCaretX;
if cy<1 then cy := 1;
if cy>fLines.Length()then cy := fLines.Length();
s := fLines[cy-1].FStr;
ls := length(s);
cx := min(ls+1,cx);
ci := 0;
while cx <= ls do
begin
//vi := s[cx];
//if FSymchars[vi] then continue;
//ivi := ord(vi);
ivi := getchar(s,cx);
//if (ivi<=0x2f) or (ivi>122 and ivi<=127) then break;
if if_c_sym(s,cx,ls) then //处理中文符号
begin
break;
end
if(ivi<48)or(ivi>57 and ivi<65)or(ivi>90 and ivi<95)or(ivi>95 and ivi<97)or(ivi>122 and ivi <= 127)then break;
ci++;
cx++;
end
return array(cy,cx+(ci?(0):1));
end
private //属性设置函数
function getclipboard();//获得clipbord
begin
if not FCopyer then
begin
FCopyer := new TcustomClipBoard(self);
end
end
function memtextchanged(p);
begin
if not(fundoing or fredoing) then
begin
fRedoList.Clear();
end
autosetgtwidth();
return DoTextChanged(p);
end
function setcurrentLineColor(c);
begin
if ifnumber(c) and c<>fcurrentLineColor then
begin
fcurrentLineColor := c;
r := carety;
InvalidateLines(r,r);
end
end
function setguttercolor(c);
begin
if ifnumber(c) and c<>fguttercolor then
begin
fguttercolor := c;
InvalidateRect(nil,false);
end
end
function setselectbkcolor(c);
begin
if c<>fselectbkcolor then
begin
fselectbkcolor := c;
b1 := BlockBegin;
b2 := BlockEnd;
if b1<>b2 then
begin
InvalidateRect(nil,false);
end
end
end
function setreadolny(n);
begin
nv := n?true:false;
if nv<>FReadOnly then
begin
FReadOnly := nv;
if FHasFocus then
begin
if FReadOnly then
begin
DestroyCaret();
end else
begin
CreateCaret();
UpDateCaret();
end
end
end
end
function SetLineInterval(n);
begin
if not(n>=0) then return n;
nn := integer(n);
if nn<>FLineinterval then
begin
FLineinterval := nn;
fTextHeight := FCharHeight+FLineInterval;
IncPAintLock();
UpDateScroll();
DecPaintLock();
end
end
function autosetgtwidth();//调整行号宽度
begin
if not Fautogutterwidth then return ;
n := Lines.Length();
nccnt := max(integer(n~10)+2,3);
if FGutterCharCount <> nccnt then
begin
SetGutterCharCnt(nccnt,true);
end
end
function setautogutterwidth(v);//设置自动调整宽度
begin
nv := v?true:false;
if nv<>Fautogutterwidth then
begin
Fautogutterwidth := nv;
if nv then
begin
autosetgtwidth();
end
end
end
function SetGutterCharCnt(n,f); //设置行号宽度
begin
if Fautogutterwidth and ifnil(f) then return ;
if not(n>=0 ) then return ;
nn := integer(n);
if nn<>FGutterCharCount then
begin
FGutterCharCount := nn;
FGutter.Width := (5*(FGutterCharCount>0))+FGutterCharCount*FCharWidth+1;
InValidateRect(nil,false);
end
end
function formatShiftTab(d);
begin
if ifarray(d)and d then
begin
for i,v in d do
begin
if not ifstring(v)then return 0;
if not v then return 0;
end
return true;
end
return 0;
end
function SelectAll(); //全选
begin
fBlockBegin := array(1,1);
fBlockEnd := fBlockBegin;
len := fLines.Length();
if len>0 then
begin
fBlockEnd := array(len,1+fLines[len-1].StrLength());
InvalidateRect(nil,false);
end else
end
function CopyToClipboard(); //复制选择
begin
r := GetSelText();
if r then
begin
getclipboard();
FCopyer.text := r;
return true;
end
end
function PasteFromClipboard();
begin
//if ReadOnly then return ;
getclipboard();
//s := FCopyer.Text;
//echo length(s),"\r\n";
if SelAvail then SelText := FCopyer.Text;
else InsertChars(FCopyer.Text);
end
function CutToClipboard();
begin
if SelAvail then
begin
s := SelText;
CopyToClipboard();
SelText := "";
//缓存
end
end
function SetSelectionMode(v);
begin
if(v <> FSelectionMode)and(v in array(smNormal,smLine))then FSelectionMode := v;
end
function MoveCaretHorz(stp,sel);
begin
if stp<0 and fCaretX <= 1 then return;
s := fLines[fCaretY-1].FStr;
if not ifstring(s)then return;
ls := length(s);
if stp>0 and fCaretX >= ls+1 then return;
nx := stp+fCaretX;
if stp>0 then
begin
if nx>ls then nx := ls+1;
else if bytetype(s,nx)=2 then nx := nx+1;
end else
begin
if nx <= 1 then nx := 1;
if bytetype(s,nx)=2 then nx -= 1;
end
MoveCaretAndSelection(array(fCaretY,fCaretX),array(fCaretY,nx),sel);
//UpdateCaret();
end
function MoveCaretVert(stp,sel);
begin
return MoveCaretAndSelection(array(fCaretY,fCaretX),array(max(1,fCaretY+stp),fCaretX),sel);
if SelAvail then
begin
bg := GetBlockBegin();
ed := GetBlockEnd();
fBlockBegin := CaretXY;
fBlockEnd := CaretXY;
InvalidateLines(bg[0],ed[0]);
end
//SetCaretXY(array(fCaretY+stp,fCaretX));
//UpdateCaret();
end
function GetGutterWidth();
begin
return FGutter.Width;
end
function UndoItem();
begin
item := fUndoList.PopItem();
if not item then return;
IncPaintLock();
tarr := array();
idx := 0;
while item do
begin
tarr[idx]:= item;
item := item.FLinkItem;
idx++;
end
for i := length(tarr)-1 downto 0 do
begin
fRedoList.AddChange(tarr[i]);
if i<idx-1 then
begin
fRedoList.MergeReplaceItem();
end
end
fUndoList.Lock();
fundoing := true;
for i := length(tarr)-1 downto 0 do
begin
item := tarr[i];
case item.FReason of
crInsert:
begin
//删除
fBlockBegin := item.FStartPos;
fBlockEnd := item.FEndPos;
SelText := "";
end
crDelete:
begin
//插入
SetCaretXY(item.FStartPos);
InsertChars(item.FStr);
//echo tostn(item);
end
end
end
fUndoList.UnLock();
fundoing := false;
DecPaintLock();
//处理
end
function RedoItem();
begin
item := fRedoList.PopItem();
if not item then return;
IncPaintLock();
tarr := array();
idx := 0;
while item do
begin
tarr[idx]:= item;
item := item.FLinkItem;
idx++;
end
fredoing := true;
for i := length(tarr)-1 downto 0 do
begin
item := tarr[i];
case item.FReason of
crInsert: //插入
begin
SetCaretXY(item.FStartPos);
InsertChars(item.FStr);
end
crDelete: //删除
begin
fBlockBegin := item.FStartPos;
fBlockEnd := item.FEndPos;
SelText := "";
end
end;
if i<idx-1 then
begin
fUndoList.MergeReplaceItem();
end
end
fredoing := false;
DecPaintLock();
end
function GetLineText();
begin
if fCaretY>0 and fCaretY <= fLines.Length()then return fLines.GetStringByIndex(fCaretY-1);
return "";
end
function SetLineText(s);
begin
if ifstring(s)and fCaretY>0 and fCaretY <= fLines.Length()then
begin
fLines.SetValueByIndex(fCaretY-1,s);
memtextchanged(array(fcarety,1));
//InvalidateLines(fCaretY-1,fCaretY-1);
end
end
function EnsureCursorPosVisible();
begin
IncPaintLock();
try
lct := max(1,LinesInWindow);
if FCaretX<LeftChar then
begin
LeftChar := FCaretX;
end else
if FCaretX>CharsInWindow+LeftChar-1 then
begin
LeftChar := FCaretX-CharsInWindow+1;
end
{if FCaretY < TopLine then
begin
TopLine := max(1,FCaretY-1); // -1
end
else if FCaretY > TopLine + Max(1, LinesInWindow) - 1 then
begin
TopLine := max(1,FCaretY - (LinesInWindow - 1)+1); //+1
end else
else
begin
//if fCaretLineNeedPaint then InvalidateLines(FCaretY,FCaretY);
fCaretLineNeedPaint := false;
end }
tl := TopLine;
vl := tl+lct;
if fCaretY >= tl and fCaretY <= vl then
begin
//fCaretLineNeedPaint := false;
end else
begin
TopLine := fCaretY;
end
finally
DecPaintLock();
end;
end
function GetCaretXY();
begin
return array(fCaretY,fCaretX);
end
function SetCaretXY(cxy);
begin
if not(ifarray(cxy)and cxy[0]>0 and cxy[1]>0)then return;
if cxy[0]>fLines.length()then cxy[0]:= fLines.Length();
cxy[1]:= Column2StrPos(cxy[0],cxy[1]);
docc := 0;
if cxy[1]<> fCaretX or cxy[0]<> fCaretY then
begin
IncPaintLock();
try
if fCaretX <> cxy[1]then
begin
docc := 1;
fCaretX := cxy[1];
end
if fCaretY <> cxy[0]then
begin
docc := 2;
fCaretY := cxy[0];
if fLastCaretY <> fCaretY then
begin
if fLastCaretY then InvalidateLines(fLastCaretY,fLastCaretY);
InvalidateLines(fCaretY,fCaretY);
end
fLastCaretY := fCaretY;
end
EnsureCursorPosVisible();
if docc then DoCaretPosChanged(); //之前在finally后
finally
DecPaintLock();
end;
end
end
function getcurrentselpos(pa,pb);
begin
pa := BlockBegin;
pb := BlockEnd;
end
function SetBlockBegin(p);
begin
if not(ifarray(p)and p[0]>0 and p[1]>0)then return;
np := p[0:1];
if np=fBlockBegin then return;
getcurrentselpos(bg,ed);
y := min(fLines.length(),p[0]);
x := Column2StrPos(y,p[1]);
fBlockBegin := array(y,x);
IncPaintLock();
if bg and ed and pg<>ed then
begin
InvalidateLines(bg[0],ed[0]);
end
getcurrentselpos(bg,ed);
if bg and ed and pg<>ed then
begin
InvalidateLines(bg[0],ed[0]);
end
DecPaintLock();
end
function SetBlockEnd(p);
begin
if not(ifarray(p)and p[0]>0 and p[1]>0)then return;
np := p[0:1];
if np=fBlockEnd then return;
getcurrentselpos(bg,ed);
y := min(fLines.length(),p[0]);
x := Column2StrPos(y,p[1]);
fBlockEnd := array(y,x);
IncPaintLock();
if bg and ed and pg<>ed then
begin
InvalidateLines(bg[0],ed[0]);
end
getcurrentselpos(bg,ed);
if bg and ed and pg<>ed then
begin
InvalidateLines(bg[0],ed[0]);
end
DecPaintLock();
//if fBlockBegin <> fBlockEnd then InvalidateRect(nil,false);
end
function ComputeCaret(X,Y:Integer);
begin
xy := PixelsToRowColumn(x,y);
SetCaretXY(xy);
end
function PixelsToRowColumn(x,y);
begin
r := max(1,min(fLines.Length(),FTopLine+Integer(y/fTextHeight)));
if x<FGutter.Width then
begin
c := 1;
end else
begin
c := Column2StrPos(r,Integer((x-FGutter.Width)/fCharWidth+0.4)+FLeftChar);
end
return array(r,max(1,c));
end
function Column2StrPos(r,c);
begin
rs := FLines.GetStringByIndex(r-1); //fLines[r-1].FStr;
if not ifstring(rs)then return 1;
if length(rs)+1<c then c := length(rs)+1;
case bytetype(rs,c)of
//1: return c+1;
2:return c+1;
end
return c;
end
function GetSelText();
begin
if not GetSelAvail()then return "";
bb := GetBlockBegin();
ee := GetBlockEnd();
return buffer_getchars(bb,ee,FSelectionMode);
end
function SetCaretX(cx);
begin
x := integer(cx);
if x<1 then return;
if x <> FCaretX then SetCaretXY(array(FCaretY,x));
end
function SetCaretY(cy);
begin
y := Integer(cy);
if y<1 then return;
if y <> FCaretY then SetCaretXY(array(y,FCaretX));
end
function SetLeftChar(v);
begin
if v <> FLeftChar and v>0 then
begin
FLeftChar := v;
FSetPostioned .|= 2;
SetXPos(FLeftChar-1);
end
end
function SetTopLine(TL);
begin
if TL <> FTopLine and TL>0 then
begin
FTopLine := TL;
FSetPostioned .|= 1;
SetYPos(FTopLine-1);
end
end
function GetSelAvail();
begin
return fBlockBegin <> fBlockEnd and fBlockBegin and fBlockEnd;
end
function SelectNextChar(); //选取后一个字符
begin
s := fLines.GetStringByIndex(fCaretY-1);
ls := length(s);
fBlockBegin := array(fCaretY,fCaretX);
fBlockEnd := array(fCaretY,fCaretX);
if fCaretX <= ls then
begin
bc := 1;
if bytetype(s,fCaretX)=1 then
begin
bc := 2;
end
fBlockEnd := array(fCaretY,fCaretX+bc);
end else
if fCaretY<fLines.Length()-1 then
begin
fBlockEnd := array(fCaretY+1,1);
end
end
function SelectPrevChar(); //选取前一个字符
begin
fBlockBegin := array(fCaretY,fCaretX);
if fCaretX>1 then
begin
s := fLines.GetStringByIndex(fCaretY-1);
bc := 1;
if bytetype(s,fCaretX-1)=2 then
begin
bc := 2;
end
fBlockEnd := array(fCaretY,fCaretX-bc);
//fBlockBegin := array(fCaretY, fCaretX-bc);
end else
if fCaretY>1 then
begin
s := fLines.GetStringByIndex(fCaretY-2);
fBlockEnd := array(CaretY-1,length(s)+1);
end
end
function SetSelTextExternal(v);
begin
if ifstring(v)and SelAvail then
begin
if SelText=v then return;
IncPaintLock();
ee := GetBlockEnd();
bb := DeleteSel();
up := false;
if bb[0]=ee[0]then
begin
//InvalidateLines(bb[0],bb[0]);
end else
begin
up := true;
end
if v then
begin
bb2 := buffer_InsertChars(bb,v);
fUndoList.AddChange(crInsert,bb,bb2,v,0);
fUndoList.MergeReplaceItem();
fBlockEnd := bb2;
if bb2[0]<> bb[0]then up := true;
end else
bb2 := bb;
ExecuteCommand(ecGotoXY,bb2);
//SetCaretXY(bb2);
//if up then UpDateScroll();
//UpDateCaret();
DecPaintLock();
memtextchanged(bb);
end
end
function DeleteSel(); //删除选择
begin
//if ReadOnly then return 0;
if not GetSelAvail()then return 0;
bb := GetBlockBegin();
ee := GetBlockEnd();
if FSelectionMode=smLine then
begin
bb[1]:= 1;
ee[1]:= fLines[ee[0]-1].StrLength()+1;
end
fUndoList.AddChange(crDelete,bb,ee,GetSelText(),0);
buffer_DeleteChars(bb,ee);
fBlockBegin := fBlockEnd := bb;
return bb;
end
function GetBlockBegin();
begin
if GetSelAvail()then
begin
if fBlockEnd[0]<fBlockBegin[0]or(fBlockEnd[0]=fBlockBegin[0]and fBlockEnd[1]<fBlockBegin[1])then return fBlockEnd;
else return fBlockBegin;
end
end
function GetBlockEnd();
begin
if GetSelAvail()then
begin
if fBlockEnd[0]<fBlockBegin[0]or(fBlockEnd[0]=fBlockBegin[0]and fBlockEnd[1]<fBlockBegin[1])then return fBlockBegin;
else return fBlockEnd;
end
end
function GetMemoText();
begin
return fLines.Text;
end
function SetMemoText(v);
begin
if not ifstring(v)then return;
IncPaintLock();
//FLines.Text := v;
ExecuteCommand(ecSelectAll);
ExecuteCommand(ecString,v);
ExecuteCommand(ecGotoXY,array(0,0));
DecPaintLock();
//UpDateScroll();
end
function GetMaxCharsInRow();
begin
if fMaxCharsInRow>5 then n := fMaxCharsInRow;
else n := 5;
//return((FLines.RowMaxLength/n)+0.5)* n;
return(ceil((FLines.RowMaxLength+1)/n))* n;
end
function CreateCaret(); //构造光标
begin
if FReadOnly then return;
if fcaretcreated then return;
h := Font.Height;
hd := Handle;
_wapi.CreateCaret(hd,nil,1,h);
_wapi.ShowCaret(hd);
fcaretcreated := true;
end
function DestroyCaret(); //销毁光标
begin
if fcaretcreated then
begin
_wapi.HideCaret(self.Handle);
_wapi.DestroyCaret();
end
fcaretcreated := false;
FIsCaretShow := false;
end
FHasFocus;
//buffer 处理
function buffer_getchars(bb,ee,sm);
begin
r := "";
if sm=smLine then
begin
len := ee[0];
for i := bb[0]to ee[0] do
begin
r += fLines[i-1].FStr;
if i<len then r += "\r\n";
end
end else
begin
if bb[0]=ee[0]then
begin
s := fLines[bb[0]-1].FStr;
if not s then return "";
bg := min(bb[1],ee[1]);
ed := max(bb[1],ee[1]);
if bg<ed then return s[bg:(ed-1)]; //2023078 出错
return "";
{if ee[1]>bb[1]and ee[1]>1 then
try
r := s[bb[1]:ee[1]-1]; //可能出错,添加try
except
r := "";
end;}
end else
begin
//第一行
s := fLines[bb[0]-1].FStr;
if bb[1]<= length(s)then r += s[bb[1]:];
r += "\r\n";
//中间
for i := bb[0]to ee[0]-2 do
begin
r += fLines[i].FStr;
r += "\r\n";
end
//最后一行
s := fLines[ee[0]-1].FStr;
if s and ee[1]>1 then r += s[1:ee[1]-1];
end
end
return r;
end
function buffer_DeleteChars(bb,ee,sm); //删除选择
begin
if bb=ee then return;
if bb[0]=ee[0]then //删除一行中的
begin
str := fLines.GetStringByIndex(bb[0]-1);
str[bb[1]:ee[1]-1]:= "";
fLines.SetValueByIndex(bb[0]-1,str);
end else //多行
begin
//删除后半
str := fLines.GetStringByIndex(bb[0]-1);
if str and length(str)>= bb[1]then str[bb[1]:]:= "";
//删除前半
str2 := fLines.GetStringByIndex(ee[0]-1);
if ee[1]>1 and str2 then str2[1:ee[1]-1]:= "";
fLines.SetValueByIndex(bb[0]-1,str+str2);
//删除中间
fLines.splices(bb[0],ee[0]-bb[0],array());
end
end
function buffer_InsertChars(cxy,str,sm); //插入
begin
if not(ifstring(str)and str)then return;
ss := str2array(str,"\n");
hs := array();
for i := 0 to length(ss)-1 do
begin
v := ss[i];
lv := length(v);
if v and v[lv]="\r" then v[lv:lv]:= "";
hs[i]:= v;
fLines.UpDateMaxStringLength(length(v));
end
cx := cxy[1];
cy := cxy[0];
lenss := length(ss)-1;
ncx := cx;
ncy := cy;
//插入的行
si := fLines.GetStringByIndex(cy-1);
lsi := length(si);
if ncx>1 then
begin
si1 := si[1:ncx-1];
if lsi >= ncx then si2 := si[ncx:];
else si2 := "";
end else
begin
si1 := "";
si2 := si;
end
if length(hs)=1 then
begin
fLines.SetStringByIndex(cy-1,si1+hs[0]+si2);
ncx := cx+length(hs[0]);
end else
begin
hs[0]:= si1+hs[0];
ncx := 1+length(hs[length(hs)-1]);
if si2 then hs[length(hs)-1]+= si2;
//ncx := 1;//length(hs[length(hs)-1]);
ncy += length(hs)-1;
hs1 := array();
for i,v in hs do hs1[i]:= new TMemoLineItem(v);
fLines.splices(cy-1,1,hs1);
end
return array(ncy,ncx);
end
end
type TSynCompletionList = class(TcustomListBox) //展示list
function Create(AOwner);override;
begin
inherited;
end
function CheckListItem(s);override;
begin
return true;
end
function GetItemText(i);override;
begin
r := GetItem(i);
if ifarray(r) then
begin
r := r["caption"];
if ifstring(r) then return r;
end
return r;
end
function ItemIndexInc(); //向下
begin
ItemIndex+=1;
idx := ItemIndex;
InsureItemVisible(idx);
end
function ItemIndexDec(); //向上
begin
ItemIndex-=1;
idx := ItemIndex;
InsureItemVisible(idx);
end
property ItemIndex read getCurrentSelection write SetCurrentSelection; //当前
private
function InsureItemVisible(idx); //移动当前的格子
begin
return InsureIdxInClient(idx);
end
end
type TSynCompletion = class(TSynCompletionList)
{**
@explan(说明) 语法提示自动完成 %%
**}
type TJumpPanel = class(TSynCompletionList) //跳转列表对象
function Create(AOwner);override;
begin
inherited;
FFilter := "";
color := rgb(230,230,220);
FIgnoreCase := true;
visible := false;
FJumpData := array();
end
function SetJumpData(s);
begin
FJumpData := s;
FFilter :="";
end
function Recycling();override;
begin
FJumpData := array();
OnJumpChoosed := nil;
inherited;
end
[weakref]OnJumpChoosed;
function CanJump(); //是否一跳转,可以跳转返回跳转的字符串
begin
p := parent;
if not p then return ;
s := p.CaretWords();
SetFilter(s);
if ItemCount>0 then return s;
return ;
end
function TryJump(s);//预备跳转
begin
p := parent;
if not p then return ;
if not ifstring(s) then
begin
s := p.CaretWords();
end
if not s then return ;
SetFilter(s);
ct := ItemCount;
if ct<1 then return ;
if ct = 1 then
begin
CallJump();
return;
end
mh := p.height;
w :=3+FCurrentWidth*GetXscrollDelta();
dh := GetYscrollDelta();
h := 3+dh*min(self.ItemCount,4);
p.GetCaretPos(x,y);
if y+h>mh then
begin
SetBoundsRect(array(x,y-h,x+w,y)) ;
end else
SetBoundsRect(array(x,y-dh,x+w,y+h-dh)) ;
Show();
end
function CallJump();
begin
visible := false;
it := GetItem(GetCurrentSelection());
if it then
begin
CallMessgeFunction(OnJumpChoosed,self.Owner,it);
end
end
function CancelJump(); //取消选中
begin
if Visible then Visible := false;
end
function MouseUp(o,e);override;
begin
inherited;
calljump();
end
function SetFilter(s);
begin
if not FJumpData then return ;
if not(ifstring(s) and s) then return ;
if FFilter= s then return ;
ls := lowercase(s);
lsl := length(ls);
if FIgnoreCase then
begin
cs := ls;
cindex := "lvalue";
if (lowercase(FFilter) = ls) then return ;
end else
begin
cs := s;
cindex := "value";
end
FFilter := s;
d := array();
ld :=0;
FCurrentWidth := 10;
for i,v in FJumpData do
begin
vi := v[cindex];
if vi= cs then
begin
d[ld++] := v;
FCurrentWidth := max(FCurrentWidth,v["clen"]);
end
end
SetData(d);
if d then
SetCurrentSelection(0);
else visible := false;
end
property IgnoreCase read FIgnoreCase Write SetIgnoreCase;
private
FCurrentWidth;
FIgnoreCase;
FJumpData;
FFilter;
function SetIgnoreCase(v);
begin
nv := v?true:false;
if nv<>FIgnoreCase then
begin
FIgnoreCase := nv;
end
end
end
function Create(AOwner);override;
begin
inherited;
fminmatch := 1;
fmatchfirst := true;
{$ifdef linuxpop} //处理避免闪烁
{$else}
WsPopUp := true;
{$endif}
FFilter := "";
FIgnoreCase := true;
visible := false;
FJump := new TJumpPanel(self);
end
function Mouseup(o,e);override;
begin
inherited;
FinishCompletion();
end
function PrepareCompletion(c);virtual; //获得数据
begin
//通过SetCompData 设置数据
if Not FMemo then return ;
s := FMemo.Text;
parseregexpr("[A-Zaz0-9_]+",s,"mi",mched,mchpos,mathlen);
r := array();
for ri,v in mched do
begin
v0 := v[0];
lv := lowercase(v0);
if r[lv] then continue;
r[lv] := v0;
end
d := array();
i := 0;
for lv,v in r do
begin
d[i,"caption"] := v;
d[i,"value"] := v;
d[i,"lvalue"] := lv;
cl := length(v);
d[i,"clen"] := cl;
d[i,"vlen"] := cl;
i++;
end
SetCompData(d);
end
function SetCompData(d);virtual;
begin
if FCompData = d then return ;
FCompData := array();
try
{ for i := 0 to length(d)-1 do
begin
viv := d[i,"value"];
vic := d[i,"caption"];
d["lvalue"] := lowercase(vic);
d["vlen"] := length(viv);
d["clen"] := length(vic);
end }
FCompData := select * from d order by ["vlen"],["order"] end;
JD := select * from d where ["jump"] end;
FJump.SetJumpData(JD);
except
FCompData := array();
end;
FFilter := "";
end
function TryCompletion(); //
begin
//查找字符
//存在就显示
//s := PrevWordPos
//SetFilter();
s := Memo.PrevWord();
sl := length(s);
if visible then
begin
if s and (sl>=fminmatch) then
begin
SetFilter(s);
end
else Visible := false;
end else
begin
if s and (sl>=fminmatch) then
begin
SetFilter(s);
if ItemCount>0 then
begin
mh := Memo.height;
w :=3+FCurrentWidth*GetXscrollDelta();
dh := GetYscrollDelta();
h := 3+dh*min(self.ItemCount,8);
Memo.GetCaretPos(x,y);
{$ifdef linuxpop}
xy := array(x,y);//
{$else}
xy := Memo.ClientToscreen(x,y);
{$endif }
if y+h>mh then
begin
begin
x := xy[0]; y := xy[1];
SetBoundsRect(array(x,y-dh-h-5,x+w,y-dh-5)) ;
end
end else
begin
x := xy[0]; y := xy[1];
SetBoundsRect(array(x,y,x+w,y+h));
end
Show(SW_SHOWNOACTIVATE);
//Visible := true;
//Memo.SetFocus(); //setfocus
end
end
end
end
function CancelCompletion();
begin
FJump.Visible := false;
visible := false;
end
function FinishCompletion();//完成
begin
if Visible then
begin
it := GetItem(self.ItemIndex);
if not it then return false ;
s := it["value"];
fl := length(FFilter);
ls := length(s);
if it["prefix"] then
begin
end else
begin
if {completedCase()}true then
begin
if s<>FFiltero and s and ls and fl then
begin
cxy := Memo.CaretXY;
cxy[1]-=fl;
Memo.ExecuteCommand(Memo.ecSelGotoXY,cxy);
Memo.ExecuteCommand(Memo.ecString,s);
end
end else
begin
if fl<ls then
begin
ips := s[fl+1:];
Memo.ExecuteCommand(Memo.ecString,ips);
end
end
end
visible := false;
exts := it["valueext"];
if ifstring(exts) and exts then
begin
extss := str2array(exts,"\r\n");
cxy := Memo.CaretXY;
cxy[1]-=fl;
if it["prefix"] then
Memo.ExecuteCommand(Memo.ecSelGotoXY,cxy);
kgct := cxy[1];
kgcts :="";
for i := 1 to kgct-1 do
begin
kgcts+=" ";
end
s := "";
for i,v in extss do
begin
if i=0 then
begin
s+=v;
end else
begin
s+=kgcts+v;
end
s+="\r\n";
{if i=0 and it["prefix"] then
begin
cxy := Memo.CaretXY;
cxy[1]-=fl;
Memo.ExecuteCommand(Memo.ecSelGotoXY,cxy);
Memo.ExecuteCommand(Memo.ecString,v);
end else
begin
Memo.ExecuteCommand(Memo.ecString,v);
end
Memo.InsertChars("\r\n");}
end
Memo.ExecuteCommand(Memo.ecString,s);
end
return true;
end
return false;
end
{function completedCase();virtual; //区分大小写
begin
return true;
end }
function SetFilter(s); //筛选
begin
if not FCompData then return ;
if not(ifstring(s) and s) then return ;
if FFilter = s then return ;
ls := lowercase(s);
lsl := length(ls);
FFiltero := s;
if FIgnoreCase then
begin
cs := ls;
cindex := "lvalue";
if (lowercase(FFilter) = ls) then return ;
end else
begin
cs := s;
cindex := "value";
end
FFilter := s;
d := array();
ld :=0;
wd := 10;
for i,v in FCompData do
begin
vi := v[cindex];
ps := pos(cs,vi);
if (fmatchfirst?(ps=1):(ps>=1)) then
begin
d[ld++] := v;
wd := max(wd,v["clen"]);
end
end
FCurrentWidth := min(1500,wd);
SetData(d);
if d then
SetCurrentSelection(0);
else visible := false;
end
function Recycling();override;
begin
SetMemo(nil);
inherited;
FCompData := array();
end
function TryJump(s); //跳转
begin
if Visible then Visible := false;
FJump.TryJump(s);
end
function CanJump(); //取消跳转
begin
return FJump.Canjump();
end
property Memo Read FMemo write SetMemo; //编辑器
property IgnoreCase read FIgnoreCase Write SetIgnoreCase; //忽略大小写
property OnJumpChoosed read GetJumpChoosed write SetJumpChoosed;
property matchfirst read fmatchfirst write fmatchfirst ;//匹配首字母
property minmatch read fminmatch write setminmatch ;//最小匹配长度
private
fminmatch;
fmatchfirst;
FCurrentWidth;
FCompData;
[weakref]FMemo;
FJump;
FIgnoreCase;
FFilter;
FFiltero;
private
function setminmatch(v);
begin
if v>=1 and v<>fminmatch then
begin
fminmatch := v;
end
end
function GetJumpChoosed();
begin
return FJump.OnjumpChoosed ;
end
function SetJumpChoosed(v);
begin
FJump.OnJumpChoosed := v;
end
function SetIgnoreCase(v);
begin
nv := v?true:false;
if nv<>FIgnoreCase then
begin
FIgnoreCase := nv;
FJump.IgnoreCase := nv;
end
end
function SetMemo(M);
begin
if M<>FMemo then
begin
tm := FMemo;
if tm then tm.Completion := nil;
FMemo := M;
IF M IS CLASS(TSynCustomMemo) then
begin
M.Completion:= self(true);
end else FMemo:= nil;
parent := FMemo;
FJump.Parent := FMemo;
//if FJump.Parent<>FMemo then FJump.Parent := FMemo;
end
end
end
type TSynHighLighter = class(TComponent) //语法高亮类型
public
hightercolor;
type thtcolor = class()
function create(cl);
begin
if cl>0 or cl<=0 then FColor := cl;
else FColor := 0;
end
property color read fcolor write fcolor;
private
fcolor;
end
Type TToken = class()
FValue; //值
FPos; //位置
FLen; //长度
FFColor; //颜色
FBKColor; //背景色
FMate; //伙伴,配对高亮
FFfacename;
FFCharset;
{static FTokenCount;
function Create();
begin
FTokenCount++;
end
function Destroy();
begin
FTokenCount--;
end }
end
function CreateAToken();virtual;
begin
return New TTOken();
end
function Create(AOwner);
begin
FCacheTokens := array();
inherited;
end
function SetInValidateIndex(idx); virtual; //当前改变的行
begin
if idx<=1 then
begin
return FCacheTokens := array();
end
ValidIndexs := array();
for i,v in FCacheTokens do
begin
if i>=idx-1 then
begin
ValidIndexs[i] := nil;
end
end
reindex(FCacheTokens,ValidIndexs);
end
function InsureTokenParserd(LastLine); virtual; //确保解析的行
begin
end
function GetLineTokens(ridx);virtual;
begin
if not Flines then return nil;
r := FCacheTokens[ridx];
if r then return r;
s := Flines.GetSTringByIndex(ridx);
if not ifstring(s) then return;
idx := 1;
len := length(s);
tks := array();
ctk :="";
while idx<= len do
begin
vi := s[idx];
if CharInSyn(vi)>0 then
begin
SetTToken(tks,ctk,idx-1);
SetTToken(tks,vi,idx);
end else
if pos(vi," \t")>0 then
begin
SetTToken(tks,ctk,idx-1);
end else
if if_c_sym(s,idx,len) then
begin
SetTToken(tks,ctk,idx-1);
ctk := s[idx:(idx+1)];
idx++;
SetTToken(tks,ctk,idx);
end else
begin
ctk+=vi;
end
idx++;
end
SetTToken(tks,ctk,idx-1);
FCacheTokens[ridx] := tks;
return tks;
end
function CharInSyn(v);virtual;
begin
if not(FSyns) then FSyns := "'~`!@#$%^&*()-+=[]{}|\\?/':;,.><"+'"';
return pos(v,FSyns);
end
function Clean();virtual;
begin
FCacheTokens := array();
end
function Recycling();virtual;
begin
SetMemo(nil);
inherited;
FCacheTokens := array();
end
property Memo read FMemo write SetMemo;
property lines read FLines;
protected
function SetTToken(tokens,ttk,idx,ext);virtual; //设置token
begin
if not ttk then return ;
lttk := length(ttk);
d := CreateAToken();
D.FValue := ttk;
d.FLen := lttk;
d.FPos := idx-lttk+1;
{
d.FFCharset := 0;
for i:= 2 to ttk step 2 do
begin
if bytetype(ttk,i)<>0 then
begin
d.FFCharset := 134;
break;
end
end }
tokens[length(tokens)] := d;
ttk := "";
return d;
end
private
FCacheTokens;
FSyns; //符号
function SetMemo(M);
begin
if Memo<>M then
begin
tfm := FMemo;
if tfm then tfm.Highlighter := nil;
FMemo := M;
if M is Class(TSynCustomMemo) then
begin
FMemo.Highlighter := self(true);
Flines := FMemo.Lines;
end else
begin
FMemo := nil;
Flines := nil;
end
//if tfm is Class(TSynCustomMemo) then tfm.Highlighter := nil;
SetInValidateIndex(1);
end
end
weakref
Flines;
FMemo;
autoref
end
type tcustomsynhighlighter = class(TSynHighLighter)
{**
@explan(说明) 通用的语法高亮类
支持单行注释,块注释,配对,字符串定义,关键字,符号%%
@data(20220915)
**}
function create(AOwner);
begin
inherited;
fsymcolor := 0xa000a0;
fnumbercolor := 0x666666;
fkeywordcolor := 0x0000ff;
fsysfuncolor := 0xff0000;
fstringcolor := 0xff00ff;
//fannotationcolor := 0xff0000;
fannotationcolor := 0xaa3300;
fignorecase := false;//忽略大小写
FChangeDeal := true;
FTokens := array();
fregs := array();
setkeyword(array("null","true","false","goto","break","for","to","while","do"));
setblockannote(array(
("/*","*/"),
));
setrowannote(array("//"));
setsyms(array("+","-","*","/",";","(",")","{","}",":"));
setstring(array(
("'","\\"),
('"',"\\"),
));
setpairs(array(
("(",")"),
("[","]"),
("{","}"),
));
setsysfun(array());
clean();
end
function ExecuteCommand(cmd,pm);override;
begin
{**
@explan(说明) 对外接口 %%
@param(cmd)(string) 命令%%
@param(pm)(array) 参数 %%
**}
case cmd of
"strings":
begin
return setstring(pm);
end
"rowannotes":
begin
return setrowannote(pm);
end
"blockannotes":
begin
return setblockannote(pm);
end
"keywords":
begin
return setkeyword(pm);
end
"syms":
begin
return setsyms(pm);
end
"sysfun":
begin
return setsysfun(pm);
end
"pairs":
begin
return setpairs(pm);
end
"regs":
begin
return setregs(pm);
end
"getcurrentpairstate":
begin
if fcbgestate then
begin
return fcbgestate[pm];
end
return nil;
end
end ;
return inherited;
end
function SetInValidateIndex(idx);override; //当前改变的行
begin
idx := max(1,idx);
fdolastline := idx-2;
if not(FChangeDeal)and idx>FSatesCount then return;
if length(FSates)>= idx then FSatesCount := idx;
else FSatesCount := length(FSates)-1;
if FSatesCount=1 then clean();
FChangeDeal := false;
end
function InsureTokenParserd(LastLine);override; //解析
begin
ls := Lines;
FChangeDeal := true;
if fdolastline>=LastLine then return ;
fdolastline := LastLine;
if hightercolor then
begin
fsymcolor := hightercolor.symcolor();
fnumbercolor := hightercolor.numcolor();
fkeywordcolor := hightercolor.keycolor();
fsysfuncolor := hightercolor.sysfunccolor();
fstringcolor := hightercolor.strcolor();
fannotationcolor := hightercolor.commentcolor();
end
for i := FSatesCount-1 to LastLine do
begin
if i<0 then continue;
s := ls.GetStringByIndex(i);
cst := FSates[i];
tks := array();
fcbgestate := array();
for jj,j in mrows(Fbgedstates,1) do
begin
v := Fbgedstates[j][i];
vj := v.Clone;
fcbgestate[j]:= vj;
Fbgedstates[j][i+1]:= vj;
end
FSates[i+1]:= ParserTokenLines(s,1,length(s),cst,tks);
FSatesCount := i+1;
FTokens[i]:= tks;
end
end
function GetLineTokens(idx);override;
begin
if idx<FSatesCount then return FTokens[idx];
end
function SetTToken(tokens,ttk,idx,ext);override; //设置token
begin
bttk := ttk;
d := inherited;
if not d then return ;
if not ext then
begin
if ifkeywords(bttk) then
begin
d.FFColor := fkeywordcolor;
end else
if ifsysfun(bttk) then
begin
d.FFColor := fsysfuncolor ;
end else
begin
dereg(d,bttk);
end
dopair(d,bttk);
end else
if ifarray(ext) then
begin
if ext[0]="str" then
begin
d.FFColor := fstringcolor;
end else
if ext[0] = "annote" then
begin
d.FFColor := fannotationcolor;
end else
if ext[0]= "sym" then
begin
d.FFColor := fsymcolor;
dopair(d,bttk);
end
end
return d;
end
function clean();override; //初始化
begin
FTokens := array();
FSates := array(0);
Fbgedstates := array();
FSatesCount := 0;
for i,v in fswordpairs do
begin
Fbgedstates[i,0]:= new tpairstate(i);
end
inherited;
end
property keywordcolor:color read fkeywordcolor write fkeywordcolor;
property sysfuncolor:color read fsysfuncolor write fsysfuncolor;
property stringcolor:color read fstringcolor write fstringcolor;
property annotationcolor:color read fannotationcolor write fannotationcolor;
property symcolor:color read fsymcolor write fsymcolor;
property numbercolor:color read fnumbercolor write fnumbercolor;
property ignorecase:bool read fignorecase write setignorecase;
private
function setignorecase(i);
begin
ni := i?true:false;
if ni<>FIgnoreCase then
begin
FIgnoreCase := ni;
for i,v in array(fstrstires ,
fkeystires,
fblockstiresa,
fblockstiresb,
frowstires,
fsysfuntires,
fsymstires) do
begin
for j,vj in v do
begin
vj.ignorecase := ni;
end
end
if fswordpairshashdata then
begin
td := fswordpairshashdata;
setpairs(td);
end
end
end
function dereg(d,ttk);
begin
for i,v in fregs do
begin
if parseregexpr(i,ttk,"",r,mp,ml)=1 then
begin
d.FFColor := v;
return ;
end
end
end
function dopair(d,bttk); //处理配对信息
begin
if FIgnoreCase then
begin
lttk := lowercase(bttk);
end else
begin
lttk := bttk;
end
n := fswordpairshash[lttk];
if n then
begin
st := fcbgestate[n];
if fswordpairs[n,2] then
begin
if st.state then
begin
st.GetRight();
end else
begin
st.GetLeft();
end
end else
begin
if fswordpairs[n][1]=lttk then
begin
st.GetRight();
end else
begin
st.GetLeft();
end
end
d.FMATe := st.GetSate();
end
end
function ParserTokenLines(s,b,e,cst,tokens); //解析字符
begin
label L_XCDG;
if cst=0 then //普通情况
begin
idx := b;
ttk := "";
while idx <= e do
begin
vi := s[idx];
if vi=" " or vi="\t" then //分隔符
begin
SetTToken(tokens,ttk,idx-1);
end else
if ifrowannote(s,e,idx,oidx,ostr) then
begin
SetTToken(tokens,ttk,idx-1);
bostr := ostr;
SetTToken(tokens,ostr,oidx-1,array("annote",bostr));
if oidx<=e then
begin
SetTToken(tokens,s[oidx:],e,array("annote",bostr));
end
return 0;
end else
if ifblockannote(s,e,idx,oidx,ostr) then //查找块注释
begin
SetTToken(tokens,ttk,idx-1);
bostr := ostr;
ncost := array("annote",bostr,fblockstiresb[bostr]);
SetTToken(tokens,ostr,oidx-1,array("annote"));
idx := oidx-1;
return ParserTokenLines(s,idx+1,e,ncost,tokens);
end else
if ifstringstart(s,e,idx,oidx,ostr) then //查找字符串
begin
SetTToken(tokens,ttk,idx-1);
bostr := ostr;
ncost := array("str",bostr,fstrstires[bostr],fstrstires_zy[bostr]);
SetTToken(tokens,ostr,oidx-1,ncost);
idx := oidx-1;
return ParserTokenLines(s,idx+1,e,ncost,tokens);
end else
if ifdefsym(s,e,idx,oidx,ostr) then //符号
begin
SetTToken(tokens,ttk,idx-1);
SetTToken(tokens,ostr,oidx-1,array("sym",ostr));
idx := oidx-1;
end else
begin
ttk+=vi;
end
idx++;
end
SetTToken(tokens,ttk,idx-1);
end else //查找
begin
if b>e then return cst;
if ifarray(cst) and (cst[0]="str" or cst[0]="annote") then
begin
r := FindRightChar(cst[2],s,b,e,cst[3]);
if r=0 then //没找到
begin
Setttoken(tokens,s[b:],e,cst);
return cst;
end else //找到
if r <= e then
begin
if b<r then
begin
Setttoken(tokens,s[b:r-1],r-1,cst);
end
if cst[0]="annote" then
begin
cstL := fblockstiresc[cst[1]];
end else
begin
cst1 := cst[1];
cstL := length(cst1);
end
Setttoken(tokens,s[r:(r-1+cstL)],(r-1+cstL),cst);
if r<e then
begin
//消除递归
b := r+cstL;
cst := 0;
goto L_XCDG;
//return ParserTokenLines(s,r+1,e,0,tokens); //递归方式
end
end
end
end
end
function setstring(d); //设置字符串信息
begin
fstrstires := array();
fstrstires_zy := array();
if not ifarray(d) then return ;
for i,v in d do
begin
if not ifarray(v) then continue;
v0 := v[0];
v1 := v[1];
if ifstring(v0) and v0 then
begin
st := new TTire();
fstrstires[v0] := st;
st.add(v0);
fstrstires_zy[v0] := v1;
end
end
end
function setkeyword(ws); //设置关键字
begin
st := new TTire();
for i,v in ws do
begin
if v and ifstring(v) then st.add(v);
end
fkeystires := array(st);
end
function setblockannote(d); //设置块注释
begin
fblockstiresa := array();
fblockstiresb := array();
fblockstiresc := array();
if not ifarray(d) then return ;
for i,v in d do
begin
if not ifarray(d) then continue ;
v0 := v[0];
v1 := v[1];
if ifstring(v0) and ifstring(v1) and v0 and v1 then
begin
st := new TTire();
st.add(v0);
fblockstiresa[v0] := st;
st := new TTire();
st.add(v1);
fblockstiresb[v0] := st;
fblockstiresc[v0] := length(v1);
end
end
end
function setrowannote(d);//设置行注释
begin
frowstires := array();
if not ifarray(d) then return ;
for i,v in d do
begin
if v and ifstring(v) then
begin
st := new TTire();
frowstires[v] := st;
st.add(v);
end
end
end
function setsysfun(d);//设置系统函数
begin
st := new TTire();
fsysfuntires := array(st);
if not ifarray(d) then return ;
for i,v in d do
begin
if ifstring(v) and v then
begin
st.add(v);
end
end
end
function setsyms(d);//设置符号
begin
st := new TTire();
fsymstires := array(st);
for i,v in d do
begin
if ifstring(v) and v then
begin
st.add(v);
end
end
end
function setregs(d);
begin
fregs := array();
for rg,v in d do
begin
if ifnil(v) then continue;
if not(rg and ifstring(rg)) then continue;
fregs[rg] := v
end
end
function setpairs(d);//设置配对
begin
fswordpairs := array();
fswordpairshash := array();
fswordpairshashdata := array();
if not ifarray(d) then return ;
for i,v in d do
begin
if not ifarray(v) then continue;
v0 := v[0];
v1 := v[1];
if FIgnoreCase then
begin
v0 := lowercase(v0);
v1 := lowercase(v1);
end
if ifstring(v0) and ifstring(v1) and v0 and v1 then
begin
fswordpairs[v1,0]:= v0;
fswordpairs[v1,1]:= v1;
fswordpairs[v1,2] := (v0=v1);
fswordpairshash[v0]:=v1;
fswordpairshash[v1]:=v1;
fswordpairshashdata[i] := v;
end
end
end
function cyclefind(cys,s,l,idx,oidx,ostr,tidx);
begin
r := 0;
if not ifarray(cys) then return r;
for i,v in cys do //字符串
begin
if v.find(s,l,idx,oidx,ostr) then
begin
r := 1;
tidx := i;
break;
end
end
return r;
end
function ifblockannote(s,l,idx,oidx,ostr,tidx);//是否为块注释
begin
return cyclefind(fblockstiresa,s,l,idx,oidx,ostr,tidx);
end
function ifrowannote(s,l,idx,oidx,ostr,tidx);//是为
begin
return cyclefind(frowstires,s,l,idx,oidx,ostr,tidx);
end
function ifstringstart(s,l,idx,oidx,ostr,tidx); //字符串判断
begin
return cyclefind(fstrstires,s,l,idx,oidx,ostr,tidx);
end
function ifkeywords(s);//关键字判断
begin
for i,v in fkeystires do
begin
if v.find(s,length(s),1,idx,ostr) and (ostr=s) then
return true;
end
end
function ifsysfun(s);//系统函数判断
begin
for i,v in fsysfuntires do
begin
if v.find(s,length(s),1,idx,ostr) and (ostr=s) then
return true;
end
end
function ifdefsym(s,l,idx,oidx,ostr,tidx); //符号判断
begin
return cyclefind(fsymstires,s,l,idx,oidx,ostr,tidx);
end
function FindRightChar(vo,s,b,e,zy); //查找封闭的字符
begin
i := b;
if not vo then return 1;
while i <= e do
begin
si := s[i];
if si=zy then
begin
i += 2;
if i>e then return 0;
continue;
end
if vo.find(s,e,i,oidx,ostr) then
begin
return i;
end
i++;
end
return 0; //没找到
end
private
FSatesCount ;// 状态行号
FChangeDeal;//改变flag
fignorecase; //忽略大小写
//前后匹配
Fbgedstates;
fcbgestate;//当前匹配
///
FSates; //当前状态
FTokens;
fdolastline; //已经处理到行
///////tire树/////////////
fkeystires;
fstrstires;
fstrstires_zy;
fsymstires;
fsysfuntires;
frowstires;
fblockstiresa;
fblockstiresb;
fblockstiresc;
fregs;
/////
fkeywordcolor;
fsysfuncolor;
fstringcolor;
fannotationcolor;
fsymcolor;
fnumbercolor;
//
fswordpairs;
fswordpairshash;
fswordpairshashdata;
end
type TSynCustomMemo = class(TCustomMemo)
{**
@explan(说明) 语法编辑器 %%
**}
function DoTextChanged(p);override;//文本改变
begin
inherited;
if Highlighter then
Highlighter.SetInValidateIndex(p[0]);
end
function MouseUp(o,e);override;
begin
inherited;
if e.Button() = mbRight then
begin
CallMessgeFunction(OnRClick,o,e);
end
end
function ExecuteCommand(cmd,data);override;
begin
case cmd of
ecLeft:
begin
if data=1 then
begin
xy := CaretXY;
y := xy[0];
x := xy[1];
if x=1 and y>1 then
begin
s := Lines.GetStringByIndex(y-2);
if ifstring(s) then
return ExecuteCommand(ecGotoXY,array(y-1,length(s)+1));
end
end
end
ecRight:
begin
if data=1 then
begin
xy := CaretXY;
y := xy[0];
if y<Lines.Length() then
begin
x := xy[1];
s := Lines.GetStringByIndex(y-1);
if ifstring(s) and (length(s)+1=x) then
begin
return ExecuteCommand(ecGotoXY,array(y+1,1));
end
end
end
end
ecDeleteLastChar:
begin
if data = 1 then
begin
tc := TabChar;
x := CaretX;
ltc := length(tc);
if x>ltc then
begin
s := LineText;
if tc = s[x-ltc:x-1] then
begin
ExecuteCommand(ecSelGotoXY,array(CaretY,x-ltc));
SelText:="";
return ;
end
end
end
return inherited ExecuteCommand(ecDeleteLastChar);
end
end
return inherited;
end
function PrepareCompletion(c);//准备完成
begin
if Completion then return Completion.PrepareCompletion(c);
end
function TryCompletion();//提示
begin
if Completion then return Completion.TryCompletion();
end
function TryJump(s); //跳转
begin
if Completion then return CompLEtion.TryJump(s);
end
function Canjump(); //是否可以跳转到当前字符串
begin
if Completion then return Completion.Canjump();
end
function FinishCompletion(); //完成填充
begin
if Completion and Completion.Visible then return Completion.FinishCompletion();
end
function CancelCompletion(); //取消填充
begin
if Completion then return Completion.CancelCompletion();
end
function CharInput(c);override; //字符输入
begin
if ReadOnly then return ;
if c="\r\n" then
begin
if FinishCompletion() then //确定键
begin
return ;
end else
begin
return inherited;
end
end else
if c="\t" then
begin
b1 := BlockBegin;
b2 := BlockEnd;
if ifarray(b1) and ifarray(b2) and b2[0]>b1[0] then return ExecuteCommand(ectab,FTabChar);
else return inherited CharInput(FTabChar);
end
inherited;
if Completion then
begin
Completion.TryCompletion();
end
end
function Completioning(); //正在准备填充
begin
return Completion and Completion.Visible;
end
function PrevWord(); //前一个词语
begin
p := PrevWordPos();
ls := Lines;
s := ls.GetStringByIndex(p[0]-1);
sl := length(s);
cx := CaretX;
cw := "";
if p[1]<=sl and cx>p[1] then
begin
cw := s[p[1]:cx-1];
cw := trim(cw);
end;
return cw;
end
function CaretWords(); //光标所在词语
begin
e := NextWordPos();
b := PrevWordPos();
ls := Lines;
s := Lines[b[0]-1];
r := "";
if s then
begin
try
s := s.FStr;
for i:= b[1] to e[1]-1 do
begin
ivi := ord(s[i]);
if(ivi<48) or (ivi>57 and ivi<65) or (ivi>90 and ivi<95) or(ivi>95 and ivi<97) or(ivi>122 and ivi<=127) then continue;
r+=s[i];
end
except
r := "";
end;
end
return r;
end
function Create(AOwner);//构造
begin
inherited;
FCOMPOSITIONFORM := new tagCOMPOSITIONFORM(nil);
FTabChar := " ";
end
function Recycling();override; //回收
begin
if FHighlighter then
begin
FHighlighter.Clean();
SetHighlighter(nil);
end
if FCompletion then
begin
SetCompletion(nil);
end
inherited;
end
function paintlinestext(RC, FirstLine, LastLine, FirstCol, LastCol); override;
begin
if not Highlighter then return inherited;
cvs := canvas;
bfontname := cvs.font.facename;
bfc := cvs.Font.color;
Highlighter.InsureTokenParserd(LastLine);
cw := GetXScrollDelta();
//********************处理**************************************8
bb := BlockBegin;
ee := BlockEnd;
if ifarray(bb) and ifarray(ee) and bb[0]=ee[0] and bb[1]<ee[1] then
begin
selt := SelText;
selbx := bb[1];
selby := bb[0];
end
if selt then
begin
selt := lowercase(selt);
tks := Highlighter.GetLineTokens(selby-1);
for i,v in tks do
begin
if v.FPos=selbx then
begin
seltcj := v.FMate;
break;
end
end
IF seltcj then
begin
Selt := 0;
end
end
crect := ClientRect;
rnzf := integer(crect[2]/cw)+20;
//***************************************************************************************
for i := FirstLine to LastLine do
begin
tks := Highlighter.GetLineTokens(i);
r := RC;
r0 := GutterWidth-(LeftChar-1)*cw;
r[1] := RC[1]+LineHeight*iy;
r[3] := r[1]+LineHeight;
iy++;
//r[3] := r[1]+LineHeight;
for j,v in tks do
begin
val := v.FValue;
vallength := length(val);
r[0] := r0+(v.FPos-1)*cw;
r[2] := r[0]+vallength*cw;
if r[2]<crect[0] then
begin
continue;
end
if r[0]>crect[2] then
begin
break;
end
c := V.FFColor;
if ifobj(c) then c := c.color;
if ifnil(c) then c := bfc;
fn := v.FFfacename;
//bfontname := cvs.font.facename;
cvs.Font.bkmode := TRANSPARENT;
if fn then
begin
cvs.Font.Facename := fn;
end else
begin
cvs.font.facename := bfontname;
end
if (c>0) then
begin
cvs.Font.Color := c;
end
else cvs.Font.Color := bfc;
if (selt and selt = lowercase(val))or(seltcj and seltcj=v.FMate) then
begin
cvs.Font.bkColor := selectbkcolor;//0xFFE2B0;
cvs.Font.bkmode := OPAQUE;
end
DrawLongString(cvs,val,vallength,r,rnzf);
//cvs.DrawText(val,r,DT_NOPREFIX);
end
end
cvs.font.facename := bfontname;
cvs.Font.Color := bfc;
cvs.Font.bkmode := TRANSPARENT;
end
function GetCaretPos(x,y);//获得光标位置
begin
y := (CaretY-GetYpos())*GetYScrollDelta();
x := (CaretX-GetXpos())*GetXScrollDelta();
end
published
property Highlighter:thighlighter read FHighlighter write SetHighlighter; //语法高亮
property Completion read FCompletion write SetCompletion; //自动完成
property TabChar read FTabChar write SetTabChar;
public //输入法相关
function WMIMESTARTCOMPOSITION(o,e):WM_IME_STARTCOMPOSITION;virtual;
begin
ime := ImmGetContext(self.Handle);
FCOMPOSITIONFORM.ptcurrentpos.cx := 200;
FCOMPOSITIONFORM.ptcurrentpos.cy := 200;
ImmSetCompositionWindow(ime,FCOMPOSITIONFORM._getptr_());
ImmReleaseContext(self.Handle,ime);
end
{$ifdef linux}
function ImmReleaseContext();
begin
end;
function ImmGetContext();
begin
end;
function ImmSetCompositionWindow();
begin
end;
function ImmSetStatusWindowPos();
begin
end;
{$else}
function ImmReleaseContext(h:pointer;ime:pointer):integer;stdcall;external "Imm32.dll" name "ImmReleaseContext";
function ImmGetContext(h:pointer):pointer;stdcall;external "Imm32.dll" name "ImmGetContext";
function ImmSetCompositionWindow(h:pointer;s:pointer):integer;stdcall;external "Imm32.dll" name "ImmSetCompositionWindow";
function ImmSetStatusWindowPos(h:pointer;s:pointer):integer;stdcall;external "Imm32.dll" name "ImmSetStatusWindowPos";
{$endif}
private
FCOMPOSITIONFORM;
FHighlighter;
FCompletion;
FTabChar;
function SetTabChar(s);
begin
if FTabChar<>s and s and ifstring(s) then
begin
FTabChar := s;
end
end
function SetHighlighter(v);
begin
if FHighlighter <>v then
begin
tv := FHighlighter;
FHighlighter := nil;
if tv is class(TSynHighLighter) then
begin
tv.Memo := nil;
end
FHighlighter := v;
if v is Class(TSynHighLighter) THEN
begin
v.Memo := self(true);
end else FHighlighter := nil;
InvalidateRect(nil,false);
end
end
function SetCompletion(v);
begin
if FCompletion<>v then
begin
tv := FCompletion ;
FCompletion := nil;
if tv is class(TSynCompletion) then
begin
tv.Memo := nil;
end
FCompletion := v;
if v is class(TSynCompletion) then
begin
v.Memo := self(true);
end else FCompletion := nil;
end
end
end
type TSynMemoNorm = class(TsynCustomMemo) //添加了常用快捷键的编辑器框
function Create(AOwner);override;
begin
inherited;
end
function keypress(o,e);override;
begin
if e.CharCode =VK_TAB then
begin
if FSheetTabFlage then return ;
end
inherited;
end
function KeyDown(o,e);override; //按键处理
begin
inherited;
if e.skip then return ;
FSheetTabFlage := false;
if ssCtrl in e.shiftstate then
begin
CancelCompletion();
case e.charcode of
ord("A") :
begin
ExecuteCommand( ecSelectAll);
end
ord("C"):
begin
ExecuteCommand(ecCopy);
end
ord("V"):
begin
if ReadOnly then return ;
ExecuteCommand(ecPaste);
end
ord("X"):
begin
//if (ssAlt in e.shiftstate) then return ExecuteCommand(ecRedo);
if ReadOnly then return ;
ExecuteCommand(ecCut);
end
ord("Y"),ord("L"):
begin
if ReadOnly then return ;
return ExecuteCommand(ecDeleteLine);
end
ord("Z"):
begin
if ReadOnly then return ;
return ExecuteCommand(ecUndo);
end
ord("U"):
begin
if ReadOnly then return ;
return ExecuteCommand(ecRedo);
end
VK_LEFT:
begin
if ssShift in e.shiftstate then return ExecuteCommand(ecSelWordLeft);
return ExecuteCommand(ecWordLeft);
end
VK_RIGHT:
begin
if ssShift in e.shiftstate then return ExecuteCommand(ecSelWordRight);
return ExecuteCommand(ecWordRight);
end
VK_END:
begin
if ssShift in e.shiftstate then return ExecuteCommand(ecSelEditorBottom);
return ExecuteCommand(ecEditorBottom);
end
VK_HOME:
begin
if ssShift in e.shiftstate then return ExecuteCommand(ecSelEditorTop);
return ExecuteCommand(ecEditorTop);
end
end ;
return ;
end
if ssShift in e.shiftstate then
begin
CancelCompletion();
case e.CharCode of
VK_TAB:
begin
if ReadOnly then return ;
FSheetTabFlage := true;
return ExecuteCommand(ecShifttab,array(TabChar,"\t"," "));
end
VK_DOWN:
begin
return ExecuteCommand(ecSelDown);
end
VK_END :
begin
return ExecuteCommand(ecSelLineEnd);
end
VK_HOME :
Begin
return ExecuteCommand(ecSelLIneStart);
end
VK_UP:
begin
return ExecuteCommand(ecSelUp);
end
VK_LEFT: ExecuteCommand(ecSelLeft);
VK_RIGHT: ExecuteCommand(ecSelRight);
end;
return ;
end
case e.CharCode of
34:
begin
return ExecuteCommand(ecPageDown,nil);
end
33:
begin
return ExecuteCommand(ecPageUp,nil);
end
VK_HOME:
begin
ExecuteCommand(ecLineStart);
return CancelCompletion();
end
VK_END:
begin
ExecuteCommand(ecLineEnd);
return CancelCompletion();
end
VK_LEFT:
begin
ExecuteCommand(ecLeft,1);
return CancelCompletion();
end
VK_RIGHT:
begin
ExecuteCommand(ecRight,1);
return CancelCompletion();
end
VK_UP:
begin
if Completioning() then return Completion.ItemIndexdec();
ExecuteCommand(ecUp);
end
VK_DOWN:
begin
if Completioning() then return Completion.ItemIndexinc();
return ExecuteCommand(ecDown);
end
VK_DELETE:
begin
if ReadOnly then return ;
ExecuteCommand(ecDeleteChar);
return CancelCompletion();
end
VK_BACK :
begin
if ReadOnly then return ;
ExecuteCommand(ecDeleteLastChar,1);
return CancelCompletion();
end
end;
end
function MouseDown(o,e);override;
begin
if e.button=mbLeft and e.shiftdouble then
begin
ExecuteCommand(ecWordLeft);
ExecuteCommand(ecSelWordRight);
end else
inherited;
CancelCompletion();
end
function DoMouseWheel(o,e);override;
begin
IF ssCtrl in e.shiftstate then
begin
fw := font.Width;
hw := font.height;
flg := false;
//echo "\r\n:",fw,"--",font.Height;
if e.delta<0 then
begin
if fw>7 then
begin
if fw=18 then
begin
fw := 17;
hw := 34;
end
flg := true;
font := array("width":fw-1,"height":hw-2);
end
end else
begin
if fw<18 then
begin
if fw=16 then
begin
fw := 17;
hw := 34;
end
flg := true;
font := array("width":fw+1,"height":hw+2);
end
end
e.skip := true;
return;
end
inherited;
end
private
FSheetTabFlage;
end
Implementation
function if_c_sym(s,idx,len,lx);//是否为中文符号
begin
if lx then //倒序
begin
if not(idx<=len) then return 0;
if idx<2 then return 0;
if ByteType(s,idx)<>2 then return 0;
c1 := getchar(s,idx-1);
c2 := getchar(s,idx);
end else //正序
begin
if not(idx<len ) then return 0;
if ByteType(s,idx)<>1 then return 0;
c1 := getchar(s,idx);
c2 := getchar(s,idx+1);
end
symv := static array(161,162,163,161,163,164,163,168,163,169,161,164,161,190,161,191,163,186,161,176,161,177,161,174,163,187,161,163,163,172);
for i:=0 to length(symv)-1 step 2 do
begin
if c1=symv[i] and c2=symv[i+1] then
begin
return 1;
end
end
end
function CreateATslMemoUndoItem(AReason,AStart,AEnd,ChangeText,SelMode);
begin
return new TTslMemoUndoItem(AReason,AStart,AEnd,ChangeText,SelMode);
end
InitialIzation
end.