home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / GIFCTRL.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  15.6 KB  |  587 lines

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