mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-09-10 09:29:13 +02:00
+ Undo/Redo by Visa Harvey (great thanks) inserted
(with some modifications) Moves work correctly Text insertion/deletion are still buggy ! * LinePosToCharIndex and reverse function changed to get more sensible results, dependant code adapted * several bug fixes
This commit is contained in:
parent
8aeb9377b7
commit
da1d805ec0
@ -123,6 +123,10 @@ const
|
||||
eaDeleteLine = 4;
|
||||
eaDeleteText = 5;
|
||||
eaSelectionChanged = 6;
|
||||
LastAction = eaSelectionChanged;
|
||||
|
||||
ActionString : array [0..LastAction] of string[8] =
|
||||
('','Move','InsLine','InsText','DelLine','DelText','SelCh');
|
||||
|
||||
CIndicator = #2#3#1;
|
||||
CEditor = #33#34#35#36#37#38#39#40#41#42#43#44#45#46#47#48#49;
|
||||
@ -155,7 +159,10 @@ type
|
||||
PIndicator = ^TIndicator;
|
||||
TIndicator = object(TView)
|
||||
Location: TPoint;
|
||||
Modified: Boolean;
|
||||
Modified : Boolean;
|
||||
{$ifdef debug}
|
||||
StoreUndo : Boolean;
|
||||
{$endif debug}
|
||||
constructor Init(var Bounds: TRect);
|
||||
procedure Draw; virtual;
|
||||
function GetPalette: PPalette; virtual;
|
||||
@ -165,6 +172,21 @@ type
|
||||
procedure Store(var S: TStream);
|
||||
end;
|
||||
|
||||
{$ifdef Undo}
|
||||
PEditorAction = ^TEditorAction;
|
||||
TEditorAction = object(TObject)
|
||||
StartPos : TPoint;
|
||||
EndPos : TPoint;
|
||||
Text : PString;
|
||||
Action : byte;
|
||||
constructor init(act:byte; StartP,EndP:TPoint;Txt:String);
|
||||
destructor done; virtual;
|
||||
end;
|
||||
|
||||
PEditorActionCollection = ^TEditorActionCollection;
|
||||
TEditorActionCollection = object(TCollection)
|
||||
end;
|
||||
{$else}
|
||||
PEditorAction = ^TEditorAction;
|
||||
TEditorAction = packed record
|
||||
Action : byte;
|
||||
@ -177,6 +199,7 @@ type
|
||||
TEditorActionCollection = object(TCollection)
|
||||
procedure FreeItem(Item: Pointer); virtual;
|
||||
end;
|
||||
{$endif Undo}
|
||||
|
||||
TSpecSymbolClass =
|
||||
(ssCommentPrefix,ssCommentSingleLinePrefix,ssCommentSuffix,ssStringPrefix,ssStringSuffix,
|
||||
@ -268,7 +291,8 @@ type
|
||||
LastLocalCmd: word;
|
||||
KeyState : Integer;
|
||||
ErrorMessage: PString;
|
||||
Actions : PEditorActionCollection;
|
||||
UndoList : PEditorActionCollection;
|
||||
RedoList : PEditorActionCollection;
|
||||
Bookmarks : array[0..9] of TEditorBookmark;
|
||||
LockFlag : integer;
|
||||
DrawCalled : boolean;
|
||||
@ -276,6 +300,7 @@ type
|
||||
function Overwrite: boolean;
|
||||
function GetLine(I: sw_integer): PLine;
|
||||
procedure CheckSels;
|
||||
procedure UpdateUndoRedo(cm : word; action : byte);
|
||||
function UpdateAttrs(FromLine: sw_integer; Attrs: byte): sw_integer;
|
||||
function UpdateAttrsRange(FromLine, ToLine: sw_integer; Attrs: byte): sw_integer;
|
||||
procedure DrawLines(FirstLine: sw_integer);
|
||||
@ -396,7 +421,8 @@ const
|
||||
ToClipCmds : TCommandSet = ([cmCut,cmCopy,cmCopyWin]);
|
||||
FromClipCmds : TCommandSet = ([cmPaste,cmPasteWin]);
|
||||
NulClipCmds : TCommandSet = ([cmClear]);
|
||||
UndoCmds : TCommandSet = ([cmUndo,cmRedo]);
|
||||
UndoCmd : TCommandSet = ([cmUndo]);
|
||||
RedoCmd : TCommandSet = ([cmRedo]);
|
||||
|
||||
function StdEditorDialog(Dialog: Integer; Info: Pointer): word;
|
||||
|
||||
@ -672,6 +698,7 @@ begin
|
||||
PointOfs:={longint(P.Y)*MaxLineLength+P.X}PosToOfsP(P);
|
||||
end;
|
||||
|
||||
{$ifndef Undo}
|
||||
function NewEditorAction(AAction: byte; AStartPos, AEndPos: TPoint; AText: string): PEditorAction;
|
||||
var P: PEditorAction;
|
||||
begin
|
||||
@ -693,6 +720,7 @@ begin
|
||||
Dispose(P);
|
||||
end;
|
||||
end;
|
||||
{$endif ndef Undo}
|
||||
|
||||
function ExtractTabs(S: string; TabSize: Sw_integer): string;
|
||||
var
|
||||
@ -1025,6 +1053,10 @@ begin
|
||||
begin
|
||||
if Modified then
|
||||
WordRec (B[0]).Lo := ord('*');
|
||||
{$ifdef debug}
|
||||
if StoreUndo then
|
||||
WordRec (B[1]).Lo := ord('S');
|
||||
{$endif debug}
|
||||
L[0] := Location.Y + 1;
|
||||
L[1] := Location.X + 1;
|
||||
FormatStr(S, ' %d:%d ', L);
|
||||
@ -1082,8 +1114,13 @@ constructor TCodeEditor.Init(var Bounds: TRect; AHScrollBar, AVScrollBar:
|
||||
PScrollBar; AIndicator: PIndicator; ABufSize:Sw_Word);
|
||||
begin
|
||||
inherited Init(Bounds,AHScrollBar,AVScrollBar);
|
||||
{$ifndef Undo}
|
||||
StoreUndo:=false;
|
||||
New(Actions, Init(500,1000));
|
||||
{$else Undo}
|
||||
StoreUndo:=true;
|
||||
{$endif def Undo}
|
||||
new(UndoList,init(500,1000));
|
||||
new(RedoList,init(500,1000));
|
||||
New(Lines, Init(500,1000));
|
||||
{ we have always need at least 1 line }
|
||||
Lines^.Insert(NewLine(''));
|
||||
@ -1227,6 +1264,9 @@ begin
|
||||
begin
|
||||
Indicator^.Location:=CurPos;
|
||||
Indicator^.Modified:=Modified;
|
||||
{$ifdef debug}
|
||||
Indicator^.StoreUndo:=StoreUndo;
|
||||
{$endif debug}
|
||||
Indicator^.DrawView;
|
||||
end;
|
||||
end;
|
||||
@ -1440,6 +1480,20 @@ begin
|
||||
CurEvent:=OldEvent;
|
||||
end;
|
||||
|
||||
procedure TCodeEditor.UpdateUndoRedo(cm : word; action : byte);
|
||||
var UndoMenu : PMenuItem;
|
||||
begin
|
||||
UndoMenu:=PAdvancedMenuBar(MenuBar)^.GetMenuItem(cm);
|
||||
if assigned(UndoMenu) then
|
||||
begin
|
||||
If assigned(UndoMenu^.Param) then
|
||||
DisposeStr(UndoMenu^.Param);
|
||||
if action<lastaction then
|
||||
UndoMenu^.Param:=NewStr(ActionString[action]);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
procedure TCodeEditor.Update;
|
||||
begin
|
||||
LimitsChanged;
|
||||
@ -1693,7 +1747,7 @@ begin
|
||||
else
|
||||
begin
|
||||
CP:=0; RX:=0;
|
||||
while (RX<X) and (CP<length(S)) do
|
||||
while (RX<=X) and (CP<length(S)) do
|
||||
begin
|
||||
Inc(CP);
|
||||
if S[CP]=TAB then
|
||||
@ -1865,9 +1919,18 @@ begin
|
||||
end;
|
||||
|
||||
procedure TCodeEditor.DeleteLine(I: sw_integer);
|
||||
var
|
||||
CP : Tpoint;
|
||||
begin
|
||||
if I<Lines^.Count then
|
||||
Lines^.AtFree(I);
|
||||
begin
|
||||
if StoreUndo then
|
||||
begin
|
||||
CP.X:=0;CP.Y:=I;
|
||||
AddAction(eaDeleteLine,CP,CP,GetLineText(I));
|
||||
end;
|
||||
Lines^.AtFree(I);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TCodeEditor.AddLine(const S: string);
|
||||
@ -2161,10 +2224,12 @@ begin
|
||||
end;
|
||||
var SelBack: sw_integer;
|
||||
SCP: TPoint;
|
||||
HoldUndo : Boolean;
|
||||
begin
|
||||
if IsReadOnly then begin InsertLine:=-1; Exit; end;
|
||||
Lock;
|
||||
SCP:=CurPos;
|
||||
HoldUndo:=StoreUndo;
|
||||
if CurPos.Y<GetLineCount then S:=GetLineText(CurPos.Y) else S:='';
|
||||
if Overwrite=false then
|
||||
begin
|
||||
@ -2183,11 +2248,16 @@ begin
|
||||
begin SelEnd.Y:=CurPos.Y+1; SelEnd.X:=length(GetLineText(CurPos.Y+1))-SelBack; end;*)
|
||||
UpdateAttrs(CurPos.Y,attrAll);
|
||||
SetCurPtr(Ind,CurPos.Y+1);
|
||||
{$ifdef Undo}
|
||||
StoreUndo:=HoldUndo;
|
||||
Addaction(eaInsertLine,SCP,CurPos,'');
|
||||
StoreUndo:=false;
|
||||
{$endif Undo}
|
||||
AdjustSelection(CurPos.X-SCP.X,CurPos.Y-SCP.Y);
|
||||
end else
|
||||
begin
|
||||
if CurPos.Y=GetLineCount-1 then
|
||||
CalcIndent(CurPos.Y);
|
||||
if CurPos.Y=GetLineCount-1 then
|
||||
begin
|
||||
Lines^.Insert(NewLine(IndentStr));
|
||||
AdjustSelection(0,1);
|
||||
@ -2197,6 +2267,7 @@ begin
|
||||
SetCurPtr(Ind,CurPos.Y+1);
|
||||
end;
|
||||
DrawLines(CurPos.Y);
|
||||
StoreUndo:=HoldUndo;
|
||||
SetModified(true);
|
||||
Unlock;
|
||||
end;
|
||||
@ -2210,10 +2281,13 @@ procedure TCodeEditor.BackSpace;
|
||||
var S,PreS: string;
|
||||
OI,CI,CP,Y,TX: Sw_integer;
|
||||
SCP: TPoint;
|
||||
HoldUndo : Boolean;
|
||||
begin
|
||||
if IsReadOnly then Exit;
|
||||
Lock;
|
||||
SCP:=CurPos;
|
||||
HoldUndo:=StoreUndo;
|
||||
StoreUndo:=false;
|
||||
if CurPos.X=0 then
|
||||
begin
|
||||
if CurPos.Y>0 then
|
||||
@ -2252,12 +2326,18 @@ begin
|
||||
S:=GetLineText(CurPos.Y);
|
||||
OI:=LinePosToCharIdx(CurPos.Y,CurPos.X);
|
||||
CI:=LinePosToCharIdx(CurPos.Y,CP);
|
||||
SetLineText(CurPos.Y,copy(S,1,CI+1-1)+copy(S,OI+1,255));
|
||||
SetLineText(CurPos.Y,copy(S,1,CI-1)+copy(S,OI,255));
|
||||
SetCurPtr(CP,CurPos.Y);
|
||||
{$ifdef Undo}
|
||||
StoreUndo:=HoldUndo;
|
||||
Addaction(eaDeleteText,SCP,CurPos,' ');
|
||||
StoreUndo:=false;
|
||||
{$endif Undo}
|
||||
end;
|
||||
UpdateAttrs(CurPos.Y,attrAll);
|
||||
AdjustSelection(CurPos.X-SCP.X,CurPos.Y-SCP.Y);
|
||||
DrawLines(CurPos.Y);
|
||||
StoreUndo:=HoldUndo;
|
||||
SetModified(true);
|
||||
Unlock;
|
||||
end;
|
||||
@ -2265,9 +2345,12 @@ end;
|
||||
procedure TCodeEditor.DelChar;
|
||||
var S: string;
|
||||
SDX,SDY,CI : sw_integer;
|
||||
HoldUndo : boolean;
|
||||
begin
|
||||
if IsReadOnly then Exit;
|
||||
Lock;
|
||||
HoldUndo:=StoreUndo;
|
||||
StoreUndo:=false;
|
||||
S:=GetLineText(CurPos.Y);
|
||||
if CurPos.X=length(S) then
|
||||
begin
|
||||
@ -2284,9 +2367,23 @@ begin
|
||||
{ Problem if S[CurPos.X+1]=TAB !! PM }
|
||||
CI:=LinePosToCharIdx(CurPos.Y,CurPos.X);
|
||||
if S[CI]=TAB then
|
||||
S:=Copy(S,1,CI-1)+CharStr(' ',TabSize-1)+Copy(S,CI+1,255)
|
||||
begin
|
||||
S:=Copy(S,1,CI-1)+CharStr(' ',TabSize-1)+Copy(S,CI+1,255);
|
||||
{$ifdef Undo}
|
||||
StoreUndo:=HoldUndo;
|
||||
Addaction(eaDeleteText,CurPos,CurPos,' ');
|
||||
StoreUndo:=false;
|
||||
{$endif Undo}
|
||||
end
|
||||
else
|
||||
Delete(S,LinePosToCharIdx(CurPos.Y,CurPos.X)+1,1);
|
||||
begin
|
||||
{$ifdef Undo}
|
||||
StoreUndo:=HoldUndo;
|
||||
Addaction(eaDeleteText,CurPos,CurPos,S[CI]);
|
||||
StoreUndo:=false;
|
||||
{$endif Undo}
|
||||
Delete(S,CI,1);
|
||||
end;
|
||||
SetLineText(CurPos.Y,S);
|
||||
SDX:=-1; SDY:=0;
|
||||
end;
|
||||
@ -2294,6 +2391,7 @@ begin
|
||||
UpdateAttrs(CurPos.Y,attrAll);
|
||||
AdjustSelection(SDX,SDY);
|
||||
DrawLines(CurPos.Y);
|
||||
StoreUndo:=HoldUndo;
|
||||
SetModified(true);
|
||||
Unlock;
|
||||
end;
|
||||
@ -2324,7 +2422,7 @@ begin
|
||||
S:=GetLineText(CurPos.Y);
|
||||
if (S<>'') and (CurPos.X<>0) then
|
||||
begin
|
||||
SetLineText(CurPos.Y,copy(S,LinePosToCharIdx(CurPos.Y,CurPos.X)+1,255));
|
||||
SetLineText(CurPos.Y,copy(S,LinePosToCharIdx(CurPos.Y,CurPos.X),255));
|
||||
SetCurPtr(0,CurPos.Y);
|
||||
UpdateAttrs(CurPos.Y,attrAll);
|
||||
DrawLines(CurPos.Y);
|
||||
@ -2341,7 +2439,7 @@ begin
|
||||
S:=GetLineText(CurPos.Y);
|
||||
if (S<>'') and (CurPos.X<>length(S)) then
|
||||
begin
|
||||
SetLineText(CurPos.Y,copy(S,1,LinePosToCharIdx(CurPos.Y,CurPos.X)));
|
||||
SetLineText(CurPos.Y,copy(S,1,LinePosToCharIdx(CurPos.Y,CurPos.X)-1));
|
||||
SetCurPtr(CurPos.X,CurPos.Y);
|
||||
UpdateAttrs(CurPos.Y,attrAll);
|
||||
DrawLines(CurPos.Y);
|
||||
@ -2661,11 +2759,14 @@ var S,SC,TabS: string;
|
||||
BI: byte;
|
||||
CI,TabStart : Sw_integer;
|
||||
SP: TPoint;
|
||||
HoldUndo : boolean;
|
||||
begin
|
||||
if IsReadOnly then Exit;
|
||||
|
||||
Lock;
|
||||
SP:=CurPos;
|
||||
HoldUndo:=StoreUndo;
|
||||
StoreUndo:=false;
|
||||
if (C<>TAB) or ((Flags and efUseTabCharacters)<>0) then
|
||||
SC:=C
|
||||
else if ((Flags and efAutoIndent)=0) then
|
||||
@ -2704,24 +2805,29 @@ begin
|
||||
else
|
||||
begin
|
||||
if Overwrite and (CI<length(S)) then
|
||||
SetLineText(CurPos.Y,copy(S,1,CI)+SC+copy(S,CI+2,255))
|
||||
SetLineText(CurPos.Y,copy(S,1,CI-1)+SC+copy(S,CI+1,255))
|
||||
else
|
||||
SetLineText(CurPos.Y,copy(S,1,CI)+SC+copy(S,CI+1,255));
|
||||
SetCurPtr(CharIdxToLinePos(CurPos.Y,CI+length(SC)+1),CurPos.Y);
|
||||
{ if PointOfs(SelStart)<>PointOfs(SelEnd) then
|
||||
if (CurPos.Y=SelEnd.Y) and (CurPos.X<SelEnd.X) then
|
||||
Inc(SelEnd.X);
|
||||
CharRight;}
|
||||
SetLineText(CurPos.Y,copy(S,1,CI-1)+SC+copy(S,CI,255));
|
||||
SetCurPtr(CurPos.X+length(SC),CurPos.Y);
|
||||
end;
|
||||
BI:=Pos(C,OpenBrackets);
|
||||
{$ifdef Undo}
|
||||
{ must be before CloseBrackets !! }
|
||||
StoreUndo:=HoldUndo;
|
||||
Addaction(eaInsertText,SP,CurPos,C);
|
||||
StoreUndo:=false;
|
||||
{$endif Undo}
|
||||
if ((Flags and efAutoBrackets)<>0) and (BI>0) then
|
||||
begin
|
||||
StoreUndo:=HoldUndo;
|
||||
AddChar(CloseBrackets[BI]);
|
||||
StoreUndo:=false;
|
||||
SetCurPtr(CurPos.X-1,CurPos.Y);
|
||||
end;
|
||||
UpdateAttrs(CurPos.Y,attrAll);
|
||||
AdjustSelection(CurPos.X-SP.X,CurPos.Y-SP.Y);
|
||||
DrawLines(CurPos.Y);
|
||||
StoreUndo:=HoldUndo;
|
||||
SetModified(true);
|
||||
UnLock;
|
||||
end;
|
||||
@ -2825,10 +2931,12 @@ begin
|
||||
begin
|
||||
s:=strpas(p2);
|
||||
if not first then
|
||||
SetCurPtr(0,i);
|
||||
SetCurPtr(0,i+1);
|
||||
InsertText(s);
|
||||
end;
|
||||
SetCurPtr(StorePos.X,StorePos.Y);
|
||||
SetModified(true);
|
||||
Update;
|
||||
{ we must free the allocated memory }
|
||||
freemem(p,l);
|
||||
end;
|
||||
@ -2859,11 +2967,11 @@ begin
|
||||
getmem(p,PCLength);
|
||||
i:=SelStart.Y;
|
||||
s:=GetLineText(i);
|
||||
str_begin:=LinePosToCharIdx(i,SelStart.X+1);
|
||||
str_begin:=LinePosToCharIdx(i,SelStart.X);
|
||||
if SelEnd.Y>SelStart.Y then
|
||||
str_end:=255
|
||||
else
|
||||
str_end:=LinePosToCharIdx(i,SelEnd.X);
|
||||
str_end:=LinePosToCharIdx(i,SelEnd.X)-1;
|
||||
s:=copy(s,str_begin,str_end-str_begin+1);
|
||||
strpcopy(p,s);
|
||||
p2:=strend(p);
|
||||
@ -2876,7 +2984,7 @@ begin
|
||||
end;
|
||||
if SelEnd.Y>SelStart.Y then
|
||||
begin
|
||||
s:=copy(GetLineText(i),1,LinePosToCharIdx(i,SelEnd.X));
|
||||
s:=copy(GetLineText(i),1,LinePosToCharIdx(i,SelEnd.X)-1);
|
||||
strpcopy(p2,EOL+s);
|
||||
end;
|
||||
OK:=WinClipboardSupported;
|
||||
@ -2891,13 +2999,156 @@ end;
|
||||
{$endif WinClipSupported}
|
||||
|
||||
procedure TCodeEditor.Undo;
|
||||
{$ifdef Undo}
|
||||
var
|
||||
Temp,Idx : Longint;
|
||||
SCP : Tpoint;
|
||||
{$endif Undo}
|
||||
begin
|
||||
{$ifdef Undo}
|
||||
StoreUndo := False;
|
||||
if UndoList^.count > 0 then
|
||||
begin
|
||||
Idx:=UndoList^.count-1;
|
||||
with PEditorAction(UndoList^.At(Idx))^ do
|
||||
begin
|
||||
case action of
|
||||
eaMoveCursor :
|
||||
begin
|
||||
{ move cursor back to original position }
|
||||
SetCurPtr(startpos.x,startpos.y);
|
||||
end;
|
||||
eaInsertLine :
|
||||
begin
|
||||
{ move cursor to inserted line, already done by other undo action?}
|
||||
{ delete inserted line}
|
||||
{ move cursor to end of line above }
|
||||
{ insert text that had been moved to line below }
|
||||
SetCurPtr(EndPos.X,EndPos.Y);
|
||||
SetDisplayText(EndPos.Y,Copy(GetDisplayText(EndPos.Y),EndPos.X+1,255));
|
||||
BackSpace;
|
||||
end;
|
||||
eaInsertText :
|
||||
begin
|
||||
SetCurPtr(startpos.x,startpos.y);
|
||||
for Temp := 1 to length(Text^) do
|
||||
DelChar;
|
||||
{ remove text }
|
||||
end;
|
||||
eaDeleteLine :
|
||||
begin
|
||||
{ reinsert deleted line }
|
||||
SCP:=CurPos;
|
||||
SetCurPtr(StartPos.X,StartPos.Y);
|
||||
InsertLine;
|
||||
SetCurPtr(StartPos.X,StartPos.Y);
|
||||
SetLineText(StartPos.Y,GetStr(Text));
|
||||
SetCurPtr(SCP.X,SCP.Y);
|
||||
end;
|
||||
eaDeleteText :
|
||||
begin
|
||||
{ reinsert deleted text }
|
||||
SetCurPtr(startpos.x,startpos.y);
|
||||
for Temp := 1 to length(Text^) do
|
||||
AddChar(Text^[Temp]);
|
||||
end;
|
||||
eaSelectionChanged :
|
||||
begin
|
||||
{ move cursor to end of last set selection }
|
||||
end;
|
||||
else
|
||||
{ what the 'ell's an undefined action doing round 'ere mate! }
|
||||
end; { once this lot is done paste into redo and modify to suit needs }
|
||||
{ move item to redo stack }
|
||||
RedoList^.Insert(UndoList^.At(Idx));
|
||||
UpdateUndoRedo(cmRedo,PEditorAction(UndoList^.At(Idx))^.Action);
|
||||
UndoList^.atDelete(Idx);
|
||||
If Idx>0 then
|
||||
UpdateUndoRedo(cmUndo,PEditorAction(UndoList^.At(Idx-1))^.Action)
|
||||
else
|
||||
UpdateUndoRedo(cmUndo,0);
|
||||
if UndoList^.count=0 then
|
||||
SetCmdState(UndoCmd,false);
|
||||
SetCmdState(RedoCmd,true);
|
||||
end;
|
||||
end;
|
||||
StoreUndo := True;
|
||||
{$else}
|
||||
NotImplemented; Exit;
|
||||
{$endif Undo}
|
||||
end;
|
||||
|
||||
procedure TCodeEditor.Redo;
|
||||
{$ifdef Undo}
|
||||
var
|
||||
Idx,Temp : Longint;
|
||||
SCP : Tpoint;
|
||||
{$endif Undo}
|
||||
begin
|
||||
{$ifdef Undo}
|
||||
StoreUndo := False;
|
||||
if RedoList^.count <> 0 then
|
||||
begin
|
||||
Idx:=RedoList^.count-1;
|
||||
with PEditorAction(RedoList^.At(Idx))^ do
|
||||
begin
|
||||
case action of
|
||||
eaMoveCursor :
|
||||
begin
|
||||
{ move cursor back to original position }
|
||||
SetCurPtr(endpos.x,endpos.y);
|
||||
end;
|
||||
eaInsertLine :
|
||||
begin
|
||||
SetCurPtr(StartPos.X,StartPos.Y);
|
||||
InsertLine;
|
||||
{ move cursor to inserted line, already done by other undo action?}
|
||||
{ delete inserted line}
|
||||
{ move cursor to end of line above }
|
||||
{ insert text that had been moved to line below }
|
||||
end;
|
||||
eaInsertText :
|
||||
begin
|
||||
SetCurPtr(startpos.x,startpos.y);
|
||||
InsertText(GetStr(Text));
|
||||
end;
|
||||
eaDeleteLine :
|
||||
begin
|
||||
SetCurPtr(StartPos.X,StartPos.Y);
|
||||
DeleteLine(EndPos.Y);
|
||||
{ insert line deleted }
|
||||
end;
|
||||
eaDeleteText :
|
||||
begin
|
||||
SetCurPtr(startpos.x,startpos.y);
|
||||
for Temp := 1 to length(GetStr(Text)) do
|
||||
DelChar;
|
||||
{ insert deleted text }
|
||||
end;
|
||||
eaSelectionChanged :
|
||||
begin
|
||||
{ move cursor to end of last set test selection }
|
||||
end;
|
||||
else
|
||||
{ what the 'ell's an undefined action doing round 'ere mate! }
|
||||
end; { once this lot is done paste back into undo and modify to suit needs }
|
||||
{ move item to undo stack }
|
||||
UndoList^.Insert(RedoList^.At(Idx));
|
||||
UpdateUndoRedo(cmUndo,PEditorAction(RedoList^.At(Idx))^.Action);
|
||||
If Idx>0 then
|
||||
UpdateUndoRedo(cmRedo,PEditorAction(RedoList^.At(Idx-1))^.Action)
|
||||
else
|
||||
UpdateUndoRedo(cmRedo,0);
|
||||
RedoList^.atDelete(Idx);
|
||||
if RedoList^.count=0 then
|
||||
SetCmdState(RedoCmd,false);
|
||||
SetCmdState(UndoCmd,true);
|
||||
end;
|
||||
end;
|
||||
StoreUndo := True;
|
||||
{$else}
|
||||
NotImplemented; Exit;
|
||||
{$endif Undo}
|
||||
end;
|
||||
|
||||
procedure TCodeEditor.GotoLine;
|
||||
@ -3644,13 +3895,17 @@ end;
|
||||
function TCodeEditor.InsertText(const S: string): Boolean;
|
||||
var I: sw_integer;
|
||||
OldPos: TPoint;
|
||||
HoldUndo : boolean;
|
||||
begin
|
||||
Lock;
|
||||
OldPos:=CurPos;
|
||||
HoldUndo:=StoreUndo;
|
||||
StoreUndo:=false;
|
||||
for I:=1 to length(S) do
|
||||
AddChar(S[I]);
|
||||
AddAction(eaInsertText,OldPos,CurPos,S);
|
||||
InsertText:=true;
|
||||
StoreUndo:=HoldUndo; {te}
|
||||
AddAction(eaInsertText,OldPos,CurPos,S);
|
||||
UnLock;
|
||||
end;
|
||||
|
||||
@ -3754,9 +4009,39 @@ begin
|
||||
end;
|
||||
|
||||
procedure TCodeEditor.AddAction(AAction: byte; AStartPos, AEndPos: TPoint; AText: string);
|
||||
var
|
||||
ActionIntegrated : boolean;
|
||||
pa : PEditorAction;
|
||||
begin
|
||||
if (Actions=nil) or (not StoreUndo) then Exit;
|
||||
Actions^.Insert(NewEditorAction(AAction,AStartPos,AEndPos,AText));
|
||||
if (UndoList=nil) or (not StoreUndo) then Exit;
|
||||
if UndoList^.count>0 then
|
||||
begin
|
||||
pa:=PEditorAction(UndoList^.At(UndoList^.count-1));
|
||||
if (pa^.action=AAction) and
|
||||
(pa^.EndPos.X=AStartPos.X) and
|
||||
(pa^.EndPos.Y=AStartPos.Y) {and
|
||||
(AAction in []) should we restrict here PM ?? }
|
||||
then
|
||||
begin
|
||||
pa^.EndPos:=AEndPos;
|
||||
pa^.text:=NewStr(GetStr(pa^.text)+AText);
|
||||
ActionIntegrated:=true;
|
||||
end;
|
||||
end
|
||||
else
|
||||
ActionIntegrated:=false;
|
||||
if not ActionIntegrated then
|
||||
begin
|
||||
UndoList^.Insert(New(PEditorAction,Init(AAction,AStartPos,AEndPos,AText)));
|
||||
UpdateUndoRedo(cmUndo,AAction);
|
||||
end;
|
||||
if UndoList^.count <> 0 then
|
||||
begin
|
||||
SetCmdState(UndoCmd,true);
|
||||
SetCmdState(RedoCmd,false);
|
||||
UpdateUndoRedo(cmRedo,0);
|
||||
RedoList^.FreeAll;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TCodeEditor.ValidBlock: boolean;
|
||||
@ -3832,6 +4117,8 @@ begin
|
||||
CanPaste:=(Clipboard<>nil) and ((Clipboard^.SelStart.X<>Clipboard^.SelEnd.X) or
|
||||
(Clipboard^.SelStart.Y<>Clipboard^.SelEnd.Y));
|
||||
SetCmdState(FromClipCmds,CanPaste and (Clipboard<>@Self));
|
||||
SetCmdState(UndoCmd,StoreUndo and (UndoList^.count>0));
|
||||
SetCmdState(RedoCmd,StoreUndo and (RedoList^.count>0));
|
||||
Message(Application,evBroadcast,cmCommandSetChanged,nil);
|
||||
DrawView;
|
||||
end;
|
||||
@ -3865,7 +4152,9 @@ var TS: PSubStream;
|
||||
begin
|
||||
inherited Load(S);
|
||||
|
||||
New(Actions, Init(500,1000));
|
||||
New(UndoList,init(500,1000));
|
||||
New(RedoList,init(500,1000));
|
||||
|
||||
New(Lines, Init(500,1000));
|
||||
{ we have always need at least 1 line }
|
||||
Lines^.Insert(NewLine(''));
|
||||
@ -4009,15 +4298,32 @@ begin
|
||||
inherited Done;
|
||||
if assigned(Lines) then
|
||||
Dispose(Lines, Done);
|
||||
If assigned(Actions) then
|
||||
Dispose(Actions, Done);
|
||||
If assigned(RedoList) then
|
||||
Dispose(RedoList,done);
|
||||
If assigned(UndoList) then
|
||||
Dispose(UndoList,done);
|
||||
end;
|
||||
|
||||
{$ifdef Undo}
|
||||
constructor TEditorAction.init(act:byte; StartP,EndP:TPoint;Txt:String);
|
||||
begin
|
||||
Action := act;
|
||||
StartPos := StartP;
|
||||
EndPos := EndP;
|
||||
Text := NewStr(txt);
|
||||
end;
|
||||
|
||||
destructor TEditorAction.done;
|
||||
begin
|
||||
DisposeStr(Text);
|
||||
end;
|
||||
{$else}
|
||||
procedure TEditorActionCollection.FreeItem(Item: Pointer);
|
||||
begin
|
||||
if assigned(Item) then
|
||||
freemem(Item,Sizeof(TEditorAction));
|
||||
end;
|
||||
{$endif Undo}
|
||||
|
||||
constructor TFileEditor.Init(var Bounds: TRect; AHScrollBar, AVScrollBar:
|
||||
PScrollBar; AIndicator: PIndicator;const AFileName: string);
|
||||
@ -4185,8 +4491,11 @@ constructor TFileEditor.Load(var S: TStream);
|
||||
var P: PString;
|
||||
SSP,SEP,CP,DP: TPoint;
|
||||
HR: TRect;
|
||||
HoldUndo : boolean;
|
||||
begin
|
||||
inherited Load(S);
|
||||
HoldUndo:=StoreUndo;
|
||||
StoreUndo:=False;
|
||||
P:=S.ReadStr;
|
||||
FileName:=GetStr(P);
|
||||
if P<>nil then DisposeStr(P);
|
||||
@ -4209,6 +4518,7 @@ begin
|
||||
SetModified(false);
|
||||
|
||||
LimitsChanged;
|
||||
StoreUndo:=HoldUndo;
|
||||
end;
|
||||
|
||||
procedure TFileEditor.Store(var S: TStream);
|
||||
@ -4547,7 +4857,16 @@ end;
|
||||
END.
|
||||
{
|
||||
$Log$
|
||||
Revision 1.53 1999-10-14 10:21:48 pierre
|
||||
Revision 1.54 1999-10-25 16:49:05 pierre
|
||||
+ Undo/Redo by Visa Harvey (great thanks) inserted
|
||||
(with some modifications)
|
||||
Moves work correctly
|
||||
Text insertion/deletion are still buggy !
|
||||
* LinePosToCharIndex and reverse function changed to get more
|
||||
sensible results, dependant code adapted
|
||||
* several bug fixes
|
||||
|
||||
Revision 1.53 1999/10/14 10:21:48 pierre
|
||||
* more tabs related problems fiwes
|
||||
|
||||
Revision 1.52 1999/10/12 23:35:18 pierre
|
||||
|
Loading…
Reference in New Issue
Block a user