Gifctrl.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:16k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1997, 1998 Master-Bank          }
  6. {                                                       }
  7. {*******************************************************}
  8. unit GIFCtrl;
  9. interface
  10. {$I RX.INC}
  11. uses Messages, {$IFDEF WIN32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  12.   SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, Menus, ExtCtrls,
  13.   Animate, RxGIF, RxTimer;
  14. type
  15. { TRxGIFAnimator }
  16.   TRxGIFAnimator = class(TRxImageControl)
  17.   private
  18.     FAnimate: Boolean;
  19.     FImage: TGIFImage;
  20.     FTimer: TRxTimer;
  21.     FFrameIndex: Integer;
  22.     FStretch: Boolean;
  23.     FLoop: Boolean;
  24.     FCenter: Boolean;
  25.     FTransparent: Boolean;
  26.     FTimerRepaint: Boolean;
  27.     FCache: TBitmap;
  28.     FCacheIndex: Integer;
  29.     FTransColor: TColor;
  30. {$IFDEF RX_D3}
  31.     FAsyncDrawing: Boolean;
  32. {$ENDIF}
  33. {$IFNDEF RX_D4}
  34.     FAutoSize: Boolean;
  35. {$ENDIF}
  36.     FOnStart: TNotifyEvent;
  37.     FOnStop: TNotifyEvent;
  38.     FOnChange: TNotifyEvent;
  39.     FOnFrameChanged: TNotifyEvent;
  40.     procedure TimerDeactivate;
  41.     function GetFrameBitmap(Index: Integer; var TransColor: TColor): TBitmap;
  42.     function GetDelayTime(Index: Integer): Cardinal;
  43. {$IFNDEF RX_D4}
  44.     procedure SetAutoSize(Value: Boolean);
  45. {$ENDIF}
  46. {$IFDEF RX_D3}
  47.     procedure SetAsyncDrawing(Value: Boolean);
  48. {$ENDIF}
  49.     procedure SetAnimate(Value: Boolean);
  50.     procedure SetCenter(Value: Boolean);
  51.     procedure SetImage(Value: TGIFImage);
  52.     procedure SetFrameIndex(Value: Integer);
  53.     procedure SetStretch(Value: Boolean);
  54.     procedure SetTransparent(Value: Boolean);
  55.     procedure ImageChanged(Sender: TObject);
  56.     procedure TimerExpired(Sender: TObject);
  57.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  58.   protected
  59. {$IFDEF RX_D4}
  60.     function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
  61. {$ENDIF}
  62.     function GetPalette: HPALETTE; override;
  63.     procedure AdjustSize; override;
  64.     procedure Paint; override;
  65.     procedure DoPaintImage; override;
  66.     procedure Change; dynamic;
  67.     procedure FrameChanged; dynamic;
  68.     procedure Start; dynamic;
  69.     procedure Stop; dynamic;
  70.   public
  71.     constructor Create(AOwner: TComponent); override;
  72.     destructor Destroy; override;
  73.   published
  74. {$IFDEF RX_D3}
  75.     property AsyncDrawing: Boolean read FAsyncDrawing write SetAsyncDrawing default False;
  76. {$ENDIF}
  77.     property Animate: Boolean read FAnimate write SetAnimate default False;
  78. {$IFDEF RX_D4}
  79.     property AutoSize default True;
  80. {$ELSE}
  81.     property AutoSize: Boolean read FAutoSize write SetAutoSize default True;
  82. {$ENDIF}
  83.     property Center: Boolean read FCenter write SetCenter default False;
  84.     property FrameIndex: Integer read FFrameIndex write SetFrameIndex default 0;
  85.     property Image: TGIFImage read FImage write SetImage;
  86.     property Loop: Boolean read FLoop write FLoop default True;
  87.     property Stretch: Boolean read FStretch write SetStretch default False;
  88.     property Transparent: Boolean read FTransparent write SetTransparent default True;
  89. {$IFDEF RX_D4}
  90.     property Anchors;
  91.     property Constraints;
  92.     property DragKind;
  93. {$ENDIF}
  94.     property Align;
  95.     property Cursor;
  96.     property DragCursor;
  97.     property DragMode;
  98.     property Enabled;
  99.     property ParentShowHint;
  100.     property PopupMenu;
  101.     property ShowHint;
  102.     property Visible;
  103.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  104.     property OnFrameChanged: TNotifyEvent read FOnFrameChanged write FOnFrameChanged;
  105.     property OnStart: TNotifyEvent read FOnStart write FOnStart;
  106.     property OnStop: TNotifyEvent read FOnStop write FOnStop;
  107.     property OnClick;
  108.     property OnDblClick;
  109.     property OnDragOver;
  110.     property OnDragDrop;
  111.     property OnEndDrag;
  112.     property OnMouseMove;
  113.     property OnMouseDown;
  114.     property OnMouseUp;
  115. {$IFDEF RX_D5}
  116.     property OnContextPopup;
  117. {$ENDIF}
  118. {$IFDEF WIN32}
  119.     property OnStartDrag;
  120. {$ENDIF}
  121. {$IFDEF RX_D4}
  122.     property OnEndDock;
  123.     property OnStartDock;
  124. {$ENDIF}
  125.   end;
  126. implementation
  127. uses VCLUtils, MaxMin, RxGraph;
  128. { Maximum delay (10 sec) guarantees that a very long and slow
  129.   GIF does not hang the system }
  130. const
  131.   MaxDelayTime = 10000;
  132. {$IFDEF WIN32}
  133.   MinDelayTime = 50;
  134. {$ELSE}
  135.   MinDelayTime = 1;
  136. {$ENDIF}
  137. { TRxGIFAnimator }
  138. constructor TRxGIFAnimator.Create(AOwner: TComponent);
  139. begin
  140.   inherited Create(AOwner);
  141.   FTimer := TRxTimer.Create(Self);
  142.   AutoSize := True;
  143.   FImage := TGIFImage.Create;
  144.   FGraphic := FImage;
  145.   FImage.OnChange := ImageChanged;
  146.   FCacheIndex := -1;
  147.   FTransColor := clNone;
  148.   FLoop := True;
  149.   FTransparent := True;
  150. end;
  151. destructor TRxGIFAnimator.Destroy;
  152. begin
  153.   Destroying;
  154.   FOnStart := nil;
  155.   FOnStop := nil;
  156.   FOnChange := nil;
  157.   FOnFrameChanged := nil;
  158.   Animate := False;
  159.   FCache.Free;
  160.   FImage.OnChange := nil;
  161.   FImage.Free;
  162.   inherited Destroy;
  163. end;
  164. procedure TRxGIFAnimator.AdjustSize;
  165. begin
  166.   if not (csReading in ComponentState) then begin
  167.     if AutoSize and Assigned(FImage) and not FImage.Empty then
  168.       SetBounds(Left, Top, FImage.ScreenWidth, FImage.ScreenHeight);
  169.   end;
  170. end;
  171. {$IFDEF RX_D4}
  172. function TRxGIFAnimator.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
  173. begin
  174.   Result := True;
  175.   if not (csDesigning in ComponentState) and Assigned(FImage) and
  176.     not FImage.Empty then
  177.   begin
  178.     if Align in [alNone, alLeft, alRight] then
  179.       NewWidth := FImage.ScreenWidth;
  180.     if Align in [alNone, alTop, alBottom] then
  181.       NewHeight := FImage.ScreenHeight;
  182.   end;
  183. end;
  184. {$ENDIF}
  185. function TRxGIFAnimator.GetDelayTime(Index: Integer): Cardinal;
  186. begin
  187.   if (FFrameIndex >= 0) and (FFrameIndex < FImage.Count) and
  188.     (FImage.Count > 1) then
  189.   begin
  190.     Result := FImage.Frames[FFrameIndex].AnimateInterval;
  191.     if Result < MinDelayTime then Result := MinDelayTime
  192.     else if Result > MaxDelayTime then Result := MaxDelayTime;
  193.   end
  194.   else Result := 0;
  195. end;
  196. function TRxGIFAnimator.GetFrameBitmap(Index: Integer;
  197.   var TransColor: TColor): TBitmap;
  198. var
  199.   I, Last, First: Integer;
  200.   SavePal: HPalette;
  201.   UseCache: Boolean;
  202. begin
  203.   Index := Min(Index, FImage.Count - 1);
  204.   UseCache := (FCache <> nil) and (FCacheIndex = Index - 1) and (FCacheIndex >= 0) and
  205.     (FImage.Frames[FCacheIndex].DisposalMethod <> dmRestorePrevious);
  206.   if UseCache then begin
  207.     Result := FCache;
  208.     TransColor := FTransColor;
  209.   end
  210.   else begin
  211.     FCache.Free;
  212.     FCache := nil;
  213.     Result := TBitmap.Create;
  214.   end;
  215. {$IFDEF RX_D3}
  216.   Result.Canvas.Lock;
  217. {$ENDIF}
  218.   try
  219.     with Result do begin
  220.       if not UseCache then begin
  221.         Width := FImage.ScreenWidth;
  222.         Height := FImage.ScreenHeight;
  223.       end;
  224.       Last := Index;
  225.       First := Max(0, Last);
  226.       SavePal := 0;
  227.       if FImage.Palette <> 0 then begin
  228.         SavePal := SelectPalette(Canvas.Handle, FImage.Palette, False);
  229.         RealizePalette(Canvas.Handle);
  230.       end;
  231.       if not UseCache then begin
  232.         if (FImage.Frames[FImage.FrameIndex].TransparentColor <> clNone) then
  233.         begin
  234.           TransColor := GetNearestColor(Canvas.Handle,
  235.             ColorToRGB(FImage.Frames[FImage.FrameIndex].TransparentColor));
  236.           Canvas.Brush.Color := PaletteColor(TransColor);
  237.         end
  238.         else if (FImage.BackgroundColor <> clNone) and FImage.Transparent then
  239.           Canvas.Brush.Color := PaletteColor(FImage.BackgroundColor)
  240.         else Canvas.Brush.Color := PaletteColor(clWindow);
  241.         Canvas.FillRect(Bounds(0, 0, Width, Height));
  242.         while First > 0 do begin
  243.           if (FImage.ScreenWidth = FImage.Frames[First].Width) and
  244.             (FImage.ScreenHeight = FImage.Frames[First].Height) then
  245.           begin
  246.             if (FImage.Frames[First].TransparentColor = clNone) or
  247.               ((FImage.Frames[First].DisposalMethod = dmRestoreBackground) and
  248.               (First < Last)) then Break;
  249.           end;
  250.           Dec(First);
  251.         end;
  252.         for I := First to Last - 1 do begin
  253.           with FImage.Frames[I] do
  254.             case DisposalMethod of
  255.               dmUndefined, dmLeave:
  256.                 Draw(Canvas, Bounds(Origin.X, Origin.Y, Width, Height), True);
  257.               dmRestoreBackground:
  258.                 if I > First then
  259.                   Canvas.FillRect(Bounds(Origin.X, Origin.Y, Width, Height));
  260.               dmRestorePrevious:
  261.                 begin { do nothing } end;
  262.             end;
  263.         end;
  264.       end
  265.       else begin
  266.         with FImage.Frames[FCacheIndex] do
  267.           if DisposalMethod = dmRestoreBackground then
  268.             Canvas.FillRect(Bounds(Origin.X, Origin.Y, Width, Height));
  269.       end; { UseCache }
  270.       with FImage.Frames[Last] do
  271.         Draw(Canvas, Bounds(Origin.X, Origin.Y, Width, Height), True);
  272. {$IFDEF RX_D3}
  273.       if (not UseCache) and (TransColor <> clNone) and FTransparent then
  274.       begin
  275.         TransparentColor := PaletteColor(TransColor);
  276.         Transparent := True;
  277.       end;
  278. {$ENDIF}
  279.       if FImage.Palette <> 0 then
  280.         SelectPalette(Canvas.Handle, SavePal, False);
  281.     end;
  282.     FCache := Result;
  283.     FCacheIndex := Index;
  284.     FTransColor := TransColor;
  285. {$IFDEF RX_D3}
  286.     Result.Canvas.Unlock;
  287. {$ENDIF}
  288.   except
  289. {$IFDEF RX_D3}
  290.     Result.Canvas.Unlock;
  291. {$ENDIF}
  292.     if not UseCache then Result.Free;
  293.     raise;
  294.   end;
  295. end;
  296. function TRxGIFAnimator.GetPalette: HPALETTE;
  297. begin
  298.   Result := 0;
  299.   if not FImage.Empty then Result := FImage.Palette;
  300. end;
  301. procedure TRxGIFAnimator.ImageChanged(Sender: TObject);
  302. begin
  303.   Lock;
  304.   try
  305.     FCacheIndex := -1;
  306.     FCache.Free;
  307.     FCache := nil;
  308.     FTransColor := clNone;
  309.     FFrameIndex := FImage.FrameIndex;
  310.     if (FFrameIndex >= 0) and (FImage.Count > 0) then
  311.       FTimer.Interval := GetDelayTime(FFrameIndex);
  312.   finally
  313.     Unlock;
  314.   end;
  315.   PictureChanged;
  316.   Change;
  317. end;
  318. procedure TRxGIFAnimator.SetImage(Value: TGIFImage);
  319. begin
  320.   Lock;
  321.   try
  322.     FImage.Assign(Value);
  323.   finally
  324.     Unlock;
  325.   end;
  326. end;
  327. procedure TRxGIFAnimator.SetCenter(Value: Boolean);
  328. begin
  329.   if Value <> FCenter then begin
  330.     Lock;
  331.     try
  332.       FCenter := Value;
  333.     finally
  334.       Unlock;
  335.     end;
  336.     PictureChanged;
  337.     if Animate then Repaint;
  338.   end;
  339. end;
  340. procedure TRxGIFAnimator.SetStretch(Value: Boolean);
  341. begin
  342.   if Value <> FStretch then begin
  343.     Lock;
  344.     try
  345.       FStretch := Value;
  346.     finally
  347.       Unlock;
  348.     end;
  349.     PictureChanged;
  350.     if Animate then Repaint;
  351.   end;
  352. end;
  353. procedure TRxGIFAnimator.SetTransparent(Value: Boolean);
  354. begin
  355.   if Value <> FTransparent then begin
  356.     Lock;
  357.     try
  358.       FTransparent := Value;
  359.     finally
  360.       Unlock;
  361.     end;
  362.     PictureChanged;
  363.     if Animate then Repaint;
  364.   end;
  365. end;
  366. procedure TRxGIFAnimator.SetFrameIndex(Value: Integer);
  367. begin
  368.   if Value <> FFrameIndex then begin
  369.     if (Value < FImage.Count) and (Value >= 0) then begin
  370.       Lock;
  371.       try
  372.         FFrameIndex := Value;
  373.         if (FFrameIndex >= 0) and (FImage.Count > 0) then
  374.           FTimer.Interval := GetDelayTime(FFrameIndex);
  375.       finally
  376.         Unlock;
  377.       end;
  378.       FrameChanged;
  379.       PictureChanged;
  380.     end;
  381.   end;
  382. end;
  383. procedure TRxGIFAnimator.DoPaintImage;
  384. var
  385.   Frame: TBitmap;
  386.   Dest: TRect;
  387.   TransColor: TColor;
  388. begin
  389.   { copy image from parent and back-level controls }
  390.   if FImage.Transparent or FImage.Empty then
  391.     CopyParentImage(Self, Canvas);
  392.   if (not FImage.Empty) and (FImage.ScreenWidth > 0) and
  393.     (FImage.ScreenHeight> 0) then
  394.   begin
  395.     TransColor := clNone;
  396.     Frame := GetFrameBitmap(FrameIndex, TransColor);
  397. {$IFDEF RX_D3}
  398.     Frame.Canvas.Lock;
  399.     try
  400. {$ENDIF}
  401.       if Stretch then Dest := ClientRect
  402.       else if Center then
  403.         Dest := Bounds((ClientWidth - Frame.Width) div 2,
  404.           (ClientHeight - Frame.Height) div 2, Frame.Width, Frame.Height)
  405.       else
  406.         Dest := Rect(0, 0, Frame.Width, Frame.Height);
  407.       if (TransColor = clNone) or not FTransparent then
  408.         Canvas.StretchDraw(Dest, Frame)
  409.       else begin
  410.         StretchBitmapRectTransparent(Canvas, Dest.Left, Dest.Top,
  411.           WidthOf(Dest), HeightOf(Dest), Bounds(0, 0, Frame.Width,
  412.           Frame.Height), Frame, TransColor);
  413.       end;
  414. {$IFDEF RX_D3}
  415.     finally
  416.       Frame.Canvas.Unlock;
  417.     end;
  418. {$ENDIF}
  419.   end;
  420. end;
  421. procedure TRxGIFAnimator.Paint;
  422. begin
  423.   PaintImage;
  424.   if FImage.Transparent or FImage.Empty then
  425.     PaintDesignRect;
  426. end;
  427. procedure TRxGIFAnimator.TimerDeactivate;
  428. var
  429.   F: TCustomForm;
  430. begin
  431.   SetAnimate(False);
  432.   if (csDesigning in ComponentState) then begin
  433.     F := GetParentForm(Self);
  434.     if (F <> nil) and (F.Designer <> nil) then
  435.       F.Designer.Modified;
  436.   end;
  437. end;
  438. procedure TRxGIFAnimator.TimerExpired(Sender: TObject);
  439. begin
  440. {$IFDEF RX_D3}
  441.   if csPaintCopy in ControlState then Exit;
  442. {$ENDIF}
  443.   if Visible and (FImage.Count > 1) and (Parent <> nil) and
  444.     Parent.HandleAllocated then
  445.   begin
  446.     Lock;
  447.     try
  448.       if FFrameIndex < FImage.Count - 1 then Inc(FFrameIndex)
  449.       else FFrameIndex := 0;
  450. {$IFDEF RX_D3}
  451.       Canvas.Lock;
  452.       try
  453.         FTimerRepaint := True;
  454.         if AsyncDrawing and Assigned(FOnFrameChanged) then
  455.           FTimer.Synchronize(FrameChanged)
  456.         else FrameChanged;
  457.         DoPaintControl;
  458.       finally
  459.         FTimerRepaint := False;
  460.         Canvas.Unlock;
  461.         if (FFrameIndex >= 0) and (FFrameIndex < FImage.Count) then
  462.           FTimer.Interval := GetDelayTime(FFrameIndex);
  463.       end;
  464.       if not FLoop and (FFrameIndex = 0) then
  465.         if AsyncDrawing then FTimer.Synchronize(TimerDeactivate)
  466.         else TimerDeactivate;
  467. {$ELSE}
  468.       FTimerRepaint := True;
  469.       try
  470.         FrameChanged;
  471.         Repaint;
  472.       finally
  473.         FTimerRepaint := False;
  474.         if (FFrameIndex >= 0) and (FFrameIndex < FImage.Count) then
  475.           FTimer.Interval := GetDelayTime(FFrameIndex);
  476.       end;
  477.       if not FLoop and (FFrameIndex = 0) then TimerDeactivate;
  478. {$ENDIF}
  479.     finally
  480.       Unlock;
  481.     end;
  482.   end;
  483. end;
  484. procedure TRxGIFAnimator.Change;
  485. begin
  486.   if Assigned(FOnChange) then FOnChange(Self);
  487. end;
  488. procedure TRxGIFAnimator.FrameChanged;
  489. begin
  490.   if Assigned(FOnFrameChanged) then FOnFrameChanged(Self);
  491. end;
  492. procedure TRxGIFAnimator.Stop;
  493. begin
  494.   if Assigned(FOnStop) then FOnStop(Self);
  495. end;
  496. procedure TRxGIFAnimator.Start;
  497. begin
  498.   if Assigned(FOnStart) then FOnStart(Self);
  499. end;
  500. {$IFNDEF RX_D4}
  501. procedure TRxGIFAnimator.SetAutoSize(Value: Boolean);
  502. begin
  503.   if Value <> FAutoSize then begin
  504.     FAutoSize := Value;
  505.     PictureChanged;
  506.   end;
  507. end;
  508. {$ENDIF}
  509. {$IFDEF RX_D3}
  510. procedure TRxGIFAnimator.SetAsyncDrawing(Value: Boolean);
  511. begin
  512.   if FAsyncDrawing <> Value then begin
  513.     Lock;
  514.     try
  515.       if Value then HookBitmap;
  516.       if Assigned(FTimer) then FTimer.SyncEvent := not Value;
  517.       FAsyncDrawing := Value;
  518.     finally
  519.       Unlock;
  520.     end;
  521.   end;
  522. end;
  523. {$ENDIF}
  524. procedure TRxGIFAnimator.SetAnimate(Value: Boolean);
  525. begin
  526.   if FAnimate <> Value then begin
  527.     if Value then begin
  528.       FTimer.OnTimer := TimerExpired;
  529.       FTimer.Enabled := True;
  530.       FAnimate := FTimer.Enabled;
  531.       Start;
  532.     end
  533.     else begin
  534.       FTimer.Enabled := False;
  535.       FTimer.OnTimer := nil;
  536.       FAnimate := False;
  537.       Stop;
  538.       PictureChanged;
  539.     end;
  540.   end;
  541. end;
  542. procedure TRxGIFAnimator.WMSize(var Message: TWMSize);
  543. begin
  544.   inherited;
  545. {$IFNDEF RX_D4}
  546.   AdjustSize;
  547. {$ENDIF}
  548. end;
  549. end.