home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d6 / RX275D6.ZIP / Units / GIFCTRL.PAS < prev    next >
Pascal/Delphi Source File  |  1999-10-12  |  16KB  |  586 lines

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