mwcustomedit.pas
来自「本人买的<<VC++项目开发实例>>源代码配套光盘.」· PAS 代码 · 共 1,920 行 · 第 1/5 页
PAS
1,920 行
function TmwCustomEdit.GetBlockEnd: TPoint;
begin
Result := fBlockEnd;
if fBlockEnd.Y < fBlockBegin.Y then Result := fBlockBegin else
if fBlockEnd.Y = fBlockBegin.Y then
if fBlockEnd.X < fBlockBegin.X then Result := fBlockBegin;
end;
function TmwCustomEdit.GetCaretX: Integer;
begin
Result := fCaretX + 1;
end;
function TmwCustomEdit.CaretXPix: Integer;
begin
Result := fCaretX * fCharWidth + fTextOffset;
end;
function TmwCustomEdit.GetCaretY: Integer;
begin
Result := fCaretY + 1;
end;
function TmwCustomEdit.CaretYPix: Integer;
begin
Result := fCaretY * fTextHeight - fTopLine * fTextHeight + 1;
end;
procedure TmwCustomEdit.FontChanged(Sender: TObject);
begin
RecalcCharExtent;
SizeOrFontChanged(TRUE);
end;
function TmwCustomEdit.GetFont: TFont;
begin
Result := inherited Font;
end;
function TmwCustomEdit.GetLineCount: Integer;
begin
Result := Lines.Count;
end;
function TmwCustomEdit.GetLeftChar: Integer;
begin
Result := fLeftChar + 1;
end;
function TmwCustomEdit.GetLineText: string;
begin
Result := '';
if (Lines.Count > 0) and (fCaretY < Lines.Count) then
Result := Lines[fCaretY];
end;
function TmwCustomEdit.GetSelAvail: Boolean;
begin
Result := (fBlockBegin.X <> fBlockEnd.X) or
((fBlockBegin.Y <> fBlockEnd.Y) and (fSelectionMode <> smColumn));
end;
function TmwCustomEdit.GetSelText: string;
function CopyPadded(const S: string; Index, Count: integer): string;
var
SrcLen: Integer;
DstLen: integer;
P: PChar;
begin
SrcLen := Length(S);
DstLen := Index + Count;
if SrcLen >= DstLen then
Result := Copy(S, Index, Count)
else begin
SetLength(Result, DstLen);
P := PChar(Result);
StrPCopy(P, Copy(S, Index, Count));
Inc(P, Length(S));
FillChar(P^, DstLen - Srclen, $20);
end;
end;
procedure CopyAndForward(const S: string; Index, Count: Integer; var P:
PChar);
var
pSrc: PChar;
SrcLen: Integer;
DstLen: Integer;
begin
SrcLen := Length(S);
if (Index <= SrcLen) and (Count > 0) then begin
Dec(Index);
pSrc := PChar(S) + Index;
DstLen := Min(SrcLen - Index, Count);
Move(pSrc^, P^, DstLen);
Inc(P, DstLen);
P^ := #0;
end;
end;
procedure CopyPaddedAndForward(const S: string; Index, Count: Integer;
var P: PChar);
var
OldP: PChar;
Len: Integer;
begin
OldP := P;
CopyAndForward(S, Index, Count, P);
Len := Count - (P - OldP);
FillChar(P^, Len, #$20);
Inc(P, Len);
end;
const
sLineBreak = #$0D#$0A;
var
First, Last, TotalLen: Integer;
ColFrom, ColTo: Integer;
I: Integer;
{$IFDEF MWE_MBCSSUPPORT}
l, r: Integer;
s: string;
{$ELSE}
ColLen: integer;
{$ENDIF}
P: PChar;
begin
if not SelAvail then
Result := ''
else begin
with BlockBegin do begin
ColFrom := X;
First := Y - 1;
end;
with BlockEnd do begin
ColTo := X;
Last := Y - 1;
end;
TotalLen := 0;
case SelectionMode of
smNormal:
if (First = Last) then
Result := Copy(Lines[First], ColFrom, ColTo - ColFrom)
else begin
// step1: calclate total length of result string
TotalLen := Max(0, Length(Lines[First]) - ColFrom + 1);
for i := First + 1 to Last - 1 do
Inc(TotalLen, Length(Lines[i]));
Inc(TotalLen, ColTo - 1);
Inc(TotalLen, Length(sLineBreak) * (Last - First));
// step2: build up result string
SetLength(Result, TotalLen);
P := PChar(Result);
CopyAndForward(Lines[First], ColFrom, MaxInt, P);
CopyAndForward(sLineBreak, 1, MaxInt, P);
for i := First + 1 to Last - 1 do begin
CopyAndForward(Lines[i], 1, MaxInt, P);
CopyAndForward(sLineBreak, 1, MaxInt, P);
end;
CopyAndForward(Lines[Last], 1, ColTo - 1, P);
end;
smColumn:
begin
if ColFrom > ColTo then
SwapInt(ColFrom, ColTo);
// step1: calclate total length of result string
{$IFNDEF MWE_MBCSSUPPORT}
ColLen := ColTo - ColFrom;
TotalLen := ColLen + (ColLen + Length(sLineBreak)) * (Last - First);
// step2: build up result string
SetLength(Result, TotalLen);
P := PChar(Result);
for i := First to Last - 1 do begin
CopyPaddedAndForward(Lines[i], ColFrom, ColLen, P);
CopyAndForward(sLineBreak, 1, MaxInt, P);
end;
CopyPaddedAndForward(Lines[Last], ColFrom, ColLen, P);
{$ELSE} //MWE_MBCSSUPPORT
for i := First to Last do begin
s := Lines[i];
l := ColFrom;
r := ColTo;
MBCSGetSelRangeInLineWhenColumnSelectionMode(s, l, r);
Inc(TotalLen, r - l);
end;
Inc(TotalLen, Length(sLineBreak) * (Last - First));
// step2: build up result string
SetLength(Result, TotalLen);
P := PChar(Result);
for i := First to Last - 1 do begin
s := Lines[i];
l := ColFrom;
r := ColTo;
MBCSGetSelRangeInLineWhenColumnSelectionMode(s, l, r);
CopyPaddedAndForward(s, l, r - l, P);
CopyAndForward(sLineBreak, 1, MaxInt, P);
end;
s := Lines[Last];
l := ColFrom;
r := ColTo;
MBCSGetSelRangeInLineWhenColumnSelectionMode(s, l, r);
CopyPaddedAndForward(Lines[Last], l, r - l, P);
{$ENDIF}
end;
smLine:
begin
// If block selection includes LastLine,
// line break code(s) of the last line will not be added.
// step1: calclate total length of result string
for i := First to Last do
Inc(TotalLen, Length(Lines[i]) + Length(sLineBreak));
if Last = Lines.Count then
Dec(TotalLen, Length(sLineBreak));
// step2: build up result string
SetLength(Result, TotalLen);
P := PChar(Result);
for i := First to Last - 1 do begin
CopyAndForward(Lines[i], 1, MaxInt, P);
CopyAndForward(sLineBreak, 1, MaxInt, P);
end;
CopyAndForward(Lines[Last], 1, MaxInt, P);
if (Last + 1) < Lines.Count then
CopyAndForward(sLineBreak, 1, MaxInt, P);
end;
end;
end;
end;
function TmwCustomEdit.GetText: string;
begin
Result := Lines.Text;
end;
function TmwCustomEdit.GetTopLine: Integer;
begin
Result := fTopLine + 1;
end;
procedure TmwCustomEdit.HideCaret;
begin
if mwsfCaretVisible in fStateFlags then
if Windows.HideCaret(Handle) then Exclude(fStateFlags, mwsfCaretVisible);
end;
{$IFDEF MWE_MBCSSUPPORT}
procedure TmwCustomEdit.WMImeComposition(var Msg: TMessage);
var
imc: HIMC;
p: PChar;
begin
if ((Msg.LParam and GCS_RESULTSTR) <> 0) then begin
imc := ImmGetContext(Handle);
try
fImeCount := ImmGetCompositionString(imc, GCS_RESULTSTR, nil, 0);
GetMem(p, fImeCount + 1);
try
ImmGetCompositionString(imc, GCS_RESULTSTR, p, fImeCount + 1);
p[fImeCount] := #0;
CommandProcessor(ecImeStr, #0, p);
finally
FreeMem(p, fImeCount + 1);
end;
finally
ImmReleaseContext(Handle, imc);
end;
end;
inherited;
end;
procedure TmwCustomEdit.WMImeNotify(var Message: TMessage);
var
imc: HIMC;
logFont: TLogFont;
begin
with Message do begin
case WParam of
IMN_SETOPENSTATUS:
begin
imc := ImmGetContext(Handle);
if (imc <> 0) then begin
GetObject(Font.Handle, SizeOf(TLogFont), @logFont);
ImmSetCompositionFont(imc, @logFont);
ImmReleaseContext(Handle, imc);
end;
end;
end;
end;
inherited;
end;
{$ENDIF}
procedure TmwCustomEdit.IncPaintLock;
begin
inc(fPaintLock);
end;
procedure TmwCustomEdit.InvalidateGutter(FirstLine, LastLine: integer);
var
rcInval: TRect;
begin
if Visible and HandleAllocated then
if (FirstLine = -1) and (LastLine = -1) then begin
rcInval := Rect(0, 0, fGutterWidth, ClientHeight);
if mwsfLinesChanging in fStateFlags then
UnionRect(fInvalidateRect, fInvalidateRect, rcInval)
else
InvalidateRect(Handle, @rcInval, FALSE);
end else begin
{ find the visible lines first }
if (LastLine < FirstLine) then SwapInt(LastLine, FirstLine);
FirstLine := Max(FirstLine, TopLine);
LastLine := Min(LastLine, TopLine + LinesInWindow);
{ any line visible? }
if (LastLine >= FirstLine) then begin
rcInval := Rect(0, fTextHeight * (FirstLine - TopLine),
fGutterWidth, fTextHeight * (LastLine - TopLine + 1));
if mwsfLinesChanging in fStateFlags then
UnionRect(fInvalidateRect, fInvalidateRect, rcInval)
else
InvalidateRect(Handle, @rcInval, FALSE);
end;
end;
end;
procedure TmwCustomEdit.InvalidateLines(FirstLine, LastLine: integer);
var
rcInval: TRect;
begin
if Visible and HandleAllocated then
if (FirstLine = -1) and (LastLine = -1) then begin
rcInval := ClientRect;
rcInval.Left := fGutterWidth;
if mwsfLinesChanging in fStateFlags then
UnionRect(fInvalidateRect, fInvalidateRect, rcInval)
else
InvalidateRect(Handle, @rcInval, FALSE);
end else begin
{ find the visible lines first }
if (LastLine < FirstLine) then SwapInt(LastLine, FirstLine);
FirstLine := Max(FirstLine, TopLine);
LastLine := Min(LastLine, TopLine + LinesInWindow);
{ any line visible? }
if (LastLine >= FirstLine) then begin
rcInval := Rect(fGutterWidth, fTextHeight * (FirstLine - TopLine),
ClientWidth, fTextHeight * (LastLine - TopLine + 1));
if mwsfLinesChanging in fStateFlags then
UnionRect(fInvalidateRect, fInvalidateRect, rcInval)
else
InvalidateRect(Handle, @rcInval, FALSE);
end;
end;
end;
procedure TmwCustomEdit.KeyDown(var Key: Word; Shift: TShiftState);
var
Data: pointer;
C: char;
Cmd: TmwEditorCommand;
begin
inherited;
// OnKeyDown is already called in ancestor
Data := nil;
C := #0;
try
Cmd := TranslateKeyCode(Key, Shift, Data);
if Cmd <> ecNone then begin
Key := 0; // eat it.
CommandProcessor(Cmd, C, Data);
end;
finally
if Data <> nil then
FreeMem(Data);
end;
end;
procedure TmwCustomEdit.Loaded;
begin
inherited Loaded;
GutterChanged(Self);
end;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?