SynEdit Selection/Block: Cleanup/Refactor; Fix bug: undo for overwrite column-mode block; Fix Bug: Copy of last-line smLine-mode block returned 2 extra bytes

git-svn-id: trunk@17789 -
This commit is contained in:
martin 2008-12-10 23:16:49 +00:00
parent d0c213de66
commit fc8a0777a9

View File

@ -19,6 +19,14 @@ If you do not delete the provisions above, a recipient may use your version
of this file under either the MPL or the GPL.
-------------------------------------------------------------------------------}
(* Naming Conventions:
Byte = Logical: Refers to the location any TextToken has in the String.
In Utf8String some TextToken can have more than one byte
Char = Physical: Refers to the (x-)location on the screen matrix.
Some TextToken (like tab) can spawn multiply char locations
*)
unit SynEditPointClasses;
{$I synedit.inc}
@ -86,7 +94,7 @@ type
constructor Create(ALines: TSynEditStrings);
//destructor Destroy; override;
procedure SetSelTextPrimitive(PasteMode: TSynSelectionMode; Value: PChar;
ATag: PInteger);
ATag: PInteger; AddToUndoList: Boolean = false);
function SelAvail: Boolean;
function IsBackwardSel: Boolean; // SelStart < SelEnd ?
property Enabled: Boolean read FEnabled write SetEnabled;
@ -94,6 +102,8 @@ type
property SelectionMode: TSynSelectionMode
read FSelectionMode write SetSelectionMode;
property SelText: String read GetSelText write SetSelText;
// Start and End positions are in the order they where defined
// This may mean Startpos is behind EndPos in the text
property StartLineBytePos: TPoint
read GetStartLineBytePos write SetStartLineBytePos;
property EndLineBytePos: TPoint
@ -102,7 +112,7 @@ type
property EndLinePos: Integer read FEndLinePos;
property StartBytePos: Integer read FStartBytePos;
property EndBytePos: Integer read FEndBytePos;
// Bounds ordered
// First and Last Pos are ordered according to the text flow (LTR)
property FirstLineBytePos: TPoint read GetFirstLineBytePos;
property LastLineBytePos: TPoint read GetLastLineBytePos;
property InvalidateLinesMethod : TInvalidateLines write FInvalidateLinesMethod;
@ -118,17 +128,23 @@ type
fLinePos: Integer; // 1 based
fCharPos: Integer; // 1 based
private
function GetLineCharPos: TPoint;
function GetLineText : string;
procedure SetLineCharPos(const AValue: TPoint);
procedure setCharPos(const AValue: Integer);
procedure setLinePos(const AValue: Integer);
function GetLineCharPos: TPoint;
procedure SetLineCharPos(const AValue: TPoint);
function GetBytePos: Integer;
procedure SetBytePos(const AValue: Integer);
function GetLineBytePos: TPoint;
procedure SetLineBytePos(const AValue: TPoint);
function GetLineText: string;
procedure SetLineText(const AValue : string);
public
constructor Create;
property LinePos : Integer read fLinePos write setLinePos;
property CharPos : Integer read fCharPos write setCharPos;
property LineCharPos : TPoint read GetLineCharPos write SetLineCharPos;
property LinePos: Integer read fLinePos write setLinePos;
property CharPos: Integer read fCharPos write setCharPos;
property LineCharPos: TPoint read GetLineCharPos write SetLineCharPos;
property BytePos: Integer read GetBytePos write SetBytePos;
property LineBytePos: TPoint read GetLineBytePos write SetLineBytePos;
property LineText: string read GetLineText write SetLineText;
end;
@ -165,6 +181,27 @@ end;
{ TSynEditCaret }
constructor TSynEditCaret.Create;
begin
inherited Create;
fLinePos:= 1;
fCharPos:= 1;
end;
procedure TSynEditCaret.setLinePos(const AValue : Integer);
begin
if fLinePos = AValue then exit;
fLinePos:= AValue;
fOnChangeList.CallNotifyEvents(self);
end;
procedure TSynEditCaret.setCharPos(const AValue : Integer);
begin
if fCharPos = AValue then exit;
fCharPos:= AValue;
fOnChangeList.CallNotifyEvents(self);
end;
function TSynEditCaret.GetLineCharPos : TPoint;
begin
Result := Point(fCharPos, fLinePos);
@ -178,18 +215,24 @@ begin
fOnChangeList.CallNotifyEvents(self);
end;
procedure TSynEditCaret.setCharPos(const AValue : Integer);
function TSynEditCaret.GetBytePos: Integer;
begin
if fCharPos = AValue then exit;
fCharPos:= AValue;
fOnChangeList.CallNotifyEvents(self);
Result := LineBytePos.X;
end;
procedure TSynEditCaret.setLinePos(const AValue : Integer);
procedure TSynEditCaret.SetBytePos(const AValue: Integer);
begin
if fLinePos = AValue then exit;
fLinePos:= AValue;
fOnChangeList.CallNotifyEvents(self);
CharPos := FLines.LogicalToPhysicalPos(Point(AValue, LinePos)).X;
end;
function TSynEditCaret.GetLineBytePos: TPoint;
begin
Result := FLines.PhysicalToLogicalPos(LineCharPos);
end;
procedure TSynEditCaret.SetLineBytePos(const AValue: TPoint);
begin
LineCharPos := FLines.LogicalToPhysicalPos(AValue);
end;
function TSynEditCaret.GetLineText : string;
@ -206,13 +249,6 @@ begin
FLines[LinePos - 1] := AValue;
end;
constructor TSynEditCaret.Create;
begin
inherited Create;
fLinePos:= 1;
fCharPos:= 1;
end;
{ TSynEditSelection }
constructor TSynEditSelection.Create(ALines : TSynEditStrings);
@ -385,7 +421,7 @@ begin
// step1: calclate total length of result string
for i := First to Last do
Inc(TotalLen, Length(FLines[i]) + Length(sLineBreak));
if Last = FLines.Count then
if Last = FLines.Count - 1 then
Dec(TotalLen, Length(sLineBreak));
// step2: build up result string
SetLength(Result, TotalLen);
@ -395,7 +431,7 @@ begin
CopyAndForward(sLineBreak, 1, MaxInt, P);
end;
CopyAndForward(FLines[Last], 1, MaxInt, P);
if (Last + 1) < FLines.Count then
if Last < FLines.Count - 1 then
CopyAndForward(sLineBreak, 1, MaxInt, P);
end;
end;
@ -403,32 +439,12 @@ begin
end;
procedure TSynEditSelection.SetSelText(const Value : string);
var
StartOfBlock, EndOfBlock: TPoint;
begin
if SelAvail then begin
if IsBackwardSel then
fUndoList.AddChange(crDelete, StartLineBytePos, EndLineBytePos,
GetSelText, SelectionMode)
else
fUndoList.AddChange(crDeleteAfterCursor, EndLineBytePos, StartLineBytePos,
GetSelText, SelectionMode);
StartOfBlock := FirstLineBytePos;
EndOfBlock := LastLineBytePos;
end else begin
StartOfBlock := FCaret.LineCharPos;
EndOfBlock := FCaret.LineCharPos;
end;
StartLineBytePos := StartOfBlock;
EndLineBytePos := EndOfBlock;
SetSelTextPrimitive(smNormal, PChar(Value), nil);
if SelectionMode = smLine then
StartOfBlock.X := 1;
if length(Value) > 0 then
fUndoList.AddChange(crInsert, StartOfBlock, EndLineBytePos, '', smNormal);
SetSelTextPrimitive(smNormal, PChar(Value), nil, true);
end;
procedure TSynEditSelection.SetSelTextPrimitive(PasteMode : TSynSelectionMode; Value : PChar; ATag : PInteger);
procedure TSynEditSelection.SetSelTextPrimitive(PasteMode : TSynSelectionMode;
Value : PChar; ATag : PInteger; AddToUndoList: Boolean = false);
var
BB, BE: TPoint;
TempString: string;
@ -729,16 +745,36 @@ var
// CaretXY := CaretXY;
end;
var
StartInsert: TPoint;
begin
FLines.BeginUpdate;
try
// BB is lower than BE
BB := FirstLineBytePos;
BE := LastLineBytePos;
if SelAvail then
if SelAvail then begin
if AddToUndoList then begin
if IsBackwardSel then
fUndoList.AddChange(crDelete, StartLineBytePos, EndLineBytePos,
GetSelText, SelectionMode)
else
fUndoList.AddChange(crDeleteAfterCursor, EndLineBytePos, StartLineBytePos,
GetSelText, SelectionMode);
end;
DeleteSelection;
if (Value <> nil) and (Value[0] <> #0) then
end;
if (Value <> nil) and (Value[0] <> #0) then begin
if AddToUndoList then
StartInsert := FCaret.LineBytePos;
InsertText;
if AddToUndoList then begin
if SelectionMode = smLine then
StartInsert.X := 1;
if length(Value) > 0 then
fUndoList.AddChange(crInsert, StartInsert, FCaret.LineBytePos, '', smNormal);
end;
end;
finally
FLines.EndUpdate; // May reset Block Begin
end;