home *** CD-ROM | disk | FTP | other *** search
/ PC World 1999 February / PCWorld_1999-02_cd.bin / temacd / HotKeys / AniIcons.pas < prev    next >
Pascal/Delphi Source File  |  1998-06-28  |  12KB  |  447 lines

  1. unit AniIcons;
  2.  
  3. interface
  4.  
  5. uses Windows, Classes, Graphics, SysUtils, TmrPool;
  6.  
  7. type
  8.   EIconListError = class(Exception);
  9.   
  10.   TNewFrameEvent = procedure(Sender: TObject; Frame: Integer) of object;
  11.  
  12.   TIconSize = (is16x16, is32x32);
  13.  
  14.   TAnimatedIcons = class;
  15.  
  16.   TAnimatedIcon = class(TIcon)
  17.   private
  18.     FDisplayTime: Longint;
  19.   public
  20.     procedure Assign(Source: TPersistent); override;
  21.     procedure LoadFromStream(Stream: TStream); override;
  22.     procedure SaveToStream(Stream: TStream); override;
  23.     property DisplayTime: Longint read FDisplayTime write FDisplayTime;
  24.   end;
  25.  
  26.   TAnimatedIcons = class(TPersistent)
  27.   private
  28.     { property variables }
  29.     FAuthor       : String;
  30.     FIcons        : TList;
  31.     FIconIndex    : Integer;
  32.     FIconSize     : TIconSize;
  33.     FPlaying      : Boolean;
  34.     FTitle        : String;
  35.     { Event variables }
  36.     FOnNewFrame   : TNewFrameEvent;
  37.     FOnStopped    : TNotifyEvent;
  38.     { Private variables }
  39.     FBrush        : TBrush;
  40.     FDrawSize     : Integer;
  41.     FCurrentTiming: Integer;
  42.     FCurrentLoop  : Integer;
  43.     FTotalLoops   : Integer;
  44.     { Private routines (property get/set) }
  45.     procedure SetIconIndex(Value: Integer);
  46.     { Private routines (object streaming) }
  47.     procedure WriteString(Stream: TStream; Value: String);
  48.     function  ReadString(Stream: TStream): String;
  49.     procedure ReadData(Stream: TStream);
  50.     procedure WriteData(Stream: TStream);
  51.   protected
  52.     { Protected routines }
  53.     procedure cmTimerElapsed(var Msg: TCMTimerElapsed); message CM_TIMERELAPSED;
  54.     procedure SetDrawSize;
  55.     procedure DefineProperties(Filer: TFiler); override;
  56.     function  Get(Index: Integer): TAnimatedIcon;
  57.     function  GetCount: Integer;
  58.     procedure Put(Index: Integer; const Icon: TAnimatedIcon);
  59.   public
  60.     { constructor / destructor }
  61.     constructor Create(Size: TIconSize);
  62.     destructor Destroy; override;
  63.     { public methods }
  64.     function  Add(const Icon: TAnimatedIcon): Integer;
  65.     function  AddIcon: TAnimatedIcon;
  66.     procedure AddIcons(Icons: TAnimatedIcons);
  67.     procedure Assign(Source: TPersistent); override;
  68.     procedure Clear;
  69.     procedure Delete(Index: Integer);
  70.     function  Equals(Icons: TAnimatedIcons): Boolean;
  71.     procedure Exchange(Index1, Index2: Integer);
  72.     procedure Insert(Index: Integer; const Icon: TAnimatedIcon);
  73.     procedure Move(CurIndex, NewIndex: Integer);
  74.     procedure LoadFromFile(const FileName: string);
  75.     procedure LoadFromStream(Stream: TStream);
  76.     procedure SaveToFile(const FileName: string);
  77.     procedure SaveToStream(Stream: TStream);
  78.     procedure Play(NrOfTimes: Integer);
  79.     procedure Stop;
  80.     procedure DrawIcon(Canvas: TCanvas; X, Y, Index: Integer; MaskColor: TColor);
  81.     { properties }
  82.     property  Count: Integer read GetCount;
  83.     property  IconIndex: Integer read FIconIndex write SetIconIndex;
  84.     property  IconSize: TIconSize read FIconSize;
  85.     property  Icons[Index: Integer]: TAnimatedIcon read Get write Put; default;
  86.   published
  87.     property  Author: String read FAuthor write FAuthor;
  88.     property  Playing: Boolean read FPlaying default False;
  89.     property  Title: String read FTitle write FTitle;
  90.     { animation event }
  91.     property  OnNewFrame: TNewFrameEvent read FOnNewFrame write FOnNewFrame;
  92.     property  OnStopped: TNotifyEvent read FOnStopped write FOnStopped;
  93.   end;
  94.  
  95. implementation
  96.  
  97. { TAnimatedIcon }
  98. procedure TAnimatedIcon.Assign(Source: TPersistent);
  99. begin
  100.   if Source is TAnimatedIcon then DisplayTime := TAnimatedIcon(Source).DisplayTime;
  101.   inherited Assign(Source);
  102. end;
  103.  
  104. procedure TAnimatedIcon.LoadFromStream(Stream: TStream);
  105. var
  106.   MStream: TMemoryStream;
  107.   lSize  : Longint;
  108.   P      : PChar;
  109. begin
  110.   Stream.Read(FDisplayTime, sizeof(Longint));
  111.   Stream.Read(lSize, sizeof(Longint));
  112.   if lSize>0 then
  113.    begin
  114.      MStream := TMemoryStream.Create;
  115.      try
  116.        P := StrAlloc(lSize+1);
  117.        try
  118.          Stream.Read(P^, lSize);
  119.          MStream.Write(P^, lSize);
  120.        finally
  121.          StrDispose(P);
  122.        end;
  123.        MStream.Position := 0;
  124.        inherited LoadFromStream(MStream);
  125.      finally
  126.        MStream.Free;
  127.      end;
  128.   end;
  129. end;
  130.  
  131. procedure TAnimatedIcon.SaveToStream(Stream: TStream);
  132. var
  133.   MStream: TMemoryStream;
  134.   lSize  : Longint;
  135.   P      : PChar;
  136. begin
  137.   Stream.Write(FDisplayTime, sizeof(Longint));
  138.   MStream := TMemoryStream.Create;
  139.   try
  140.     inherited SaveToStream(MStream);
  141.     lSize := MStream.Size;
  142.     Stream.Write(lSize, sizeof(LongInt));
  143.     MStream.Position := 0;
  144.     P := StrAlloc(lSize+1);
  145.     try
  146.       MStream.Read(P^, lSize);
  147.       Stream.Write(P^, lSize);
  148.     finally
  149.       StrDispose(P);
  150.     end;
  151.   finally
  152.     MStream.Free;
  153.   end;
  154. end;
  155.  
  156. { TAnimatedIcons }
  157. constructor TAnimatedIcons.Create(Size: TIconSize);
  158. begin
  159.   inherited Create;
  160.   FIconSize := Size;
  161.   SetDrawSize;
  162.   FIcons := TList.Create;
  163.   FBrush := TBrush.Create;
  164.   TimerPool.NotifyRegister(Self, False);
  165. end;
  166.  
  167. destructor TAnimatedIcons.Destroy;
  168. begin
  169.   TimerPool.NotifyUnregister(Self);
  170.   Clear;
  171.   FIcons.Free;
  172.   FBrush.Free;
  173.   inherited Destroy;
  174. end;
  175.  
  176. procedure TAnimatedIcons.SetIconIndex(Value: Integer);
  177. begin
  178.   if FIconIndex<>Value then
  179.    begin
  180.      if (Value>=0) and (Value<Count) then
  181.       FIconIndex := Value
  182.      else
  183.       raise EIconListError.Create('Icon list index out of bounds');
  184.    end;
  185. end;
  186.  
  187. function TAnimatedIcons.Add(const Icon: TAnimatedIcon): Integer;
  188. begin
  189.   Result := GetCount;
  190.   Insert(Result, Icon);
  191. end;
  192.  
  193. function TAnimatedIcons.AddIcon: TAnimatedIcon;
  194. begin
  195.   Result := TAnimatedIcon.Create;
  196.   FIcons.Add(Result);
  197. end;
  198.  
  199. procedure TAnimatedIcons.AddIcons(Icons: TAnimatedIcons);
  200. var
  201.   I: Integer;
  202. begin
  203.   for I := 0 to Icons.Count - 1 do Add(Icons[I]);
  204. end;
  205.  
  206. procedure TAnimatedIcons.Assign(Source: TPersistent);
  207. begin
  208.   if Source is TAnimatedIcons then
  209.    begin
  210.      FAuthor := TAnimatedIcons(Source).Author;
  211.      FTitle := TAnimatedIcons(Source).Title;
  212.      FIconSize := TAnimatedIcons(Source).IconSize;
  213.      SetDrawSize;
  214.      Clear;
  215.      AddIcons(TAnimatedIcons(Source));
  216.    end
  217.   else
  218.    inherited Assign(Source);
  219. end;
  220.  
  221. procedure TAnimatedIcons.DefineProperties(Filer: TFiler);
  222.  
  223.   function DoWrite: Boolean;
  224.   begin
  225.     if Filer.Ancestor <> nil then
  226.     begin
  227.       Result := True;
  228.       if Filer.Ancestor is TAnimatedIcons then
  229.         Result := not Equals(TAnimatedIcons(Filer.Ancestor))
  230.     end
  231.     else Result := Count > 0;
  232.   end;
  233.  
  234. begin
  235.   Filer.DefineBinaryProperty('Icons', ReadData, WriteData, DoWrite);
  236. end;
  237.  
  238. function TAnimatedIcons.Equals(Icons: TAnimatedIcons): Boolean;
  239. var
  240.   I, Count: Integer;
  241. begin
  242.   Result := False;
  243.   Count := GetCount;
  244.   if Count <> Icons.GetCount then Exit;
  245.   for I := 0 to Count - 1 do if Get(I) <> Icons.Get(I) then Exit;
  246.   Result := True;
  247. end;
  248.  
  249. procedure TAnimatedIcons.Exchange(Index1, Index2: Integer);
  250. begin
  251.   FIcons.Exchange(Index1, Index2);
  252. end;
  253.  
  254. procedure TAnimatedIcons.Move(CurIndex, NewIndex: Integer);
  255. begin
  256.   FIcons.Move(CurIndex, NewIndex);
  257. end;
  258.  
  259. function TAnimatedIcons.GetCount: Integer;
  260. begin
  261.   Result := FIcons.Count;
  262. end;
  263.  
  264. function TAnimatedIcons.Get(Index: Integer): TAnimatedIcon;
  265. begin
  266.   Result := TAnimatedIcon(FIcons[Index]);
  267. end;
  268.  
  269. procedure TAnimatedIcons.Put(Index: Integer; const Icon: TAnimatedIcon);
  270. begin
  271.   Delete(Index);
  272.   Insert(Index, Icon);
  273. end;
  274.  
  275. procedure TAnimatedIcons.Clear;
  276. begin
  277.   while Count>0 do Delete(0);
  278. end;
  279.  
  280. procedure TAnimatedIcons.Delete(Index: Integer);
  281. begin
  282.   TAnimatedIcon(FIcons[Index]).Free;
  283.   FIcons.Delete(Index);
  284.   FIcons.Pack;
  285. end;
  286.  
  287. procedure TAnimatedIcons.Insert(Index: Integer; const Icon: TAnimatedIcon);
  288. var
  289.   NewIcon: TAnimatedIcon;
  290. begin
  291.   NewIcon := TAnimatedIcon.Create;
  292.   NewIcon.Assign(Icon);
  293.   FIcons.Insert(Index, NewIcon);
  294. end;
  295.  
  296. procedure TAnimatedIcons.LoadFromFile(const FileName: string);
  297. var
  298.   Stream: TStream;
  299. begin
  300.   Stream := TFileStream.Create(FileName, fmOpenRead);
  301.   try
  302.     LoadFromStream(Stream);
  303.   finally
  304.     Stream.Free;
  305.   end;
  306. end;
  307.  
  308. function TAnimatedIcons.ReadString(Stream: TStream): String;
  309. var
  310.   i, iCount : Integer;
  311.   cLetter   : Char;
  312. begin
  313.   Result := '';
  314.   with Stream do
  315.    begin
  316.      Read(iCount, sizeof(Longint));
  317.      for i:=1 to iCount do
  318.       begin
  319.         Read(cLetter, sizeof(Char));
  320.         Result := Result + cLetter;
  321.       end;
  322.    end;
  323. end;
  324.  
  325. procedure TAnimatedIcons.WriteString(Stream: TStream; Value: String);
  326. var
  327.   i, iCount : Integer;
  328. begin
  329.   iCount := Length(Value);
  330.   with Stream do
  331.    begin
  332.      Write(iCount, sizeof(Longint));
  333.      for i:=1 to iCount do
  334.       Write(Value[i], sizeof(Char));
  335.    end;
  336. end;
  337.  
  338. procedure TAnimatedIcons.LoadFromStream(Stream: TStream);
  339. var
  340.   i, iCount: Longint;
  341. begin
  342.   FTitle := ReadString(Stream);
  343.   FAuthor := ReadString(Stream);
  344.   Stream.Read(FIconSize, sizeof(TIconSize));
  345.   SetDrawSize;
  346.   Stream.Read(iCount, sizeof(LongInt));
  347.   Clear;
  348.   for i:=0 to iCount-1 do
  349.    AddIcon.LoadFromStream(Stream);
  350. end;
  351.  
  352. procedure TAnimatedIcons.ReadData(Stream: TStream);
  353. begin
  354.   LoadFromStream(Stream);
  355. end;
  356.  
  357. procedure TAnimatedIcons.SaveToFile(const FileName: string);
  358. var
  359.   Stream: TStream;
  360. begin
  361.   Stream := TFileStream.Create(FileName, fmCreate);
  362.   try
  363.     SaveToStream(Stream);
  364.   finally
  365.     Stream.Free;
  366.   end;
  367. end;
  368.  
  369. procedure TAnimatedIcons.SaveToStream(Stream: TStream);
  370. var
  371.   i, iCount: Integer;
  372. begin
  373.   iCount := Count;
  374.   WriteString(Stream, FTitle);
  375.   WriteString(Stream, FAuthor);
  376.   Stream.Write(FIconSize, sizeof(TIconSize));
  377.   Stream.Write(iCount, sizeof(LongInt));
  378.   for I := 0 to iCount - 1 do
  379.    Icons[I].SaveToStream(Stream);
  380. end;
  381.  
  382. procedure TAnimatedIcons.WriteData(Stream: TStream);
  383. begin
  384.   SaveToStream(Stream);
  385. end;
  386.  
  387. procedure TAnimatedIcons.cmTimerElapsed(var Msg: TCMTimerElapsed);
  388. begin
  389.   if (FIconIndex>=FIcons.Count) then
  390.    begin
  391.      FIconIndex := 0;
  392.      if (FIcons.Count = 0) then Exit;
  393.    end;
  394.   inc(FCurrentTiming, Msg.MilliSeconds);
  395.   if FCurrentTiming>=Icons[FIconIndex].DisplayTime*10 then
  396.    begin
  397.      if Assigned(FOnNewFrame) then FOnNewFrame(Self, FIconIndex);
  398.      inc(FIconIndex);
  399.      if FIconIndex>=Count then
  400.       begin
  401.         FIconIndex := 0;
  402.         if FTotalLoops>0 then
  403.          begin
  404.            inc(FCurrentLoop);
  405.            if FCurrentLoop = FTotalLoops then Stop;
  406.          end;
  407.       end;
  408.      FCurrentTiming := 0;
  409.    end;
  410. end;
  411.  
  412. procedure TAnimatedIcons.Play(NrOfTimes: Integer);
  413. begin
  414.   if not Assigned(FOnNewFrame) or (Count=0) then Exit;
  415.   FIconIndex := 0;
  416.   FCurrentTiming := 0;
  417.   FPlaying := True;
  418.   FTotalLoops := NrOfTimes;
  419.   FCurrentLoop := 0;
  420.   TimerPool.NotifyRegister(Self, True);
  421. end;
  422.  
  423. procedure TAnimatedIcons.Stop;
  424. begin
  425.   TimerPool.NotifyRegister(Self, False);
  426.   FPlaying := False;
  427.   if Assigned(FOnStopped) then FOnStopped(Self);
  428. end;
  429.  
  430. procedure TAnimatedIcons.SetDrawSize;
  431. begin
  432.   if FIconSize=is16x16 then FDrawSize := 16 else FDrawSize := 32;
  433. end;
  434.  
  435. procedure TAnimatedIcons.DrawIcon(Canvas: TCanvas; X, Y, Index: Integer; MaskColor: TColor);
  436. begin
  437.   if not Assigned(Canvas) then Exit;
  438.   if (Index>=0) and (Index<FIcons.Count) then
  439.    begin
  440.      FBrush.Color := MaskColor;
  441.      DrawIconEx(Canvas.Handle, X, Y, TIcon(FIcons[Index]).Handle, FDrawSize, FDrawSize, 0,
  442.                 FBrush.Handle, DI_NORMAL);
  443.    end;
  444. end;
  445.  
  446. end.
  447.