home *** CD-ROM | disk | FTP | other *** search
/ QBasic & Borland Pascal & C / Delphi5.iso / Runimage / Delphi50 / Source / Vcl / IMGLIST.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-08-11  |  34.2 KB  |  1,262 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Borland Delphi Visual Component Library         }
  5. {                                                       }
  6. {       Copyright (c) 1995,99 Inprise Corporation       }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit ImgList;
  11.  
  12. {$R-,T-,H+,X+}
  13.  
  14. interface
  15.  
  16. uses Windows, Classes, Graphics, CommCtrl;
  17.  
  18. type
  19.  
  20. { TChangeLink }
  21.  
  22.   TCustomImageList = class;
  23.  
  24.   TChangeLink = class(TObject)
  25.   private
  26.     FSender: TCustomImageList;
  27.     FOnChange: TNotifyEvent;
  28.   public
  29.     destructor Destroy; override;
  30.     procedure Change; dynamic;
  31.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  32.     property Sender: TCustomImageList read FSender write FSender;
  33.   end;
  34.  
  35. { TCustomImageList }
  36.  
  37.   TDrawingStyle = (dsFocus, dsSelected, dsNormal, dsTransparent);
  38.   TImageType = (itImage, itMask);
  39.   TResType = (rtBitmap, rtCursor, rtIcon);
  40.   TOverlay = 0..3;
  41.   TLoadResource = (lrDefaultColor, lrDefaultSize, lrFromFile,
  42.     lrMap3DColors, lrTransparent, lrMonoChrome);
  43.   TLoadResources = set of TLoadResource;
  44.   TImageIndex = type Integer;
  45.  
  46.   TCustomImageList = class(TComponent)
  47.   private
  48.     FHeight: Integer;
  49.     FWidth: Integer;
  50.     FAllocBy: Integer;
  51.     FHandle: HImageList;
  52.     FDrawingStyle: TDrawingStyle;
  53.     FMasked: Boolean;
  54.     FShareImages: Boolean;
  55.     FImageType: TImageType;
  56.     FBkColor: TColor;
  57.     FBlendColor: TColor;
  58.     FClients: TList;
  59.     FBitmap: TBitmap;
  60.     FMonoBitmap: TBitmap;
  61.     FChanged: Boolean;
  62.     FUpdateCount: Integer;
  63.     FOnChange: TNotifyEvent;
  64.     procedure BeginUpdate;
  65.     procedure EndUpdate;
  66.     procedure InitBitmap;
  67.     procedure CheckImage(Image: TGraphic);
  68.     procedure CopyImages(Value: HImageList);
  69.     procedure CreateImageList;
  70.     function Equal(IL: TCustomImageList): Boolean;
  71.     procedure FreeHandle;
  72.     function GetCount: Integer;
  73.     function GetBitmapHandle(Bitmap: HBITMAP): HBITMAP;
  74.     function GetBkColor: TColor;
  75.     function GetHandle: HImageList;
  76.     function GetImageHandle(Image, ImageDDB: TBitmap): HBITMAP;
  77.     procedure InsertImage(Index: Integer; Image, Mask: TBitmap; MaskColor: TColor);
  78.     procedure ReadData(Stream: TStream);
  79.     procedure SetBkColor(Value: TColor);
  80.     procedure SetDrawingStyle(Value: TDrawingStyle);
  81.     procedure SetHandle(Value: HImageList);
  82.     procedure SetHeight(Value: Integer);
  83.     procedure SetNewDimensions(Value: HImageList);
  84.     procedure SetWidth(Value: Integer);
  85.     procedure WriteData(Stream: TStream);
  86.     procedure ReadD2Stream(Stream: TStream);
  87.     procedure ReadD3Stream(Stream: TStream);
  88.   protected
  89.     procedure AssignTo(Dest: TPersistent); override;
  90.     procedure Change; dynamic;
  91.     procedure DefineProperties(Filer: TFiler); override;
  92.     procedure DoDraw(Index: Integer; Canvas: TCanvas; X, Y: Integer;
  93.       Style: Cardinal; Enabled: Boolean); virtual;
  94.     procedure GetImages(Index: Integer; Image, Mask: TBitmap);
  95.     procedure HandleNeeded;
  96.     procedure Initialize; virtual;
  97.   public
  98.     constructor Create(AOwner: TComponent); override;
  99.     constructor CreateSize(AWidth, AHeight: Integer);
  100.     destructor Destroy; override;
  101.     procedure Assign(Source: TPersistent); override;
  102.     function Add(Image, Mask: TBitmap): Integer;
  103.     function AddIcon(Image: TIcon): Integer;
  104.     procedure AddImages(Value: TCustomImageList);
  105.     function AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
  106.     procedure Clear;
  107.     procedure Delete(Index: Integer);
  108.     procedure Draw(Canvas: TCanvas; X, Y, Index: Integer; Enabled: Boolean=True);
  109.     procedure DrawOverlay(Canvas: TCanvas; X, Y: Integer;
  110.       ImageIndex: Integer; Overlay: TOverlay; Enabled: Boolean=True);
  111.     function FileLoad(ResType: TResType; Name: string;
  112.       MaskColor: TColor): Boolean;
  113.     procedure GetBitmap(Index: Integer; Image: TBitmap);
  114.     function GetHotSpot: TPoint; virtual;
  115.     procedure GetIcon(Index: Integer; Image: TIcon);
  116.     function GetImageBitmap: HBITMAP;
  117.     function GetMaskBitmap: HBITMAP;
  118.     function GetResource(ResType: TResType; Name: string;
  119.       Width: Integer; LoadFlags: TLoadResources; MaskColor: TColor): Boolean;
  120.     function GetInstRes(Instance: THandle; ResType: TResType; Name: string;
  121.       Width: Integer; LoadFlags: TLoadResources; MaskColor: TColor): Boolean;
  122.     function HandleAllocated: Boolean;
  123.     procedure Insert(Index: Integer; Image, Mask: TBitmap);
  124.     procedure InsertIcon(Index: Integer; Image: TIcon);
  125.     procedure InsertMasked(Index: Integer; Image: TBitmap; MaskColor: TColor);
  126.     procedure Move(CurIndex, NewIndex: Integer);
  127.     function Overlay(ImageIndex: Integer; Overlay: TOverlay): Boolean;
  128.     procedure RegisterChanges(Value: TChangeLink);
  129.     function ResourceLoad(ResType: TResType; Name: string;
  130.       MaskColor: TColor): Boolean;
  131.     function ResInstLoad(Instance: THandle; ResType: TResType; Name: string;
  132.       MaskColor: TColor): Boolean;
  133.     procedure Replace(Index: Integer; Image, Mask: TBitmap);
  134.     procedure ReplaceIcon(Index: Integer; Image: TIcon);
  135.     procedure ReplaceMasked(Index: Integer; NewImage: TBitmap; MaskColor: TColor);
  136.     procedure UnRegisterChanges(Value: TChangeLink);
  137.     property Count: Integer read GetCount;
  138.     property Handle: HImageList read GetHandle write SetHandle;
  139.   public
  140.     property AllocBy: Integer read FAllocBy write FAllocBy default 4;
  141.     property BlendColor: TColor read FBlendColor write FBlendColor default clNone;
  142.     property BkColor: TColor read GetBkColor write SetBkColor default clNone;
  143.     property DrawingStyle: TDrawingStyle read FDrawingStyle write SetDrawingStyle default dsNormal;
  144.     property Height: Integer read FHeight write SetHeight default 16;
  145.     property ImageType: TImageType read FImageType write FImageType default itImage;
  146.     property Masked: Boolean read FMasked write FMasked default True;
  147.     property ShareImages: Boolean read FShareImages write FShareImages default False;
  148.     property Width: Integer read FWidth write SetWidth default 16;
  149.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  150.   end;
  151.  
  152. implementation
  153.  
  154. uses SysUtils, Consts, Forms;
  155.  
  156. { TCustomImageList }
  157.  
  158. function GetRGBColor(Value: TColor): DWORD;
  159. begin
  160.   Result := ColorToRGB(Value);
  161.   case Result of
  162.     clNone: Result := CLR_NONE;
  163.     clDefault: Result := CLR_DEFAULT;
  164.   end;
  165. end;
  166.  
  167. function GetColor(Value: DWORD): TColor;
  168. begin
  169.   case Value of
  170.     CLR_NONE: Result := clNone;
  171.     CLR_DEFAULT: Result := clDefault;
  172.   else
  173.     Result := TColor(Value);
  174.   end;
  175. end;
  176.  
  177. constructor TCustomImageList.Create(AOwner: TComponent);
  178. begin
  179.   inherited Create(AOwner);
  180.   FWidth := 16;
  181.   FHeight := 16;
  182.   Initialize;
  183. end;
  184.  
  185. constructor TCustomImageList.CreateSize(AWidth, AHeight: Integer);
  186. begin
  187.   inherited Create(nil);
  188.   FWidth := AWidth;
  189.   FHeight := AHeight;
  190.   Initialize;
  191. end;
  192.  
  193. destructor TCustomImageList.Destroy;
  194. begin
  195.   while FClients.Count > 0 do
  196.     UnRegisterChanges(TChangeLink(FClients.Last));
  197.   FBitmap.Free;
  198.   FreeHandle;
  199.   FClients.Free;
  200.   FClients := nil;
  201.   if FMonoBitmap <> nil then FMonoBitmap.Free;
  202.   inherited Destroy;
  203. end;
  204.  
  205. procedure TCustomImageList.Initialize;
  206. const
  207.   MaxSize = 32768;
  208. begin
  209.   FClients := TList.Create;
  210.   if (Height < 1) or (Height > MaxSize) or (Width < 1) then
  211.     raise EInvalidOperation.Create(SInvalidImageSize);
  212.   AllocBy := 4;
  213.   Masked := True;
  214.   DrawingStyle := dsNormal;
  215.   ImageType := itImage;
  216.   FBkColor := clNone;
  217.   FBlendColor := clNone;
  218.   FBitmap := TBitmap.Create;
  219.   InitBitmap;
  220. end;
  221.  
  222. function TCustomImageList.HandleAllocated: Boolean;
  223. begin
  224.   Result := FHandle <> 0;
  225. end;
  226.  
  227. procedure TCustomImageList.HandleNeeded;
  228. begin
  229.   if FHandle = 0 then CreateImageList;
  230. end;
  231.  
  232. procedure TCustomImageList.InitBitmap;
  233. var
  234.   ScreenDC: HDC;
  235. begin
  236.   ScreenDC := GetDC(0);
  237.   try
  238.     with FBitmap do
  239.     begin
  240.       Handle := CreateCompatibleBitmap(ScreenDC, Self.Width, Self.Height);
  241.       Canvas.Brush.Color := clBlack;
  242.       Canvas.FillRect(Rect(0, 0, Width, Height));
  243.     end;
  244.   finally
  245.     ReleaseDC(0, ScreenDC);
  246.   end;
  247.   if FMonoBitmap <> nil then
  248.   begin
  249.     FMonoBitmap.Free;
  250.     FMonoBitmap := nil;
  251.   end;
  252. end;
  253.  
  254. procedure TCustomImageList.SetNewDimensions(Value: HImageList);
  255. var
  256.   AHeight, AWidth: Integer;
  257. begin
  258.   AWidth := Width;
  259.   AHeight := Height;
  260.   ImageList_GetIconSize(Value, AWidth, AHeight);
  261.   FWidth := AWidth;
  262.   FHeight := AHeight;
  263.   InitBitmap;
  264. end;
  265.  
  266. procedure TCustomImageList.SetWidth(Value: Integer);
  267. begin
  268.   if Value <> Width then
  269.   begin
  270.     FWidth := Value;
  271.     if HandleAllocated then ImageList_SetIconSize(FHandle, Width, Height);
  272.     Clear;
  273.     InitBitmap;
  274.     Change;
  275.   end;
  276. end;
  277.  
  278. procedure TCustomImageList.SetHeight(Value: Integer);
  279. begin
  280.   if Value <> Height then
  281.   begin
  282.     FHeight := Value;
  283.     if HandleAllocated then ImageList_SetIconSize(FHandle, Width, Height);
  284.     Clear;
  285.     InitBitmap;
  286.     Change;
  287.   end;
  288. end;
  289.  
  290. procedure TCustomImageList.SetHandle(Value: HImageList);
  291. begin
  292.   FreeHandle;
  293.   if Value <> 0 then
  294.   begin
  295.     SetNewDimensions(Value);
  296.     FHandle := Value;
  297.     Change;
  298.   end;
  299. end;
  300.  
  301. function TCustomImageList.GetBitmapHandle(Bitmap: HBITMAP): HBITMAP;
  302. begin
  303.   if Bitmap <> 0 then
  304.     Result := Bitmap else
  305.     Result := FBitmap.Handle;
  306. end;
  307.  
  308. function TCustomImageList.GetHandle: HImageList;
  309. begin
  310.   HandleNeeded;
  311.   Result := FHandle;
  312. end;
  313.  
  314. function TCustomImageList.GetImageHandle(Image, ImageDDB: TBitmap): HBITMAP;
  315. begin
  316.   CheckImage(Image);
  317.   if Image <> nil then
  318.     if Image.HandleType = bmDDB then
  319.       Result := Image.Handle
  320.     else
  321.     begin
  322.       ImageDDB.Assign(Image);
  323.       ImageDDB.HandleType := bmDDB;
  324.       Result := ImageDDB.Handle;
  325.     end
  326.   else Result := FBitmap.Handle;
  327. end;
  328.  
  329. procedure TCustomImageList.FreeHandle;
  330. begin
  331.   if HandleAllocated and not ShareImages then
  332.     ImageList_Destroy(Handle);
  333.   FHandle := 0;
  334.   Change;
  335. end;
  336.  
  337. procedure TCustomImageList.CreateImageList;
  338. const
  339.   Mask: array[Boolean] of Longint = (0, ILC_MASK);
  340. begin
  341.   FHandle := ImageList_Create(Width, Height, ILC_COLORDDB or Mask[Masked],
  342.     AllocBy, AllocBy);
  343.   if FHandle = 0 then raise EInvalidOperation.Create(SInvalidImageList);
  344.   if FBkColor <> clNone then BkColor := FBkColor;
  345. end;
  346.  
  347. function TCustomImageList.GetImageBitmap: HBITMAP;
  348. var
  349.   Info: TImageInfo;
  350. begin
  351.   if (Count > 0) and ImageList_GetImageInfo(Handle, 0, Info) then
  352.   begin
  353.     Result := Info.hbmImage;
  354.     DeleteObject(Info.hbmMask);
  355.   end
  356.   else Result := 0;
  357. end;
  358.  
  359. function TCustomImageList.GetMaskBitmap: HBITMAP;
  360. var
  361.   Info: TImageInfo;
  362. begin
  363.   if (Count > 0) and ImageList_GetImageInfo(Handle, 0, Info) then
  364.   begin
  365.     Result := Info.hbmMask;
  366.     DeleteObject(Info.hbmImage);
  367.   end
  368.   else Result := 0;
  369. end;
  370.  
  371. function TCustomImageList.Add(Image, Mask: TBitmap): Integer;
  372. var
  373.   ImageDDB, MaskDDB: TBitmap;
  374. begin
  375.   ImageDDB := TBitmap.Create;
  376.   try
  377.     MaskDDB := TBitmap.Create;
  378.     try
  379.       HandleNeeded;
  380.       Result := ImageList_Add(FHandle, GetImageHandle(Image, ImageDDB),
  381.         GetImageHandle(Mask, MaskDDB));
  382.     finally
  383.       MaskDDB.Free;
  384.     end;
  385.   finally
  386.     ImageDDB.Free;
  387.   end;
  388.   Change;
  389. end;
  390.  
  391. function TCustomImageList.AddMasked(Image: TBitmap; MaskColor: TColor): Integer;
  392. var
  393.   ImageDDB: TBitmap;
  394. begin
  395.   ImageDDB := TBitmap.Create;
  396.   try
  397.     if Masked and (MaskColor <> -1) then
  398.     begin
  399.       with TBitmap.Create do
  400.       try
  401.         Assign(Image);
  402.         TransparentColor := MaskColor;
  403.         Self.HandleNeeded;
  404.         Result := ImageList_Add(Self.FHandle, GetImageHandle(Image, ImageDDB),
  405.           GetBitmapHandle(MaskHandle));
  406.       finally
  407.         Free;
  408.       end;
  409.     end
  410.     else Result := ImageList_Add(Handle, GetImageHandle(Image, ImageDDB), 0);
  411.   finally
  412.     ImageDDB.Free;
  413.   end;
  414.   Change;
  415. end;
  416.  
  417. function TCustomImageList.AddIcon(Image: TIcon): Integer;
  418. begin
  419.   if Image = nil then
  420.     Result := Add(nil, nil)
  421.   else
  422.   begin
  423.     CheckImage(Image);
  424.     Result := ImageList_AddIcon(Handle, Image.Handle);
  425.   end;
  426.   Change;
  427. end;
  428.  
  429. procedure TCustomImageList.GetBitmap(Index: Integer; Image: TBitmap);
  430. begin
  431.   if (Image <> nil) and HandleAllocated then
  432.     with Image do
  433.     begin
  434.       Height := FHeight;
  435.       Width := FWidth;
  436.       Draw(Canvas, 0, 0, Index);
  437.     end;
  438. end;
  439.  
  440. procedure TCustomImageList.GetIcon(Index: Integer; Image: TIcon);
  441. const
  442.   DrawingStyles: array[TDrawingStyle] of Longint = (ILD_FOCUS,
  443.     ILD_SELECTED, ILD_NORMAL, ILD_TRANSPARENT);
  444.   Images: array[TImageType] of Longint = (0, ILD_MASK);
  445. begin
  446.   if (Image <> nil) and HandleAllocated then
  447.     Image.Handle := ImageList_GetIcon(Handle, Index,
  448.       DrawingStyles[DrawingStyle] or Images[ImageType]);
  449. end;
  450.  
  451. function TCustomImageList.GetCount: Integer;
  452. begin
  453.   if HandleAllocated then Result := ImageList_GetImageCount(Handle)
  454.   else Result := 0;
  455. end;
  456.  
  457. procedure TCustomImageList.Replace(Index: Integer; Image, Mask: TBitmap);
  458. var
  459.   ImageDDB, MaskDDB: TBitmap;
  460. begin
  461.   ImageDDB := TBitmap.Create;
  462.   try
  463.     MaskDDB := TBitmap.Create;
  464.     try
  465.       if HandleAllocated and not ImageList_Replace(Handle, Index,
  466.         GetImageHandle(Image, ImageDDB), GetImageHandle(Mask, MaskDDB)) then
  467.           raise EInvalidOperation.Create(SReplaceImage);
  468.     finally
  469.       MaskDDB.Free;
  470.     end;
  471.   finally
  472.     ImageDDB.Free;
  473.   end;
  474.   Change;
  475. end;
  476.  
  477. procedure TCustomImageList.ReplaceMasked(Index: Integer; NewImage: TBitmap; MaskColor: TColor);
  478. var
  479.   TempIndex: Integer;
  480.   Image, Mask: TBitmap;
  481. begin
  482.   if HandleAllocated then
  483.   begin
  484.     CheckImage(NewImage);
  485.     TempIndex := AddMasked(NewImage, MaskColor);
  486.     if TempIndex <> -1 then
  487.     try
  488.       Image := TBitmap.Create;
  489.       try
  490.         with Image do
  491.         begin
  492.           Height := FHeight;
  493.           Width := FWidth;
  494.         end;
  495.         Mask := TBitmap.Create;
  496.         try
  497.           with Mask do
  498.           begin
  499.             Monochrome := True;
  500.             Height := FHeight;
  501.             Width := FWidth;
  502.           end;
  503.           ImageList_Draw(Handle, TempIndex, Image.Canvas.Handle, 0, 0, ILD_NORMAL);
  504.           ImageList_Draw(Handle, TempIndex, Mask.Canvas.Handle, 0, 0, ILD_MASK);
  505.           if not ImageList_Replace(Handle, Index, Image.Handle, Mask.Handle) then
  506.             raise EInvalidOperation.Create(SReplaceImage);
  507.         finally
  508.           Mask.Free;
  509.         end;
  510.       finally
  511.         Image.Free;
  512.       end;
  513.     finally
  514.       Delete(TempIndex);
  515.     end
  516.     else raise EInvalidOperation.Create(SReplaceImage);
  517.   end;
  518.   Change;
  519. end;
  520.  
  521. procedure TCustomImageList.ReplaceIcon(Index: Integer; Image: TIcon);
  522. begin
  523.   if HandleAllocated then
  524.     if Image = nil then Replace(Index, nil, nil)
  525.     else begin
  526.       CheckImage(Image);
  527.       if ImageList_ReplaceIcon(Handle, Index, Image.Handle) = -1 then
  528.         raise EInvalidOperation.Create(SReplaceImage);
  529.     end;
  530.   Change;
  531. end;
  532.  
  533. procedure TCustomImageList.Delete(Index: Integer);
  534. begin
  535.   if Index >= Count then raise EInvalidOperation.Create(SImageIndexError);
  536.   if HandleAllocated then ImageList_Remove(Handle, Index);
  537.   Change;
  538. end;
  539.  
  540. procedure TCustomImageList.Clear;
  541. begin
  542.   Delete(-1);
  543. end;
  544.  
  545. procedure TCustomImageList.SetBkColor(Value: TColor);
  546. begin
  547.   if HandleAllocated then ImageList_SetBkColor(FHandle, GetRGBColor(Value))
  548.   else FBkColor := Value;
  549.   Change;
  550. end;
  551.  
  552. function TCustomImageList.GetBkColor: TColor;
  553. begin
  554.   if HandleAllocated then Result := GetColor(ImageList_GetBkColor(Handle))
  555.   else Result := FBkColor;
  556. end;
  557.  
  558. procedure TCustomImageList.DoDraw(Index: Integer; Canvas: TCanvas; X, Y: Integer;
  559.   Style: Cardinal; Enabled: Boolean);
  560. const
  561.   ROP_DSPDxax = $00E20746;
  562. var
  563.   R: TRect;
  564.   DestDC, SrcDC: HDC;
  565. begin
  566.   if HandleAllocated then
  567.   begin
  568.     if Enabled then
  569.       ImageList_DrawEx(Handle, Index, Canvas.Handle, X, Y, 0, 0,
  570.         GetRGBColor(BkColor), GetRGBColor(BlendColor), Style)
  571.     else
  572.     begin
  573.       if FMonoBitmap = nil then
  574.       begin
  575.         FMonoBitmap := TBitmap.Create;
  576.         with FMonoBitmap do
  577.         begin
  578.           Monochrome := True;
  579.           Width := Self.Width;
  580.           Height := Self.Height;
  581.         end;
  582.       end;
  583.       { Store masked version of image temporarily in FBitmap }
  584.       FMonoBitmap.Canvas.Brush.Color := clWhite;
  585.       FMonoBitmap.Canvas.FillRect(Rect(0, 0, Self.Width, Self.Height));
  586.       ImageList_DrawEx(Handle, Index, FMonoBitmap.Canvas.Handle, 0,0,0,0,
  587.         CLR_DEFAULT, 0, ILD_NORMAL);
  588.       R := Rect(X, Y, X+Width, Y+Height);
  589.       SrcDC := FMonoBitmap.Canvas.Handle;
  590.       { Convert Black to clBtnHighlight }
  591.       Canvas.Brush.Color := clBtnHighlight;
  592.       DestDC := Canvas.Handle;
  593.       Windows.SetTextColor(DestDC, clWhite);
  594.       Windows.SetBkColor(DestDC, clBlack);
  595.       BitBlt(DestDC, X+1, Y+1, Width, Height, SrcDC, 0, 0, ROP_DSPDxax);
  596.       { Convert Black to clBtnShadow }
  597.       Canvas.Brush.Color := clBtnShadow;
  598.       DestDC := Canvas.Handle;
  599.       Windows.SetTextColor(DestDC, clWhite);
  600.       Windows.SetBkColor(DestDC, clBlack);
  601.       BitBlt(DestDC, X, Y, Width, Height, SrcDC, 0, 0, ROP_DSPDxax);
  602.     end;
  603.   end;
  604. end;
  605.  
  606. procedure TCustomImageList.Draw(Canvas: TCanvas; X, Y, Index: Integer;
  607.   Enabled: Boolean);
  608. const
  609.   DrawingStyles: array[TDrawingStyle] of Longint = (ILD_FOCUS, ILD_SELECTED,
  610.     ILD_NORMAL, ILD_TRANSPARENT);
  611.   Images: array[TImageType] of Longint = (0, ILD_MASK);
  612. begin
  613.   if HandleAllocated then
  614.     DoDraw(Index, Canvas, X, Y, DrawingStyles[DrawingStyle] or
  615.       Images[ImageType], Enabled);
  616. end;
  617.  
  618. procedure TCustomImageList.DrawOverlay(Canvas: TCanvas; X, Y: Integer;
  619.   ImageIndex: Integer; Overlay: TOverlay; Enabled: Boolean);
  620. const
  621.   Images: array[TImageType] of Longint = (0, ILD_MASK);
  622. var
  623.   Index: Integer;
  624. begin
  625.   if HandleAllocated then
  626.   begin
  627.     Index := IndexToOverlayMask(Overlay + 1);
  628.     DoDraw(ImageIndex, Canvas, X, Y, Images[ImageType] or ILD_OVERLAYMASK and
  629.       Index, Enabled);
  630.   end;
  631. end;
  632.  
  633. function TCustomImageList.Overlay(ImageIndex: Integer; Overlay: TOverlay): Boolean;
  634. begin
  635.   if HandleAllocated then
  636.     Result := ImageList_SetOverlayImage(Handle, ImageIndex, Overlay + 1)
  637.   else Result := False;
  638. end;
  639.  
  640. procedure TCustomImageList.CopyImages(Value: HImageList);
  641. var
  642.   I: Integer;
  643.   Image, Mask: TBitmap;
  644.   ARect: TRect;
  645. begin
  646.   ARect := Rect(0, 0, Width, Height);
  647.   BeginUpdate;
  648.   try
  649.     Image := TBitmap.Create;
  650.     try
  651.       with Image do
  652.       begin
  653.         Height := FHeight;
  654.         Width := FWidth;
  655.       end;
  656.       Mask := TBitmap.Create;
  657.       try
  658.         with Mask do
  659.         begin
  660.           Monochrome := True;
  661.           Height := FHeight;
  662.           Width := FWidth;
  663.         end;
  664.         for I := 0 to ImageList_GetImageCount(Value) - 1 do
  665.         begin
  666.           with Image.Canvas do
  667.           begin
  668.             FillRect(ARect);
  669.             ImageList_Draw(Value, I, Handle, 0, 0, ILD_NORMAL);
  670.           end;
  671.           with Mask.Canvas do
  672.           begin
  673.             FillRect(ARect);
  674.             ImageList_Draw(Value, I, Handle, 0, 0, ILD_MASK);
  675.           end;
  676.           Add(Image, Mask);
  677.         end;
  678.       finally
  679.         Mask.Free;
  680.       end;
  681.     finally
  682.       Image.Free;
  683.     end;
  684.   finally
  685.     EndUpdate;
  686.   end;
  687. end;
  688.  
  689. procedure TCustomImageList.GetImages(Index: Integer; Image, Mask: TBitmap);
  690. var
  691.   R: TRect;
  692. begin
  693.   R := Rect(0, 0, Width, Height);
  694.   with Image.Canvas do
  695.   begin
  696.     Brush.Color := clWhite;
  697.     FillRect(R);
  698.     ImageList_Draw(Self.Handle, Index, Handle, 0, 0, ILD_NORMAL);
  699.   end;
  700.   with Mask.Canvas do
  701.   begin
  702.     Brush.Color := clWhite;
  703.     FillRect(R);
  704.     ImageList_Draw(Self.Handle, Index, Handle, 0, 0, ILD_MASK);
  705.   end;
  706. end;
  707.  
  708. procedure TCustomImageList.InsertImage(Index: Integer; Image, Mask: TBitmap;
  709.   MaskColor: TColor);
  710. var
  711.   I: Integer;
  712.   OldImage, OldMask: TBitmap;
  713.   TempList: TCustomImageList;
  714. begin
  715.   BeginUpdate;
  716.   try
  717.     OldImage := TBitmap.Create;
  718.     try
  719.       with OldImage do
  720.       begin
  721.         Height := FHeight;
  722.         Width := FWidth;
  723.       end;
  724.       OldMask := TBitmap.Create;
  725.       try
  726.         with OldMask do
  727.         begin
  728.           Monochrome := True;
  729.           Height := FHeight;
  730.           Width := FWidth;
  731.         end;
  732.         TempList := TCustomImageList.CreateSize(5, 5);
  733.         try
  734.           TempList.Assign(Self);
  735.           Clear;
  736.           if Index > TempList.Count then
  737.             raise EInvalidOperation.Create(SImageIndexError);
  738.           for I := 0 to Index - 1 do
  739.           begin
  740.             TempList.GetImages(I, OldImage, OldMask);
  741.             Add(OldImage, OldMask);
  742.           end;
  743.           if MaskColor <> -1 then
  744.             AddMasked(Image, MaskColor) else
  745.             Add(Image, Mask);
  746.           for I := Index to TempList.Count - 1 do
  747.           begin
  748.             TempList.GetImages(I, OldImage, OldMask);
  749.             Add(OldImage, OldMask);
  750.           end;
  751.         finally
  752.           TempList.Free;
  753.         end;
  754.       finally
  755.         OldMask.Free;
  756.       end;
  757.     finally
  758.       OldImage.Free;
  759.     end;
  760.   finally
  761.     EndUpdate;
  762.   end;
  763. end;
  764.  
  765. procedure TCustomImageList.Insert(Index: Integer; Image, Mask: TBitmap);
  766. begin
  767.   InsertImage(Index, Image, Mask, -1);
  768. end;
  769.  
  770. procedure TCustomImageList.InsertMasked(Index: Integer; Image: TBitmap;
  771.   MaskColor: TColor);
  772. begin
  773.   InsertImage(Index, Image, nil, MaskColor);
  774. end;
  775.  
  776. procedure TCustomImageList.InsertIcon(Index: Integer; Image: TIcon);
  777. var
  778.   I: Integer;
  779.   TempList: TCustomImageList;
  780.   Icon: TIcon;
  781. begin
  782.   Icon := TIcon.Create;
  783.   TempList := TCustomImageList.CreateSize(5, 5);
  784.   TempList.Assign(Self);
  785.   Clear;
  786.   if Index > TempList.Count then raise EInvalidOperation.Create(SImageIndexError);
  787.   BeginUpdate;
  788.   try
  789.     for I := 0 to Index - 1 do
  790.     begin
  791.       TempList.GetIcon(I, Icon);
  792.       AddIcon(Icon);
  793.     end;
  794.     AddIcon(Image);
  795.     for I := Index to TempList.Count - 1 do
  796.     begin
  797.       TempList.GetIcon(I, Icon);
  798.       AddIcon(Icon);
  799.     end;
  800.   finally
  801.     TempList.Free;
  802.     EndUpdate;
  803.   end;
  804. end;
  805.  
  806. procedure TCustomImageList.Move(CurIndex, NewIndex: Integer);
  807. var
  808.   Image, Mask: TBitmap;
  809. begin
  810.   if CurIndex <> NewIndex then
  811.   begin
  812.     Image := TBitmap.Create;
  813.     try
  814.       with Image do
  815.       begin
  816.         Height := FHeight;
  817.         Width := FWidth;
  818.       end;
  819.       Mask := TBitmap.Create;
  820.       try
  821.         with Mask do
  822.         begin
  823.           Height := FHeight;
  824.           Width := FWidth;
  825.         end;
  826.         GetImages(CurIndex, Image, Mask);
  827.         Delete(CurIndex);
  828.         Insert(NewIndex, Image, Mask);
  829.       finally
  830.         Mask.Free;
  831.       end;
  832.     finally
  833.       Image.Free;
  834.     end;
  835.   end;
  836. end;
  837.  
  838. procedure TCustomImageList.AddImages(Value: TCustomImageList);
  839. begin
  840.   if Value <> nil then CopyImages(Value.Handle);
  841. end;
  842.  
  843. procedure TCustomImageList.Assign(Source: TPersistent);
  844. var
  845.   ImageList: TCustomImageList;
  846. begin
  847.   if Source = nil then FreeHandle
  848.   else if Source is TCustomImageList then
  849.   begin
  850.     Clear;
  851.     ImageList := TCustomImageList(Source);
  852.     Masked := ImageList.Masked;
  853.     ImageType := ImageList.ImageType;
  854.     DrawingStyle := ImageList.DrawingStyle;
  855.     ShareImages := ImageList.ShareImages;
  856.     SetNewDimensions(ImageList.Handle);
  857.     if not HandleAllocated then HandleNeeded
  858.     else ImageList_SetIconSize(Handle, Width, Height);
  859.     BkColor := GetColor(ImageList_GetBkColor(ImageList.Handle));
  860.     BlendColor := ImageList.BlendColor;
  861.     AddImages(ImageList);
  862.   end
  863.   else inherited Assign(Source);
  864. end;
  865.  
  866. procedure TCustomImageList.AssignTo(Dest: TPersistent);
  867. var
  868.   ImageList: TCustomImageList;
  869. begin
  870.   if Dest is TCustomImageList then
  871.   begin
  872.     ImageList := TCustomImageList(Dest);
  873.     ImageList.Masked := Masked;
  874.     ImageList.ImageType := ImageType;
  875.     ImageList.DrawingStyle := DrawingStyle;
  876.     ImageList.ShareImages := ShareImages;
  877.     ImageList.BlendColor := BlendColor;
  878.     with ImageList do
  879.     begin
  880.       Clear;
  881.       SetNewDimensions(Self.Handle);
  882.       if not HandleAllocated then HandleNeeded
  883.       else ImageList_SetIconSize(Handle, Width, Height);
  884.       BkColor := GetColor(ImageList_GetBkColor(Self.Handle));
  885.       AddImages(Self);
  886.     end;
  887.   end
  888.   else inherited AssignTo(Dest);
  889. end;
  890.  
  891. procedure TCustomImageList.CheckImage(Image: TGraphic);
  892. begin
  893.   if Image = nil then Exit;
  894.   with Image do
  895.     if (Height < FHeight) or (Width < FWidth) then
  896.       raise EInvalidOperation.Create(SInvalidImageSize);
  897. end;
  898.  
  899. procedure TCustomImageList.SetDrawingStyle(Value: TDrawingStyle);
  900. begin
  901.   if Value <> DrawingStyle then
  902.   begin
  903.     FDrawingStyle := Value;
  904.     Change;
  905.   end;
  906. end;
  907.  
  908. function TCustomImageList.GetHotSpot: TPoint;
  909. begin
  910.   Result := Point(0, 0);
  911. end;
  912.  
  913. function TCustomImageList.GetInstRes(Instance: THandle; ResType: TResType;
  914.   Name: string; Width: Integer; LoadFlags: TLoadResources; MaskColor: TColor):
  915.   Boolean;
  916. const
  917.   ResMap: array [TResType] of Integer = (IMAGE_BITMAP, IMAGE_CURSOR, IMAGE_ICON);
  918. var
  919.   hImage: HImageList;
  920.   Flags: Integer;
  921. begin
  922.   Flags := 0;
  923.   if lrDefaultColor in LoadFlags then Flags := Flags or LR_DEFAULTCOLOR;
  924.   if lrDefaultSize in LoadFlags then Flags := Flags or LR_DEFAULTSIZE;
  925.   if lrFromFile in LoadFlags then Flags := Flags or LR_LOADFROMFILE;
  926.   if lrMap3DColors in LoadFlags then Flags := Flags or LR_LOADMAP3DCOLORS;
  927.   if lrTransparent in LoadFlags then Flags := Flags or LR_LOADTRANSPARENT;
  928.   if lrMonoChrome in LoadFlags then Flags := Flags or LR_MONOCHROME;
  929.   hImage := ImageList_LoadImage(Instance, PChar(Name), Width, AllocBy,
  930.     MaskColor, ResMap[ResType], Flags);
  931.   if hImage <> 0 then
  932.   begin
  933.     CopyImages(hImage);
  934.     ImageList_Destroy(hImage);
  935.     Result := True;
  936.   end
  937.   else Result := False;
  938. end;
  939.  
  940. function TCustomImageList.GetResource(ResType: TResType; Name: string;
  941.   Width: Integer; LoadFlags: TLoadResources; MaskColor: TColor): Boolean;
  942. begin
  943.   Result := GetInstRes(MainInstance, ResType, Name, Width, LoadFlags, MaskColor);
  944. end;
  945.  
  946. function TCustomImageList.ResInstLoad(Instance: THandle; ResType: TResType;
  947.   Name: string; MaskColor: TColor): Boolean;
  948. begin
  949.   Result := GetInstRes(Instance, ResType, Name, Width, [], MaskColor);
  950. end;
  951.  
  952. function TCustomImageList.ResourceLoad(ResType: TResType; Name: string;
  953.   MaskColor: TColor): Boolean;
  954. var
  955.   LibModule: PLibModule;
  956. begin
  957.   Result := False;
  958.   if HInstance = MainInstance then
  959.     Result := GetInstRes(MainInstance, ResType, Name, Width, [], MaskColor)
  960.   else
  961.   begin
  962.     LibModule := LibModuleList;
  963.     while LibModule <> nil do
  964.       with LibModule^ do
  965.       begin
  966.         Result := GetInstRes(ResInstance, ResType, Name, Width, [], MaskColor);
  967.         if not Result and (Instance <> ResInstance) then
  968.           Result := GetInstRes(Instance, ResType, Name, Width, [], MaskColor);
  969.         if Result then Exit;
  970.         LibModule := LibModule.Next;
  971.       end;
  972.   end;
  973. end;
  974.  
  975. function TCustomImageList.FileLoad(ResType: TResType; Name: string;
  976.   MaskColor: TColor): Boolean;
  977. begin
  978.   Result := GetResource(ResType, Name, Width, [lrFromFile], MaskColor);
  979. end;
  980.  
  981. procedure TCustomImageList.Change;
  982. var
  983.   I: Integer;
  984. begin
  985.   FChanged := True;
  986.   if FUpdateCount > 0 then Exit;
  987.   if FClients <> nil then
  988.     for I := 0 to FClients.Count - 1 do
  989.       TChangeLink(FClients[I]).Change;
  990.   if Assigned(FOnChange) then FOnChange(Self);
  991. end;
  992.  
  993. procedure TCustomImageList.UnRegisterChanges(Value: TChangeLink);
  994. var
  995.   I: Integer;
  996. begin
  997.   if FClients <> nil then
  998.     for I := 0 to FClients.Count - 1 do
  999.       if FClients[I] = Value then
  1000.       begin
  1001.         Value.Sender := nil;
  1002.         FClients.Delete(I);
  1003.         Break;
  1004.       end;
  1005. end;
  1006.  
  1007. procedure TCustomImageList.RegisterChanges(Value: TChangeLink);
  1008. begin
  1009.   Value.Sender := Self;
  1010.   if FClients <> nil then FClients.Add(Value);
  1011. end;
  1012.  
  1013. function TCustomImageList.Equal(IL: TCustomImageList): Boolean;
  1014.  
  1015.   function StreamsEqual(S1, S2: TMemoryStream): Boolean;
  1016.   begin
  1017.     Result := (S1.Size = S2.Size) and CompareMem(S1.Memory, S2.Memory, S1.Size);
  1018.   end;
  1019.  
  1020. var
  1021.   MyImage, OtherImage: TMemoryStream;
  1022. begin
  1023.   if (IL = nil) or (Count <> IL.Count) then
  1024.   begin
  1025.     Result := False;
  1026.     Exit;
  1027.   end;
  1028.   if (Count = 0) and (IL.Count = 0) then
  1029.   begin
  1030.     Result := True;
  1031.     Exit;
  1032.   end;
  1033.   MyImage := TMemoryStream.Create;
  1034.   try
  1035.     WriteData(MyImage);
  1036.     OtherImage := TMemoryStream.Create;
  1037.     try
  1038.       IL.WriteData(OtherImage);
  1039.       Result := StreamsEqual(MyImage, OtherImage);
  1040.     finally
  1041.       OtherImage.Free;
  1042.     end;
  1043.   finally
  1044.     MyImage.Free;
  1045.   end;
  1046. end;
  1047.  
  1048. procedure TCustomImageList.DefineProperties(Filer: TFiler);
  1049.  
  1050.   function DoWrite: Boolean;
  1051.   begin
  1052.     if Filer.Ancestor <> nil then
  1053.       Result := not (Filer.Ancestor is TCustomImageList) or
  1054.         not Equal(TCustomImageList(Filer.Ancestor))
  1055.     else
  1056.       Result := Count > 0;
  1057.   end;
  1058.  
  1059. begin
  1060.   inherited DefineProperties(Filer);
  1061.   Filer.DefineBinaryProperty('Bitmap', ReadData, WriteData, DoWrite);
  1062. end;
  1063.  
  1064. procedure TCustomImageList.ReadD2Stream(Stream: TStream);
  1065. var
  1066.   FullImage, Image, FullMask, Mask: TBitmap;
  1067.   I, J, Size, Pos, Count: Integer;
  1068.   SrcRect: TRect;
  1069. begin
  1070.   Stream.ReadBuffer(Size, SizeOf(Size));
  1071.   Stream.ReadBuffer(Count, SizeOf(Count));
  1072.   FullImage := TBitmap.Create;
  1073.   try
  1074.     Pos := Stream.Position;
  1075.     FullImage.LoadFromStream(Stream);
  1076.     Stream.Position := Pos + Size;
  1077.     FullMask := TBitmap.Create;
  1078.     try
  1079.       FullMask.LoadFromStream(Stream);
  1080.       Image := TBitmap.Create;
  1081.       Image.Width := Width;
  1082.       Image.Height := Height;
  1083.       Mask := TBitmap.Create;
  1084.       Mask.Monochrome := True;
  1085.       Mask.Width := Width;
  1086.       Mask.Height := Height;
  1087.       SrcRect := Rect(0, 0, Width, Height);
  1088.       BeginUpdate;
  1089.       try
  1090.         for J := 0 to (FullImage.Height div Height) - 1 do
  1091.         begin
  1092.           if Count = 0 then Break;
  1093.           for I := 0 to (FullImage.Width div Width) - 1 do
  1094.           begin
  1095.             if Count = 0 then Break;
  1096.             Image.Canvas.CopyRect(SrcRect, FullImage.Canvas,
  1097.               Bounds(I * Width, J * Height, Width, Height));
  1098.             Mask.Canvas.CopyRect(SrcRect, FullMask.Canvas,
  1099.               Bounds(I * Width, J * Height, Width, Height));
  1100.             Add(Image, Mask);
  1101.             Dec(Count);
  1102.           end;
  1103.         end;
  1104.       finally
  1105.         Image.Free;
  1106.         Mask.Free;
  1107.         EndUpdate;
  1108.       end;
  1109.     finally
  1110.       FullMask.Free;
  1111.     end;
  1112.   finally
  1113.     FullImage.Free;
  1114.   end;
  1115. end;
  1116.  
  1117. procedure TCustomImageList.ReadD3Stream(Stream: TStream);
  1118. var
  1119.   SA: TStreamAdapter;
  1120. begin
  1121.   SA := TStreamAdapter.Create(Stream);
  1122.   try
  1123.     Handle := ImageList_Read(SA);
  1124.     if Handle = 0 then
  1125.       raise EReadError.CreateRes(@SImageReadFail);
  1126.   finally
  1127.     SA.Free;
  1128.   end;
  1129. end;
  1130.  
  1131. procedure TCustomImageList.ReadData(Stream: TStream);
  1132. var
  1133.   CheckInt1, CheckInt2: Integer;
  1134.   CheckByte1, CheckByte2: Byte;
  1135.   StreamPos: Integer;
  1136. begin
  1137.   FreeHandle;
  1138.   StreamPos := Stream.Position;              // check stream signature to
  1139.   Stream.Read(CheckInt1, SizeOf(CheckInt1)); // determine a Delphi 2 or Delphi
  1140.   Stream.Read(CheckInt2, SizeOf(CheckInt2)); // 3 imagelist stream.  Delphi 2
  1141.   CheckByte1 := Lo(LoWord(CheckInt1));       // streams can be read, but only
  1142.   CheckByte2 := Hi(LoWord(CheckInt1));       // Delphi 3 streams will be written
  1143.   Stream.Position := StreamPos;
  1144.   if (CheckInt1 <> CheckInt2) and (CheckByte1 = $49) and (CheckByte2 = $4C) then
  1145.     ReadD3Stream(Stream)
  1146.   else
  1147.     ReadD2Stream(Stream);
  1148. end;
  1149.  
  1150. procedure TCustomImageList.WriteData(Stream: TStream);
  1151. var
  1152.   SA: TStreamAdapter;
  1153. begin
  1154.   SA := TStreamAdapter.Create(Stream);
  1155.   try
  1156.     if not ImageList_Write(Handle, SA) then
  1157.       raise EWriteError.CreateRes(@SImageWriteFail);
  1158.   finally
  1159.     SA.Free;
  1160.   end;
  1161. end;
  1162. (*
  1163. var
  1164.   I: Integer;
  1165.   DIB1, DIB2: TBitmap;
  1166.   DC: HDC;
  1167.   S: TMemoryStream;
  1168.  
  1169.   procedure WriteDIB(BM: HBitmap);
  1170.     { The ImageList leaves its bitmap handle selected into a DC somewhere,
  1171.       so we can't select it into our own DC to copy from it.  The only safe
  1172.       operation is GetDIB (GetDIBits), which extracts the pixel bits without
  1173.       selecting the BM into a DC.  This code builds our own bitmap from
  1174.       those bits, then crops it to the minimum size before writing it out.}
  1175.   var
  1176.     BitsSize: DWORD;
  1177.     Header, Bits: PChar;
  1178.     DIBBits: Pointer;
  1179.     R: TRect;
  1180.     HeaderSize: DWORD;
  1181.     GlyphsPerRow, Rows: Integer;
  1182.   begin
  1183.     if BM = 0 then Exit;
  1184.     GetDIBSizes(BM, HeaderSize, BitsSize);
  1185.     GetMem(Header, HeaderSize + BitsSize);
  1186.     try
  1187.       Bits := Header + HeaderSize;
  1188.       GetDIB(BM, 0, Header^, Bits^);
  1189.       DIB1.Handle := CreateDIBSection(DC, PBitmapInfo(Header)^, DIB_RGB_COLORS, DIBBits, 0, 0);
  1190.       System.Move(Bits^, DIBBits^, BitsSize);
  1191.       with PBitmapInfo(Header)^.bmiHeader do
  1192.       begin
  1193.         GlyphsPerRow := biWidth div Width;
  1194.         if GlyphsPerRow = 0 then Inc(GlyphsPerRow);
  1195.         if GlyphsPerRow > Count then GlyphsPerRow := Count;
  1196.         biWidth := GlyphsPerRow * Width;
  1197.         Rows := Count div GlyphsPerRow;
  1198.         if Count > Rows * GlyphsPerRow then Inc(Rows);
  1199.         biHeight := Rows * Height;
  1200.         R := Rect(0, 0, biWidth, biHeight);
  1201.       end;
  1202.       DIB2.Handle := CreateDIBSection(DC, PBitmapInfo(Header)^, DIB_RGB_COLORS, DIBBits, 0, 0);
  1203.       DIB2.Canvas.CopyRect(R, DIB1.Canvas, R);
  1204.       DIB2.SaveToStream(S);
  1205.     finally
  1206.       FreeMem(Header);
  1207.     end;
  1208.   end;
  1209.  
  1210. begin
  1211.   DIB1 := nil;
  1212.   DIB2 := nil;
  1213.   DC := 0;
  1214.   S := TMemoryStream.Create;
  1215.   try
  1216.     DIB1 := TBitmap.Create;
  1217.     DIB2 := TBitmap.Create;
  1218.     DC := GetDC(0);
  1219.     WriteDIB(GetImageBitmap);
  1220.     I := S.Size;
  1221.     WriteDIB(GetMaskBitmap);
  1222.     Stream.WriteBuffer(I, sizeof(I));
  1223.     I := Count;
  1224.     Stream.WriteBuffer(I, sizeof(I));
  1225.     Stream.WriteBuffer(S.Memory^, S.Size);
  1226.   finally
  1227.     ReleaseDC(0, DC);
  1228.     DIB1.Free;
  1229.     DIB2.Free;
  1230.     S.Free;
  1231.   end;
  1232. end;
  1233. *)
  1234. procedure TCustomImageList.BeginUpdate;
  1235. begin
  1236.   Inc(FUpdateCount);
  1237. end;
  1238.  
  1239. procedure TCustomImageList.EndUpdate;
  1240. begin
  1241.   if FUpdateCount > 0 then Dec(FUpdateCount);
  1242.   if FChanged then
  1243.   begin
  1244.     FChanged := False;
  1245.     Change;
  1246.   end;
  1247. end;
  1248.  
  1249. { TChangeLink }
  1250.  
  1251. destructor TChangeLink.Destroy;
  1252. begin
  1253.   if Sender <> nil then Sender.UnRegisterChanges(Self);
  1254.   inherited Destroy;
  1255. end;
  1256.  
  1257. procedure TChangeLink.Change;
  1258. begin
  1259.   if Assigned(OnChange) then OnChange(Sender);
  1260. end;
  1261.  
  1262. end.