Files
2021-03-16 20:12:46 +01:00

261 lines
8.2 KiB
ObjectPascal

{-------------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: SynMemo.pas, released 2000-04-07.
The Original Code is based on mwCustomEdit.pas by Martin Waldenburg, part of
the mwEdit component suite.
Portions created by Martin Waldenburg are Copyright (C) 1998 Martin Waldenburg.
Unicode translation by Maël Hörz.
All Rights Reserved.
Contributors to the SynEdit and mwEdit projects are listed in the
Contributors.txt file.
Alternatively, the contents of this file may be used under the terms of the
GNU General Public License Version 2 or later (the "GPL"), in which case
the provisions of the GPL are applicable instead of those above.
If you wish to allow use of your version of this file only under the terms
of the GPL and not to allow others to use your version of this file
under the MPL, indicate your decision by deleting the provisions above and
replace them with the notice and other provisions required by the GPL.
If you do not delete the provisions above, a recipient may use your version
of this file under either the MPL or the GPL.
$Id: SynMemo.pas,v 1.15.2.3 2008/09/14 16:25:03 maelh Exp $
You may retrieve the latest version of this file at the SynEdit home page,
located at http://SynEdit.SourceForge.net
Known Issues:
- several EM_XXX messages aren't handled yet;
- EM_XXX messages aren't implemented on CLX, although this could be useful;
-------------------------------------------------------------------------------}
unit SynMemo;
{$I SynEdit.inc}
interface
uses
RichEdit,
Windows,
Messages,
SynEdit,
SynEditTextBuffer,
SynEditTypes,
SysUtils,
Classes;
type
TSynMemo = class(TSynEdit)
private
// EM_XXX see winuser.h (PSDK August 2001)
procedure EMGetSel(var Message: TMessage); message EM_GETSEL;
procedure EMSetSel(var Message: TMessage); message EM_SETSEL;
procedure EMGetModify(var Message: TMessage); message EM_GETMODIFY;
procedure EMSetModify(var Message: TMessage); message EM_SETMODIFY;
procedure EMGetLineCount(var Message: TMessage); message EM_GETLINECOUNT;
procedure EMGetSelText(var Message: TMessage); message EM_GETSELTEXT; //richedit.h
procedure EMReplaceSel(var Message: TMessage); message EM_REPLACESEL;
procedure EMGetLine(var Message: TMessage); message EM_GETLINE;
procedure EMCanUndo(var Message: TMessage); message EM_CANUNDO;
procedure EMUndo(var Message: TMessage); message EM_UNDO;
procedure EMGetFirstVisibleLine(var Message: TMessage); message EM_GETFIRSTVISIBLELINE;
procedure EMCharFromPos(var Message: TMessage); message EM_CHARFROMPOS;
end;
implementation
uses
{$IFDEF SYN_COMPILER_18_UP}
AnsiStrings,
{$ENDIF}
{$IFDEF UNICODE}
WideStrUtils,
{$ENDIF}
SynUnicode,
SynEditMiscProcs;
{ TSynMemo }
// EM_GETSEL
// wParam = (WPARAM) (LPDWORD) lpdwStart; // receives starting position
// lParam = (LPARAM) (LPDWORD) lpdwEnd; // receives ending position
procedure TSynMemo.EMGetSel(var Message: TMessage);
var
s, e: Integer;
begin
s := GetSelStart;
e := GetSelEnd;
if Message.wParam <> 0 then PDWORD(Message.wParam)^ := s;
if Message.lParam <> 0 then PDWORD(Message.lParam)^ := e;
Message.Result := MakeLong(s, e)
end;
// EM_SETSEL
// wParam = (WPARAM) (INT) nStart; // starting position
// lParam = (LPARAM) (INT) nEnd; // ending position
procedure TSynMemo.EMSetSel(var Message: TMessage);
begin
SetSelStart(Message.wParam);
SetSelEnd(Message.lParam);
end;
procedure TSynMemo.EMSetModify(var Message: TMessage);
begin
Modified := Message.wParam <> 0;
end;
procedure TSynMemo.EMGetModify(var Message: TMessage);
begin
Message.Result := Integer(Modified);
end;
procedure TSynMemo.EMGetLineCount(var Message: TMessage);
begin
//(WPARAM) wParam, // not used; must be zero
//(LPARAM) lParam // not used; must be zero
Message.Result := Lines.Count;
end;
procedure TSynMemo.EMGetSelText(var Message: TMessage);
begin
if Message.lParam <> 0 then
begin
if IsWindowUnicode(Handle) then
WStrLCopy(PWideChar(Message.lParam), PWideChar(SelText), Length(SelText))
else
{$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLCopy(PAnsiChar(Message.lParam), PAnsiChar(AnsiString(SelText)), Length(SelText));
Message.Result := Length(SelText);
end;
end;
// EM_REPLACESEL
// fCanUndo = (BOOL) wParam ; // flag that specifies whether replacement can be undone
// lpszReplace = (LPCTSTR) lParam ; // pointer to replacement text string
// see PasteFromClipboard CF_TEXT - use common function ?
// or use SetSelText/SetSelTextPrimitive (no undo)
procedure TSynMemo.EMReplaceSel(var Message: TMessage);
var
StartOfBlock: TBufferCoord;
EndOfBlock: TBufferCoord;
begin
if ReadOnly then Exit;
DoOnPaintTransient(ttBefore);
BeginUndoBlock;
try
if SelAvail and (Message.WParam <> 0){???} then
UndoList.AddChange(crDelete, BlockBegin, BlockEnd, SelText, SelectionMode);
StartOfBlock := BlockBegin;
EndOfBlock := BlockEnd;
BlockBegin := StartOfBlock;
BlockEnd := EndOfBlock;
LockUndo;
try
if IsWindowUnicode(Handle) then
SelText := PWideChar(Message.lParam)
else
SelText := UnicodeString(PAnsiChar(Message.lParam))
finally
UnlockUndo;
end;
if (Message.WParam <> 0){???} then
UndoList.AddChange(crPaste, StartOfBlock, BlockEnd, SelText, smNormal);
finally
EndUndoBlock;
end;
EnsureCursorPosVisible;
// Selection should have changed...
StatusChanged([scSelection]);
DoOnPaintTransient(ttAfter);
end;
// wParam = line number
// lParam = line string (PAnsiChar/PWideChar)
// no terminating #0
procedure TSynMemo.EMGetLine(var Message: TMessage);
var
DestAnsi, SourceAnsi: PAnsiChar;
DestWide, SourceWide: PWideChar;
begin
if {$IFNDEF SYN_COMPILER_16_UP}(Message.WParam >= 0) and {$ENDIF}(Integer(Message.WParam) < Lines.Count) then
begin
if IsWindowUnicode(Handle) then
begin
DestWide := PWideChar(Message.LParam);
SourceWide := PWideChar(Lines[Message.WParam]);
WStrLCopy(DestWide, SourceWide, PWord(Message.LParam)^);
Message.Result := WStrLen(DestWide);
end
else
begin
DestAnsi := PAnsiChar(Message.LParam);
SourceAnsi := PAnsiChar(AnsiString(Lines[Message.WParam]));
{$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLCopy(DestAnsi, SourceAnsi, PWord(Message.LParam)^);
Message.Result := {$IFDEF SYN_COMPILER_18_UP}AnsiStrings.{$ENDIF}StrLen(DestAnsi);
end
end
else
Message.Result := 0;
end;
//(WPARAM) wParam, // not used; must be zero
//(LPARAM) lParam // not used; must be zero
procedure TSynMemo.EMCanUndo(var Message: TMessage);
begin
Message.Result := Integer(CanUndo);
end;
//(WPARAM) wParam, // not used; must be zero
//(LPARAM) lParam // not used; must be zero
procedure TSynMemo.EMUndo(var Message: TMessage);
begin
Message.Result := Integer(CanUndo);
Undo;
end;
//(WPARAM) wParam, // not used; must be zero
//(LPARAM) lParam // not used; must be zero
procedure TSynMemo.EMGetFirstVisibleLine(var Message: TMessage);
begin
Message.Result := TopLine;
end;
//(WPARAM) wParam, // not used; must be zero
//(LPARAM) lParam // point coordinates
procedure TSynMemo.EMCharFromPos(var Message: TMessage);
var
vPos: TBufferCoord;
i: Integer;
begin
vPos := DisplayToBufferPos(PixelsToRowColumn(Message.LParamLo, Message.LParamHi));
Dec(vPos.Line);
if vPos.Line >= Lines.Count then
vPos.Char := 1
else if vPos.Char > Length(Lines[vPos.Line]) then
vPos.Char := Length(Lines[vPos.Line]) + 1; // ???
i := vPos.Line;
while i > 0 do
begin
Dec(i);
Inc(vPos.Char, Length(Lines[i]) + 2);
end;
//todo: this can't be right, CharIndex can easily overflow
Message.Result := MakeLong(vPos.Char{CharIndex}, vPos.Line{Line zero based});
end;
end.