RVAnimate.pas
上传用户:daoqigc
上传日期:2021-04-20
资源大小:2795k
文件大小:12k
源码类别:

RichEdit

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {       RichView                                        }
  4. {       Displaying animations in TRichView.             }
  5. {                                                       }
  6. {       Copyright (c) Sergey Tkachenko                  }
  7. {       svt@trichview.com                               }
  8. {       http://www.trichview.com                        }
  9. {                                                       }
  10. {*******************************************************}
  11. {$I RV_Defs.inc}
  12. unit RVAnimate;
  13. interface
  14. {$IFNDEF RVDONOTUSEANIMATION}
  15. uses Classes, Graphics, Controls,
  16.      DLines, RVItem, CRVFData;
  17. type
  18.   TRVAnimatorList = class;
  19.   { ---------------------------------------------------------------------------
  20.     TRVAnimator: abstract base class for all animators in TRichView
  21.   }
  22.   TRVAnimator = class
  23.     private
  24.       List: TRVAnimatorList;
  25.     protected
  26.       FrameIndex: Integer;
  27.       Item: TCustomRVItemInfo;
  28.       Interval: Integer;
  29.       function GetFrameCount: Integer; virtual; abstract;
  30.       function IsVisible: Boolean;
  31.       procedure CalcNextFrameIndex;
  32.       procedure DrawFrame;
  33.       procedure ResetBackground; virtual;
  34.     public
  35.       RVData: TCustomRVFormattedData;    
  36.       constructor Create(ARVData: TCustomRVFormattedData; AItem: TCustomRVItemInfo);
  37.       procedure Update(ARVData: TCustomRVFormattedData; AItem: TCustomRVItemInfo);
  38.       destructor Destroy; override;
  39.       procedure Reset; virtual; abstract;
  40.       procedure ChangeFrame; virtual; abstract;
  41.       procedure Draw(X, Y: Integer; Canvas: TCanvas; Animation: Boolean); virtual; abstract;
  42.   end;
  43.   { ---------------------------------------------------------------------------
  44.     TRVAnimatorList: list of animators (classes inherited from TRVAnimator).
  45.     An object of this class is contained in TRichViewRVData (FAnimatorList) for
  46.     root richviews.
  47.   }
  48.   TRVAnimatorList = class (TList)
  49.     public
  50.       Active: Boolean;
  51.       LastMinInterval,
  52.       MinInterval: Integer;
  53.       constructor Create;
  54.       destructor Destroy; override;
  55.       procedure TimerEvent;
  56.       procedure Clear; {$IFDEF RICHVIEWDEF4}override;{$ENDIF}
  57.       procedure FreeAnimators;
  58.       procedure Reset;
  59.       procedure Add(var Item: TRVAnimator);
  60.       procedure ResetBackground;
  61.   end;
  62.   { ---------------------------------------------------------------------------
  63.     TRVBitmapAnimator: displaying animations for bitmaps.
  64.     The source bitmap is sliced into frames (ImageWidth x ImageHeight).
  65.     This animator is created for graphic items having nonzero Interval property
  66.     (interval is a time to display one frame, in 1/100 sec.)
  67.   }
  68.   TRVBitmapAnimator = class (TRVAnimator)
  69.     protected
  70.       function GetFrameCount: Integer; override;
  71.     public
  72.       procedure Reset; override;
  73.       procedure ChangeFrame; override;
  74.       procedure Draw(X, Y: Integer; Canvas: TCanvas; Animation: Boolean); override;
  75.   end;
  76.   { Type of procedure to create animators }
  77.   TRVMakeAnimatorProc = procedure (item: TCustomRVItemInfo; RVData: TCustomRVFormattedData;
  78.       var anim: TRVAnimator);
  79.   { Variable pointing to such procedure }
  80.   var RV_MakeAnimator: TRVMakeAnimatorProc;
  81.   { Maximal possible number of animations in one richview }
  82. const RVMaxAnimations: Integer = 300;
  83. {$ENDIF}
  84. implementation
  85. {$IFNDEF RVDONOTUSEANIMATION}
  86. uses RichView;
  87. {================================== TRVAnimator ===============================}
  88. { Constructor }
  89. constructor TRVAnimator.Create(ARVData: TCustomRVFormattedData; AItem: TCustomRVItemInfo);
  90. begin
  91.   inherited Create;
  92.   Update(ARVData, AItem);
  93. end;
  94. {------------------------------------------------------------------------------}
  95. { Destructor. Removes itself from the list. }
  96. destructor TRVAnimator.Destroy;
  97. begin
  98.   if List<>nil then begin
  99.     List.Remove(Self);
  100.     if List.Count=0 then
  101.       List.Active := False;
  102.   end;
  103.   inherited;
  104. end;
  105. {------------------------------------------------------------------------------}
  106. { Advances FrameIndex }
  107. procedure TRVAnimator.CalcNextFrameIndex;
  108. begin
  109.   inc(FrameIndex);
  110.   if FrameIndex>=GetFrameCount then
  111.     FrameIndex := 0;
  112. end;
  113. {------------------------------------------------------------------------------}
  114. { Sets new values of RVData and Item.
  115.   If ARVData parameter = nil, it's not changed. }
  116. procedure TRVAnimator.Update(ARVData: TCustomRVFormattedData; AItem: TCustomRVItemInfo);
  117. begin
  118.   if ARVData<>nil then
  119.     RVData := ARVData;
  120.   Item  := AItem;
  121. end;
  122. {------------------------------------------------------------------------------}
  123. { Draws the current frame of animation }
  124. procedure TRVAnimator.DrawFrame;
  125. var x,y: Integer;
  126.     ditem: TRVDrawLineInfo;
  127.     Ctrl: TControl;
  128. begin
  129.   RVData.GetOrigin(x,y);
  130.   Ctrl := RVData.GetParentControl;
  131.   if (Item.DrawItemNo<0) or (Item.DrawItemNo>=TCustomRVFormattedData(RVData.GetRVData).DrawItems.Count) then
  132.     exit;
  133.   ditem := TCustomRVFormattedData(RVData.GetRVData).DrawItems[Item.DrawItemNo];
  134.   inc(x, ditem.Left-TCustomRichView(Ctrl).HScrollPos);
  135.   inc(y, ditem.Top-TCustomRichView(Ctrl).VScrollPos*TCustomRichView(Ctrl).VSmallStep);
  136.   Draw(x+item.GetBorderWidth,y+item.GetBorderHeight, TCustomRichView(Ctrl).Canvas, True);
  137. end;
  138. {------------------------------------------------------------------------------}
  139. { A place to invalidate stored background images. }
  140. procedure TRVAnimator.ResetBackground;
  141. begin
  142. end;
  143. {------------------------------------------------------------------------------}
  144. { Is this animation visible? }
  145. function TRVAnimator.IsVisible: Boolean;
  146. var x,y,h: Integer;
  147.     Ctrl: TControl;
  148. begin
  149.   RVData.GetOrigin(x,y);
  150.   Ctrl := RVData.GetRootData.GetParentControl;
  151.   if (Item.DrawItemNo<0) or (Item.DrawItemNo>=TCustomRVFormattedData(RVData.GetRVData).DrawItems.Count) then begin
  152.     Result := False;
  153.     exit;
  154.   end;
  155.   inc(y, TCustomRVFormattedData(RVData.GetRVData).DrawItems[item.DrawItemNo].Top-TCustomRichView(Ctrl).VScrollPos*TCustomRichView(Ctrl).VSmallStep);
  156.   h := Ctrl.ClientHeight;
  157.   Result := (y<h) and (y+TRVNonTextItemInfo(item).Height>0);
  158. end;
  159. {================================ TRVAnimatorList =============================}
  160. { Constructor }
  161. constructor TRVAnimatorList.Create;
  162. begin
  163.   inherited Create;
  164.   LastMinInterval := MaxInt;
  165.   MinInterval     := MaxInt;
  166. end;
  167. { Destructor }
  168. destructor TRVAnimatorList.Destroy;
  169. begin
  170.   Clear;
  171.   inherited Destroy;
  172. end;
  173. {------------------------------------------------------------------------------}
  174. { Adds a new item.
  175.   If the number of items exceeds the maximum, frees the Item instead. }
  176. procedure TRVAnimatorList.Add(var Item: TRVAnimator);
  177. begin
  178.   if Count=RVMaxAnimations then begin
  179.     Item.Free;
  180.     Item := nil;
  181.     exit;
  182.   end;
  183.   Item.Reset;
  184.   if MinInterval>Item.Interval then
  185.     MinInterval := Item.Interval;
  186.   inherited Add(Item);
  187.   Item.List := Self;
  188. end;
  189. {------------------------------------------------------------------------------}
  190. { Clears the list. Important: animators are not destroyed, just unlinked from
  191.   the list. }
  192. procedure TRVAnimatorList.Clear;
  193. var i: Integer;
  194. begin
  195.   for i := 0 to Count-1 do
  196.     TRVAnimator(Items[i]).List := nil;
  197.   inherited Clear;
  198.   Active := False;
  199. end;
  200. {------------------------------------------------------------------------------}
  201. { Clears the list, destroying all animators. }
  202. procedure TRVAnimatorList.FreeAnimators;
  203. var i: Integer;
  204. begin
  205.   for i := 0 to Count-1 do begin
  206.     TRVAnimator(Items[i]).List := nil;
  207.     TRVAnimator(Items[i]).Free;
  208.   end;
  209.   inherited Clear;
  210.   Active := False;  
  211. end;
  212. {------------------------------------------------------------------------------}
  213. { Calls ResetBackground of all items. }
  214. procedure TRVAnimatorList.ResetBackground;
  215. var i: Integer;
  216. begin
  217.   for i := 0 to Count-1 do 
  218.     TRVAnimator(Items[i]).ResetBackground;
  219. end;
  220. {------------------------------------------------------------------------------}
  221. { A procedure to call regularly on timer.
  222.   It's called when MinInterval is elapsed.
  223.   Decreases Interval of all animators by MinIterval.
  224.   If it becomes 0, calls ChangeFrame and redraws visible animators.
  225.   Calculates new MinInteval (min of Interval of all animators) }
  226. procedure TRVAnimatorList.TimerEvent;
  227. var i, Elapsed: Integer;
  228.     Animator: TRVAnimator;
  229. begin
  230.   Elapsed := MinInterval;
  231.   MinInterval := MaxInt;
  232.   for i := 0 to Count-1 do begin
  233.     Animator := TRVAnimator(Items[i]);
  234.     dec(Animator.Interval, Elapsed);
  235.     if Animator.Interval<=0 then begin
  236.       Animator.ChangeFrame;
  237.       if Animator.IsVisible then
  238.         Animator.DrawFrame;
  239.     end;
  240.     if MinInterval>Animator.Interval then
  241.       MinInterval := Animator.Interval;
  242.   end;
  243. end;
  244. {------------------------------------------------------------------------------}
  245. { Calls Reset for all animators. Calculates new MinInterval. }
  246. procedure TRVAnimatorList.Reset;
  247. var i: Integer;
  248.     Animator: TRVAnimator;
  249. begin
  250.   MinInterval := MaxInt;
  251.   for i := 0 to Count-1 do begin
  252.     Animator := TRVAnimator(Items[i]);
  253.     Animator.Reset;
  254.     if MinInterval>Animator.Interval then
  255.       MinInterval := Animator.Interval;
  256.   end;
  257. end;
  258. {============================== TRVBitmapAnimator =============================}
  259. { Draws the current frame at (X,Y) on Canvas.
  260.   Animation=True, if this is a drawing on timer.
  261.   Animation=False, if this is a drawing from item.Paint. }  
  262. procedure TRVBitmapAnimator.Draw(X, Y: Integer; Canvas: TCanvas; Animation: Boolean);
  263. var bmp: TBitmap;
  264.     w,h,nCols: Integer;
  265. begin
  266.   bmp := TBitmap(TRVGraphicItemInfo(Item).ImageCopy);
  267.   if bmp=nil then
  268.     bmp := TBitmap(TRVGraphicItemInfo(Item).Image);
  269.   w := TRVGraphicItemInfo(Item).GetImageWidth(nil);
  270.   h := TRVGraphicItemInfo(Item).GetImageHeight(nil);
  271.   nCols := bmp.Width div w;
  272.   Canvas.CopyRect(Bounds(X,Y,w,h), bmp.Canvas,
  273.     Bounds((FrameIndex mod nCols)*w, (FrameIndex div nCols)*h,w,h));
  274. end;
  275. {------------------------------------------------------------------------------}
  276. { Rewinds to the first frame. Updates Interval. }
  277. procedure TRVBitmapAnimator.Reset;
  278. begin
  279.   Interval := TRVGraphicItemInfo(Item).Interval*10;
  280.   FrameIndex := 0;
  281. end;
  282. {------------------------------------------------------------------------------}
  283. { Change frame to the next one. Updates Interval. }
  284. procedure TRVBitmapAnimator.ChangeFrame;
  285. begin
  286.   Interval := TRVGraphicItemInfo(Item).Interval*10;
  287.   CalcNextFrameIndex;
  288. end;
  289. {------------------------------------------------------------------------------}
  290. { Returns a number of frames in TRVBitmapAnimator for item } 
  291. function GetBitmapFrameCount(item: TRVGraphicItemInfo): Integer;
  292. var w,h: Integer;
  293. begin
  294.   w := Item.GetImageWidth(nil);
  295.   h := Item.GetImageHeight(nil);
  296.   if (w=0) or (h=0) then
  297.     Result := 0
  298.   else
  299.     Result := (Item.Image.Width div w)*(Item.Image.Height div h);
  300. end;
  301. {------------------------------------------------------------------------------}
  302. { Returns the count of frames }
  303. function TRVBitmapAnimator.GetFrameCount: Integer;
  304. begin
  305.   Result := GetBitmapFrameCount(TRVGraphicItemInfo(Item));
  306. end;
  307. {==============================================================================}
  308. { This procedure creates an animator (anim) for the item, if it's necessary.
  309.   Otherwise they free-and-nil anim.
  310.   This procedure can create only TRVBitmapAnimator.
  311.   In other units (for example, in RVGifAnimate), there may be other procedures
  312.   creating different animators.
  313.   They must be assigned to RV_MakeAnimator. They must do their work and call
  314.   the previous RV_MakeAnimator, thus making a procedure chain. }
  315. procedure RV_MakeAnimatorDef(item: TCustomRVItemInfo; RVData: TCustomRVFormattedData;
  316.   var anim: TRVAnimator);
  317. begin
  318.   if item is TRVGraphicItemInfo then begin
  319.     if (TRVGraphicItemInfo(item).Interval>0) and
  320.        (TRVGraphicItemInfo(item).Image is TBitmap) and
  321.        (GetBitmapFrameCount(TRVGraphicItemInfo(item))>1) then begin
  322.         if (anim<>nil) and not (anim is TRVBitmapAnimator) then begin
  323.           anim.Free;
  324.           anim := nil;
  325.         end;
  326.         if anim=nil then begin
  327.           anim := TRVBitmapAnimator.Create(RVData, Item);
  328.           RVData.InsertAnimator(TObject(anim));
  329.           end
  330.         else if anim<>nil then begin
  331.           anim.Update(RVData, Item);
  332.           anim.Reset;
  333.         end;
  334.     end;
  335.   end;
  336.   anim.Free;
  337.   anim := nil;
  338. end;
  339. initialization
  340.   RV_MakeAnimator := RV_MakeAnimatorDef;
  341. {$ENDIF}
  342. end.