Models.pas
上传用户:yj_qiu
上传日期:2022-08-08
资源大小:23636k
文件大小:6k
源码类别:

游戏引擎

开发平台:

Delphi

  1. (*
  2.  @Abstract(Basic models unit)
  3.  (C) 2006-2007 George "Mirage" Bakhtadze. <a href="http://www.casteng.com">www.casteng.com</a> <br>
  4.  Created: Apr 04, 2007 <br>
  5.  Unit contains basic model (from Model-View-Controller) classes
  6. *)
  7. {$Include GDefines.inc}
  8. unit Models;
  9. interface
  10. uses Basics, Props, BaseMsg;
  11. const
  12.   // Operations array grow step
  13.   OperationsCapacityStep = 32;
  14. type
  15.   // Operation flag
  16.   TOperationFlag = (// Operation is in applied state
  17.                     ofApplied,
  18.                     // Operation was handled
  19.                     ofHandled,
  20.                     // Operation is intermediate and for example should not be added to editor's queue
  21.                     ofIntermediate
  22.                     );
  23.   TOperationFlags = set of TOperationFlag;
  24.   // Auto-inverse operation class
  25.   TOperation = class
  26.   protected
  27.     // Should actually perform the operation. Repeated call should undo all changes made by previous call.
  28.     procedure DoApply; virtual; abstract;
  29.     // Should try to merge the operations and undo information taking in account applied state
  30.     function DoMerge(AOperation: TOperation): Boolean; virtual;
  31.   public
  32.     // Flag set
  33.     Flags: TOperationFlags;
  34.     // Applies the operation. Repeated call will undo the operation.
  35.     procedure Apply;
  36.     // Adds to the operation actions of the given one if possible and returns True if success. Both operations should be in applied or both in unapplied state.
  37.     function Merge(AOperation: TOperation): Boolean; 
  38.   end;
  39.   // Operations manager 
  40.   TOperationManager = class
  41.   private
  42.     FOperations: array of TOperation;
  43.     // Total valid operations
  44.     FTotalOperations,
  45.     // Last applied operation index
  46.     FCurOperation: Integer;
  47.     // Last operation applyed (added, undone, redone)
  48.     FLastOperation: TOperation;
  49.     procedure FreeRange(FromIndex, Count: Integer);
  50.   public
  51.     constructor Create;
  52.     destructor Destroy; override;
  53.     // Remove all operations
  54.     procedure Clear;
  55.     // Add an operation
  56.     procedure Add(Operation: TOperation);
  57.     // Undo last operations
  58.     procedure Undo;
  59.     // Redo previously undone operation
  60.     procedure Redo;
  61.     // Returns True if there is a t least one operation to undo
  62.     function CanUndo: Boolean;
  63.     // Returns True if there is a t least one operation to redo
  64.     function CanRedo: Boolean;
  65.     // Last operation applyed (added, undone, redone)
  66.     property LastOperation: TOperation read FLastOperation;
  67.   end;
  68.   IModel = interface
  69.   end;
  70.   TModel = class(TInterfacedObject, IModel)
  71.   protected
  72.     FOperations: TOperation;                               // Points to last applied operation
  73.   public
  74.     procedure GetProperties(const Result: TProperties); virtual; abstract;
  75.     procedure SetProperties(Properties: TProperties); virtual; abstract;
  76.     procedure DoOperation(const Operation: TOperation); virtual; abstract;
  77.     property LastOperation: TOperation read FOperations;
  78.   end;
  79.   // This message usually is sent to core handler when an operation is ready to apply. Default handler will free all unhandled operations.
  80.   TOperationMsg = class(TMessage)
  81.     Operation: TOperation;
  82.     constructor Create(AOperation: TOperation);
  83.   end;
  84. implementation
  85. { TOperationMessage }
  86. constructor TOperationMsg.Create(AOperation: TOperation);
  87. begin
  88.   Operation := AOperation;
  89. end;
  90. { TOperation }
  91. function TOperation.DoMerge(AOperation: TOperation): Boolean;
  92. begin
  93.   Result := False;
  94. end;
  95. procedure TOperation.Apply;
  96. begin
  97.   DoApply;
  98.   if ofApplied in Flags then Exclude(Flags, ofApplied) else Include(Flags, ofApplied);
  99. end;
  100. function TOperation.Merge(AOperation: TOperation): Boolean;
  101. begin
  102.   Assert(((ofApplied in Flags) and (ofApplied in AOperation.Flags)) or
  103.          (not (ofApplied in Flags) and not (ofApplied in AOperation.Flags)),
  104.          'TOperation.Merge: Both operations should be in applied or both in unapplied state');
  105.   Result := DoMerge(AOperation);
  106. end;
  107. { TOperationManager }
  108. procedure TOperationManager.FreeRange(FromIndex, Count: Integer);
  109. var i: Integer;
  110. begin
  111.   for i := FromIndex to FromIndex + Count - 1 do begin
  112.     if FLastOperation = FOperations[i] then FLastOperation := nil;
  113.     FOperations[i].Free;
  114.     FOperations[i] := nil;
  115.   end;
  116. end;
  117. constructor TOperationManager.Create;
  118. begin
  119.   FLastOperation := nil;
  120.   FCurOperation  := -1;
  121. end;
  122. destructor TOperationManager.Destroy;
  123. begin
  124.   Clear;
  125.   inherited;
  126. end;
  127. procedure TOperationManager.Clear;
  128. begin
  129.   FreeRange(0, FTotalOperations-1);
  130.   FLastOperation   := nil;
  131.   FCurOperation    := -1;
  132.   FTotalOperations := 0;
  133. end;
  134. procedure TOperationManager.Add(Operation: TOperation);        // o o o X o o
  135. begin
  136.   if CanUndo and FOperations[FCurOperation].Merge(Operation) then begin
  137.     Operation.Free;
  138. //    FOperations[FCurOperation].Apply;
  139.     Exit;
  140.   end;
  141.   Inc(FCurOperation);
  142.   if FCurOperation < FTotalOperations-1 then FreeRange(FCurOperation, FTotalOperations - FCurOperation -2);
  143.   FTotalOperations := FCurOperation+1;
  144.   if Length(FOperations) <= FTotalOperations then SetLength(FOperations, Length(FOperations) + OperationsCapacityStep);
  145.   FOperations[FCurOperation] := Operation;
  146.   FLastOperation := Operation
  147. end;
  148. procedure TOperationManager.Undo;
  149. begin
  150.   if CanUndo then begin
  151.     FLastOperation := FOperations[FCurOperation];
  152.     FLastOperation.Apply;
  153.     Dec(FCurOperation);
  154.   end;
  155. end;
  156. procedure TOperationManager.Redo;
  157. begin
  158.   if CanRedo then begin
  159.     Inc(FCurOperation);
  160.     FLastOperation := FOperations[FCurOperation];
  161.     FLastOperation.Apply;
  162.   end;
  163. end;
  164. function TOperationManager.CanUndo: Boolean;
  165. begin
  166.   Result := FCurOperation >= 0;
  167. end;
  168. function TOperationManager.CanRedo: Boolean;
  169. begin
  170.   Result := FCurOperation < FTotalOperations-1;
  171. end;
  172. end.