Procházet zdrojové kódy

improve ability to handle group undo

Johann ELSASS před 2 roky
rodič
revize
5080981b64
2 změnil soubory, kde provedl 54 přidání a 6 odebrání
  1. 27 6
      lazpaint/image/uimage.pas
  2. 27 0
      lazpaint/image/ustatetype.pas

+ 27 - 6
lazpaint/image/uimage.pas

@@ -156,8 +156,9 @@ type
     function CanRedo: boolean;
     procedure Undo;
     procedure Redo;
-    procedure DoBegin;
+    function DoBegin: TComposedImageDifference;
     procedure DoEnd(out ADoFound: boolean; out ASomethingDone: boolean);
+    procedure DoEnd(var ACompose: TComposedImageDifference);
     procedure ClearUndo;
     procedure CompressUndo;
     function UsedMemory: int64;
@@ -1170,9 +1171,10 @@ begin
   end;
 end;
 
-procedure TLazPaintImage.DoBegin;
+function TLazPaintImage.DoBegin: TComposedImageDifference;
 begin
-  AddUndo(TComposedImageDifference.Create(True));
+  result := TComposedImageDifference.Create(True);
+  AddUndo(result);
 end;
 
 procedure TLazPaintImage.DoEnd(out ADoFound: boolean; out ASomethingDone: boolean);
@@ -1189,14 +1191,16 @@ begin
     curIndex := FUndoPos;
     curDiff := curGroup[curIndex];
     if not ((curDiff is TComposedImageDifference) and
-      TComposedImageDifference(curDiff).Agglutinate) then
+      TComposedImageDifference(curDiff).Agglutinate and
+      not TComposedImageDifference(curDiff).LockAgglutinate) then
         exit;
     ADoFound:= true;
     ASomethingDone := true;
     repeat
       insideDiff := TComposedImageDifference(curDiff).GetLast;
       if (insideDiff <> nil) and (insideDiff is TComposedImageDifference) and
-         TComposedImageDifference(insideDiff).Agglutinate then
+         TComposedImageDifference(insideDiff).Agglutinate and
+         not TComposedImageDifference(insideDiff).LockAgglutinate then
       begin
         curGroup := TComposedImageDifference(curDiff);
         curIndex := curGroup.Count-1;
@@ -1209,12 +1213,29 @@ begin
     if TComposedImageDifference(curDiff).Count = 0 then
     begin
       curGroup.Delete(curIndex);
-      if curGroup = FUndoList then dec(FUndoPos);
+      if (curGroup = FUndoList) and (FUndoPos >= curIndex) then dec(FUndoPos);
       ASomethingDone := false;
     end;
   end;
 end;
 
+procedure TLazPaintImage.DoEnd(var ACompose: TComposedImageDifference);
+var
+  index: Integer;
+begin
+  ACompose.StopAgglutinate;
+  if ACompose.Count = 0 then
+  begin
+    index := FUndoList.IndexOf(ACompose);
+    if index <> -1 then
+    begin
+      FUndoList.Delete(index);
+      if FUndoPos >= index then dec(FUndoPos);
+      ACompose := nil;
+    end;
+  end;
+end;
+
 procedure TLazPaintImage.ClearUndo;
 begin
   try

+ 27 - 0
lazpaint/image/ustatetype.pas

@@ -68,9 +68,12 @@ type
     function GetCount: integer;
     function GetItem(AIndex: integer): TCustomImageDifference;
     function GetTotalCount: integer;
+    procedure SetLockAgglutinate(AValue: boolean);
   protected
     FDiffs: TImageDifferenceList;
     FAgglutinate: boolean;
+    FLockAgglutinate: boolean; // prevent stopping the agglutination to have a frame
+                               // for subactions having their own stack of composed difference
     function GetIsIdentity: boolean; override;
     function GetImageDifferenceKind: TImageDifferenceKind; override;
     function GetChangingBounds: TRect; override;
@@ -89,11 +92,13 @@ type
     procedure Clear;
     procedure Delete(AIndex: integer);
     procedure DeleteFrom(AIndex: integer);
+    function IndexOf(ADiff: TCustomImageDifference): integer;
     function GetLast: TCustomImageDifference;
     function ToString: ansistring; override;
     property Count: integer read GetCount;
     property TotalCount: integer read GetTotalCount;
     property Agglutinate: boolean read FAgglutinate;
+    property LockAgglutinate: boolean read FLockAgglutinate write SetLockAgglutinate;
     property Item[AIndex: integer]: TCustomImageDifference read GetItem; default;
   end;
 
@@ -223,6 +228,14 @@ begin
       inc(result, FDiffs[i].GetCost);
 end;
 
+procedure TComposedImageDifference.SetLockAgglutinate(AValue: boolean);
+begin
+  if FLockAgglutinate=AValue then Exit;
+  if AValue and not Agglutinate then
+    raise Exception.Create('Currently not agglutinating actions');
+  FLockAgglutinate:=AValue;
+end;
+
 function TComposedImageDifference.GetIsIdentity: boolean;
 var
   i: Integer;
@@ -290,8 +303,17 @@ begin
 end;
 
 procedure TComposedImageDifference.StopAgglutinate;
+var
+  last: TComposedImageDifference;
 begin
   FAgglutinate:= false;
+  if (FDiffs.Count > 0) and (FDiffs[FDiffs.Count-1] is TComposedImageDifference) then
+  begin
+    last := TComposedImageDifference(FDiffs[FDiffs.Count-1]);
+    last.StopAgglutinate;
+    if last.Count = 0 then
+       FDiffs.Delete(FDiffs.Count-1);
+  end;
 end;
 
 destructor TComposedImageDifference.Destroy;
@@ -365,6 +387,11 @@ begin
     Delete(i);
 end;
 
+function TComposedImageDifference.IndexOf(ADiff: TCustomImageDifference): integer;
+begin
+  result := FDiffs.IndexOf(ADiff);
+end;
+
 function TComposedImageDifference.GetLast: TCustomImageDifference;
 begin
   if Count = 0 then result := nil