home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d123456 / DFS.ZIP / IconCtls.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-28  |  30KB  |  833 lines

  1. {$I DFS.INC}  { Standard defines for all Delphi Free Stuff components }
  2.  
  3. {------------------------------------------------------------------------------}
  4. { TdfsIconComboBox and TdfsIconListBox v1.16                                   }
  5. {------------------------------------------------------------------------------}
  6. { A Caching Icon ComboBox and ListBox component for Delphi.                    }
  7. {                                                                              }
  8. { Copyright 1996-2001, Brad Stowers.  All Rights Reserved.                     }
  9. {                                                                              }
  10. { Copyright:                                                                   }
  11. { All Delphi Free Stuff (hereafter "DFS") source code is copyrighted by        }
  12. { Bradley D. Stowers (hereafter "author"), and shall remain the exclusive      }
  13. { property of the author.                                                      }
  14. {                                                                              }
  15. { Distribution Rights:                                                         }
  16. { You are granted a non-exlusive, royalty-free right to produce and distribute }
  17. { compiled binary files (executables, DLLs, etc.) that are built with any of   }
  18. { the DFS source code unless specifically stated otherwise.                    }
  19. { You are further granted permission to redistribute any of the DFS source     }
  20. { code in source code form, provided that the original archive as found on the }
  21. { DFS web site (http://www.delphifreestuff.com) is distributed unmodified. For }
  22. { example, if you create a descendant of TDFSColorButton, you must include in  }
  23. { the distribution package the colorbtn.zip file in the exact form that you    }
  24. { downloaded it from http://www.delphifreestuff.com/mine/files/colorbtn.zip.   }
  25. {                                                                              }
  26. { Restrictions:                                                                }
  27. { Without the express written consent of the author, you may not:              }
  28. {   * Distribute modified versions of any DFS source code by itself. You must  }
  29. {     include the original archive as you found it at the DFS site.            }
  30. {   * Sell or lease any portion of DFS source code. You are, of course, free   }
  31. {     to sell any of your own original code that works with, enhances, etc.    }
  32. {     DFS source code.                                                         }
  33. {   * Distribute DFS source code for profit.                                   }
  34. {                                                                              }
  35. { Warranty:                                                                    }
  36. { There is absolutely no warranty of any kind whatsoever with any of the DFS   }
  37. { source code (hereafter "software"). The software is provided to you "AS-IS", }
  38. { and all risks and losses associated with it's use are assumed by you. In no  }
  39. { event shall the author of the softare, Bradley D. Stowers, be held           }
  40. { accountable for any damages or losses that may occur from use or misuse of   }
  41. { the software.                                                                }
  42. {                                                                              }
  43. { Support:                                                                     }
  44. { Support is provided via the DFS Support Forum, which is a web-based message  }
  45. { system.  You can find it at http://www.delphifreestuff.com/discus/           }
  46. { All DFS source code is provided free of charge. As such, I can not guarantee }
  47. { any support whatsoever. While I do try to answer all questions that I        }
  48. { receive, and address all problems that are reported to me, you must          }
  49. { understand that I simply can not guarantee that this will always be so.      }
  50. {                                                                              }
  51. { Clarifications:                                                              }
  52. { If you need any further information, please feel free to contact me directly.}
  53. { This agreement can be found online at my site in the "Miscellaneous" section.}
  54. {------------------------------------------------------------------------------}
  55. { The lateset version of my components are always available on the web at:     }
  56. {   http://www.delphifreestuff.com/                                            }
  57. { See IconCtls.txt for notes, known issues, and revision history.              }
  58. {------------------------------------------------------------------------------}
  59. { Date last modified:  June 28, 2001                                           }
  60. {------------------------------------------------------------------------------}
  61.  
  62. unit IconCtls;
  63.  
  64. interface
  65.  
  66. uses
  67.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  68.   Forms, Dialogs, StdCtrls, Menus;
  69.  
  70. const
  71.   DFS_COMBO_VERSION = 'TdfsIconComboBox v1.16';
  72.   DFS_LIST_VERSION  = 'TdfsIconListBox v1.16';
  73.  
  74. type
  75.   TdfsIconComboBox = class(TCustomComboBox)
  76.   private
  77.     { Variables for properties }
  78.     FFileName: String;
  79.     FAutoDisable: boolean;
  80.     FEnableCaching: boolean;
  81.     FNumberOfIcons: integer;
  82.     FRecreating: boolean;
  83.     FOnFileChange: TNotifyEvent;
  84.  
  85.     { Routines that should only be used internally by component }
  86.     procedure LoadIcons;
  87.     procedure FreeIcons;
  88.     procedure UpdateEnabledState;
  89.  
  90.     {$IFDEF DFS_COMPILER_3_UP}
  91.     procedure CMRecreateWnd(var Message: TMessage); message CM_RECREATEWND;
  92.     {$ENDIF}
  93.     procedure WMDeleteItem(var Msg: TWMDeleteItem); message WM_DELETEITEM;
  94.   protected
  95.     { Routines for setting property values and updating affected items }
  96.     procedure SetFileName(Value: String);
  97.     procedure SetAutoDisable(Value: boolean);
  98.     procedure SetEnableCaching(Value: boolean);
  99.     function GetVersion: string;
  100.     procedure SetVersion(const Val: string);
  101.  
  102.     { Icon service routines }
  103.     function  ReadIcon(const Index: integer): TIcon;
  104.     function  GeTdfsIcon(Index: integer): TIcon;
  105.  
  106.     { Owner drawing routines }
  107.     procedure MeasureItem(Index: Integer; var Height: Integer);              override;
  108.     procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
  109.   public
  110.     constructor Create(AOwner: TComponent); override;
  111.  
  112.     { Returns a specific TIcon in the list.  The TIcon is owned by the
  113.       component, so you should NEVER free it. }
  114.     property Icon[Index: integer]: TIcon
  115.        read GeTdfsIcon;
  116.   published
  117.     property Version: string
  118.        read GetVersion
  119.        write SetVersion
  120.        stored FALSE;
  121.     { Name of icon file to display }
  122.     property FileName: string
  123.        read FFileName
  124.        write SetFileName;
  125.     { If true, the combobox will be disabled when FileName does not exist }
  126.     property AutoDisable: boolean
  127.        read FAutoDisable
  128.        write SetAutoDisable
  129.        default TRUE;
  130.     { If true, icons will be loaded as needed, instead of all at once }
  131.     property EnableCaching: boolean
  132.        read FEnableCaching
  133.        write SetEnableCaching
  134.        default TRUE;
  135.     { The number of icons in the file.  -1 if FileName is not valid.  }
  136.     property NumberOfIcons: integer
  137.        read FNumberOfIcons
  138.        default -1;
  139.  
  140.     { Useful if you have statics the reflect the number of icons, etc. }
  141.     property OnFileChange: TNotifyEvent
  142.        read FOnFileChange
  143.        write FOnFileChange;
  144.  
  145.     { Protected properties in parent that we will make available to everyone }
  146.     property Color;
  147.     property Ctl3D;
  148.     property DragMode;
  149.     property DragCursor;
  150.     property DropDownCount default 5;
  151.     property Enabled;
  152.     property ItemIndex;
  153.     property ParentColor;
  154.     property ParentCtl3D;
  155.     property ParentFont;
  156.     property ParentShowHint;
  157.     property PopupMenu;
  158.     property ShowHint;
  159.     property TabOrder;
  160.     property TabStop;
  161.     property Visible;
  162.     property OnChange;
  163.     property OnClick;
  164.     property OnDblClick;
  165.     property OnDragDrop;
  166.     property OnDragOver;
  167.     property OnDropDown;
  168.     property OnEndDrag;
  169.     property OnEnter;
  170.     property OnExit;
  171.     property OnKeyDown;
  172.     property OnKeyPress;
  173.     property OnKeyUp;
  174.   end;
  175.  
  176.   TOrientation = (lbHorizontal, lbVertical);
  177.  
  178.   TdfsIconListBox = class(TCustomListBox)
  179.   private
  180.     { Private declarations }
  181.     FFileName: String;
  182.     FAutoDisable: boolean;
  183.     FEnableCaching: boolean;
  184.     FNumberOfIcons: integer;
  185.     FMargin: integer;
  186.     FRecreating: boolean;
  187.     FOnFileChange: TNotifyEvent;
  188.  
  189.     { Routines that should only be used internally by component }
  190.     procedure LoadIcons;
  191.     procedure FreeIcons;
  192.     procedure UpdateEnabledState;
  193.  
  194.     procedure CNDeleteItem(var Msg: TWMDeleteItem); message CN_DELETEITEM;
  195.     {$IFDEF DFS_COMPILER_3_UP}
  196.     procedure CMRecreateWnd(var Message: TMessage); message CM_RECREATEWND;
  197.     {$ENDIF}
  198.   protected
  199.     procedure CreateParams(var Params: TCreateParams);                       override;
  200.     procedure CreateWnd; override;
  201.     { Routines for setting property values and updating affected items }
  202.     procedure SetFileName(Value: String);
  203.     procedure SetAutoDisable(Value: boolean);
  204.     procedure SetMargin(const Value: integer);
  205.     procedure SetEnableCaching(Value: boolean);
  206.     function GetVersion: string;
  207.     procedure SetVersion(const Val: string);
  208.  
  209.     { Icon service routines }
  210.     function  ReadIcon(const Index: integer): TIcon;
  211.     function  GeTdfsIcon(Index: integer): TIcon;
  212.  
  213.     { Owner drawing routines }
  214. {    procedure MeasureItem(Index: Integer; var Height: Integer);              override;}
  215.     procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
  216.   public
  217.     constructor Create(AOwner: TComponent); override;
  218.  
  219.     { Returns a specific TIcon in the list.  The TIcon is owned by the
  220.       component, so you should NEVER free it. }
  221.     property Icon[Index: integer]: TIcon
  222.        read GeTdfsIcon;
  223.   published
  224.     property Version: string
  225.        read GetVersion
  226.        write SetVersion
  227.        stored FALSE;
  228.     { Name of icon file to display }
  229.     property FileName: string
  230.        read FFileName
  231.        write SetFileName;
  232.     { If true, the combobox will be disabled when FileName does not exist }
  233.     property AutoDisable: boolean
  234.        read FAutoDisable
  235.        write SetAutoDisable
  236.        default TRUE;
  237.     { If true, icons will be loaded as needed, instead of all at once }
  238.     property EnableCaching: boolean
  239.        read FEnableCaching
  240.        write SetEnableCaching
  241.        default TRUE;
  242.     { Number of pixels of white space to add around the icons for padding }
  243.     property Margin: integer
  244.        read FMargin
  245.        write SetMargin
  246.        default 5;
  247.     { The number of icons in the file.  -1 if FileName is not valid.  }
  248.     property NumberOfIcons: integer
  249.        read FNumberOfIcons
  250.        default -1;
  251.  
  252.     { Useful if you have statics the reflect the number of icons, etc. }
  253.     property OnFileChange: TNotifyEvent
  254.        read FOnFileChange
  255.        write FOnFileChange;
  256.  
  257.     { Protected properties in parent that we will make available to everyone }
  258.     property Align;
  259.     property Color;
  260.     property Ctl3D;
  261.     property DragMode;
  262.     property DragCursor;
  263.     property Enabled;
  264.     property ItemIndex;
  265.     property ParentColor;
  266.     property ParentCtl3D;
  267.     property ParentFont;
  268.     property ParentShowHint;
  269.     property PopupMenu;
  270.     property ShowHint;
  271.     property TabOrder;
  272.     property TabStop;
  273.     property Visible;
  274.     property OnClick;
  275.     property OnDblClick;
  276.     property OnDragDrop;
  277.     property OnDragOver;
  278.     property OnEndDrag;
  279.     property OnEnter;
  280.     property OnExit;
  281.     property OnKeyDown;
  282.     property OnKeyPress;
  283.     property OnKeyUp;
  284.   end;
  285.  
  286. implementation
  287.  
  288. uses
  289.   ShellAPI;
  290.  
  291.  
  292. { TdfsIconComboBox Component }
  293. constructor TdfsIconComboBox.Create(AOwner: TComponent);
  294. begin
  295.   inherited Create(AOwner);
  296.   FRecreating := FALSE;
  297.   { Set default values }
  298.   FileName := '';
  299.   AutoDisable := TRUE;
  300.   EnableCaching := TRUE;
  301.   FNumberOfIcons := -1;
  302.   DropDownCount := 5;
  303.   Style := csOwnerDrawFixed;
  304.   ItemHeight := GetSystemMetrics(SM_CYICON) + 6;
  305.   Height := ItemHeight;
  306.   Font.Name := 'Arial';
  307.   Font.Height := ItemHeight;
  308.   Width := GetSystemMetrics(SM_CXICON) + GetSystemMetrics(SM_CXVSCROLL) + 10;
  309. end;
  310.  
  311. {$IFDEF DFS_COMPILER_3_UP}
  312. procedure TdfsIconComboBox.CMRecreateWnd(var Message: TMessage);
  313. begin
  314.   FRecreating := TRUE;
  315.   try
  316.     inherited;
  317.   finally
  318.     FRecreating := FALSE;
  319.   end;
  320. end;
  321. {$ENDIF}
  322.  
  323. procedure TdfsIconComboBox.WMDeleteItem(var Msg: TWMDeleteItem);
  324. var
  325.   Icon: TIcon;
  326. begin
  327.   if FRecreating then exit;
  328.  
  329.   { Don't use GeTdfsIcon here! }
  330.   Icon := TIcon(Items.Objects[Msg.DeleteItemStruct^.itemID]);
  331.   { Free it.  If it is NIL, Free ignores it, so it is safe }
  332.   Icon.Free;
  333.   { Zero out the TIcon we just freed }
  334.   Items.Objects[Msg.DeleteItemStruct^.itemID] := NIL;
  335. end;
  336.  
  337. { Initialize the icon handles, which are stored in the Objects property }
  338. procedure TdfsIconComboBox.LoadIcons;
  339. var
  340.   x: integer;
  341.   Icon: TIcon;
  342.   Buff: array[0..255] of char;
  343.   OldCursor: TCursor;
  344. begin
  345.   { Clear any old icon handles }
  346.   FreeIcons;
  347.   { Reset the contents of the combobox }
  348.   Clear;
  349.   { Update the enabled state of the control }
  350.   UpdateEnabledState;
  351.   { If we have a valid file then setup the combobox. }
  352.   if FileExists(FileName) then begin
  353.     { If we are not loading on demand, set the cursor to an hourglass }
  354.     OldCursor := Screen.Cursor;
  355.     if not EnableCaching then
  356.       Screen.Cursor := crHourGlass;
  357.     { Find out how many icons are in the file }
  358.       FNumberOfIcons := ExtractIcon(hInstance, StrPCopy(Buff, FileName),
  359.          {$IFDEF DFS_WIN32} UINT(-1)); {$ELSE} word(-1)); {$ENDIF}
  360.     { Loop for every icon in the file }
  361.     for x := 0 to NumberOfIcons - 1 do begin
  362.       { If we are not loading on demand... }
  363.       if not EnableCaching then begin
  364.         { Create a TIcon object... }
  365.         Icon := TIcon.Create;
  366.         { and assign the icon to it. }
  367.         Icon.Handle := ExtractIcon(hInstance, Buff, x);
  368.         { Add the icon and a dummy string to the combobox }
  369.         Items.AddObject(Format('%d',[x]), Icon);
  370.       end else
  371.         { We're loading on demand, so just add a dummy string }
  372.         Items.AddObject(Format('%d',[x]), NIL);
  373.     end;
  374.     { Reset the index to the first item. }
  375.     ItemIndex := 0;
  376.     { if not loading on demand, restore the cursor }
  377.     if not EnableCaching then
  378.       Screen.Cursor := OldCursor;
  379.   end;
  380. end;
  381.  
  382. { Free the icon resources we created. }
  383. procedure TdfsIconComboBox.FreeIcons;
  384. var
  385.   x: integer;
  386.   Icon: TIcon;
  387. begin
  388.   { Loop for every icon }
  389.   for x := 0 to Items.Count-1 do begin
  390.     { Get the icon object }
  391.     Icon := TIcon(Items.Objects[x]);  { Don't use GeTdfsIcon here! }
  392.     { Free it.  If it is NIL, Free ignores it, so it is safe }
  393.     Icon.Free;
  394.     { Zero out the TIcon we just freed }
  395.     Items.Objects[x] := NIL;
  396.   end;
  397.   { Reset the number of Icons to reflect that we have no file. }
  398.   FNumberOfIcons := -1;
  399. end;
  400.  
  401. { Disable the control if we don't have a valid filename, and option is enabled }
  402. procedure TdfsIconComboBox.UpdateEnabledState;
  403. begin
  404.   if AutoDisable then
  405.     Enabled := FileExists(FileName)
  406.   else
  407.     Enabled := TRUE;
  408.   { This could be compressed into one statement, but I don't think it }
  409.   { is nearly as readable/understandable this way.  Looks like C.     }
  410. { Enabled := (AutoDisable and FileExists(FileName)) or (not AutoDisable); }
  411. end;
  412.  
  413. { Update the filename of the icon file. }
  414. procedure TdfsIconComboBox.SetFileName(Value: String);
  415. begin
  416.   { If new value is same as old, don't reload icons.  That's silly. }
  417.   if FFileName = Value then exit;
  418.   FFileName := Value;
  419.   { Initialize icon handles from new icon file. }
  420.   LoadIcons;
  421.   { Call user event handler, if one exists }
  422.   if assigned(FOnFileChange) then
  423.     FOnFileChange(Self);
  424. end;
  425.  
  426. { Update the AutoDisable property }
  427. procedure TdfsIconComboBox.SetAutoDisable(Value: boolean);
  428. begin
  429.   { If it's the same, we don't need to do anything }
  430.   if Value = FAutoDisable then exit;
  431.   FAutoDisable := Value;
  432.   { Update the enabled state of control based on new AutoDisable setting }
  433.   UpdateEnabledState;
  434. end;
  435.  
  436. { Update the EnableCaching property }
  437. procedure TdfsIconComboBox.SetEnableCaching(Value: boolean);
  438. begin
  439.   { If it's the same, we don't need to do anything }
  440.   if Value = FEnableCaching then exit;
  441.   FEnableCaching := Value;
  442.   { If load on demand is not enabled, we need to load all the icons. }
  443.   if not FEnableCaching then
  444.     LoadIcons;
  445. end;
  446.  
  447. { Used to extract icons from files and assign them to a TIcon object }
  448. function TdfsIconComboBox.ReadIcon(const Index: integer): TIcon;
  449. var
  450.   Buff: array[0..255] of char;
  451. begin
  452.   { Create the new icon }
  453.   Result := TIcon.Create;
  454.   { Assign it the icon handle }
  455.   Result.Handle := ExtractIcon(hInstance, StrPCopy(Buff, FileName), Index);
  456. end;
  457.  
  458. { Returns the icon for a given combobox index }
  459. function TdfsIconComboBox.GeTdfsIcon(Index: integer): TIcon;
  460. begin
  461.   { If load on demand is enabled... }
  462.   if EnableCaching then
  463.     { Has the icon been loaded yet? }
  464.     if Items.Objects[Index] = NIL then
  465.       { No, we must get the icon and add it to Objects }
  466.       Items.Objects[Index] := ReadIcon(Index);
  467.   { Return the requested icon }
  468.   Result := TIcon(Items.Objects[Index]);
  469. end;
  470.  
  471. { Return the size of the item we are drawing }
  472. procedure TdfsIconComboBox.MeasureItem(Index: Integer; var Height: Integer);
  473. begin
  474.   { Ask Windows how tall icons are }
  475.   Height := GetSystemMetrics(SM_CYICON);
  476. end;
  477.  
  478. { Draw the item requested in the given rectangle.  Because of the parent's default }
  479. { behavior, we needn't worry about the State.  That's very nice.                   }
  480. procedure TdfsIconComboBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  481. var
  482.   Icon: TIcon;
  483. begin
  484.   { Use the controls canvas for drawing... }
  485.   with Canvas do begin
  486.     try
  487.       { Fill in the rectangle.  The proper brush has already been set up for us,   }
  488.       { so we needn't use State to set it ourselves.                               }
  489.       FillRect(Rect);
  490.       { Get the icon to be drawn }
  491.       Icon := GeTdfsIcon(Index);
  492.       { If nothing has gone wrong, draw the icon.  Theoretically, it should never  }
  493.       { be NIL, but why take the chance?                                           }
  494.       if Icon <> nil then
  495.         { Using the given rectangle, draw the icon on the control's canvas,        }
  496.         { centering it within the rectangle.                                       }
  497.         with Rect do Draw(Left + (Right - Left - Icon.Width) div 2,
  498.                           Top + (Bottom - Top - Icon.Width) div 2, Icon);
  499.     except
  500.       { If anything went wrong, we fall down to here.  You may want to add some    }
  501.       { sort of user notification.  No clean up is necessary since we did not      }
  502.       { create anything.  We'll just ignore the problem and hope it goes away. :)  }
  503.       {!};
  504.     end;
  505.   end;
  506. end;
  507.  
  508. function TdfsIconComboBox.GetVersion: string;
  509. begin
  510.   Result := DFS_COMBO_VERSION;
  511. end;
  512.  
  513. procedure TdfsIconComboBox.SetVersion(const Val: string);
  514. begin
  515.   { empty write method, just needed to get it to show up in Object Inspector }
  516. end;
  517.  
  518.  
  519.  
  520. { TdfsIconListBox Component }
  521.  
  522. constructor TdfsIconListBox.Create(AOwner: TComponent);
  523. begin
  524.   inherited Create(AOwner);
  525.   FRecreating := FALSE;
  526.   { Set default values }
  527.   FMargin := 5;
  528.   ItemHeight := GetSystemMetrics(SM_CYICON) + FMargin;{ + 6;}
  529.   Style := lbOwnerDrawFixed;
  530.   Font.Name := 'Arial';
  531.   Font.Height := ItemHeight;
  532.   FileName := '';
  533.   FAutoDisable := TRUE;
  534.   FEnableCaching := TRUE;
  535.   FNumberOfIcons := -1;
  536. end;
  537.  
  538. procedure TdfsIconListBox.CreateParams(var Params: TCreateParams);
  539. begin
  540.   inherited CreateParams(Params);
  541.   Params.Style := Params.Style or LBS_MULTICOLUMN;
  542. {  if Orientation = lbVertical then
  543.     Params.Style := Params.Style or LBS_DISABLENOSCROLL or WS_VSCROLL and (not WS_HSCROLL)
  544.   else
  545.     Params.Style := Params.Style or LBS_DISABLENOSCROLL or WS_HSCROLL and (not WS_VSCROLL);}
  546. end;
  547.  
  548. procedure TdfsIconListBox.CNDeleteItem(var Msg: TWMDeleteItem);
  549. var
  550.   Icon: TIcon;
  551. begin
  552.   if FRecreating then exit;
  553.  
  554.   { Don't use GeTdfsIcon here! }
  555.   Icon := TIcon(Items.Objects[Msg.DeleteItemStruct^.itemID]);
  556.   { Free it.  If it is NIL, Free ignores it, so it is safe }
  557.   Icon.Free;
  558.   { Zero out the TIcon we just freed }
  559.   Items.Objects[Msg.DeleteItemStruct^.itemID] := NIL;
  560. end;
  561.  
  562.  
  563. { Initialize the icon handles, which are stored in the Objects property }
  564. procedure TdfsIconListBox.LoadIcons;
  565.   function CounTdfsIcons(Inst: THandle; Filename: PChar): integer;
  566.   var
  567.     TmpIcon: HICON;
  568.   begin
  569.     Result := 0;
  570.     TmpIcon := ExtractIcon(Inst, Filename, Result);
  571.     while (TmpIcon <> 0) do begin
  572.       inc(Result);
  573.       DestroyIcon(TmpIcon);
  574.       TmpIcon := ExtractIcon(Inst, Filename, Result);
  575.     end;
  576.   end;
  577. var
  578.   x: integer;
  579.   Icon: TIcon;
  580.   Buff: array[0..255] of char;
  581.   OldCursor: TCursor;
  582. begin
  583.   { Clear any old icon handles }
  584.   FreeIcons;
  585.   { Reset the contents of the listbox }
  586.   Clear;
  587.   { Update the enabled state of the control }
  588.   UpdateEnabledState;
  589.   { If we have a valid file then setup the combobox. }
  590.   if FileExists(FileName) then begin
  591.     { If we are not loading on demand, set the cursor to an hourglass }
  592.     OldCursor := Screen.Cursor;
  593.     if not EnableCaching then
  594.       Screen.Cursor := crHourGlass;
  595.     { Find out how many icons are in the file }
  596.       FNumberOfIcons := ExtractIcon(hInstance, StrPCopy(Buff, FileName),
  597.          {$IFDEF DFS_WIN32} UINT(-1)); {$ELSE} word(-1)); {$ENDIF}
  598.     { Loop for every icon in the file }
  599.     for x := 0 to NumberOfIcons - 1 do begin
  600.       { If we are not loading on demand... }
  601.       if not EnableCaching then begin
  602.         { Create a TIcon object... }
  603.         Icon := TIcon.Create;
  604.         { and assign the icon to it. }
  605.         Icon.Handle := ExtractIcon(hInstance, Buff, x);
  606.         { Add the icon and a dummy string to the combobox }
  607.         Items.AddObject(Format('%d',[x]), Icon);
  608.       end else
  609.         { We're loading on demand, so just add a dummy string }
  610.         Items.AddObject(Format('%d',[x]), NIL);
  611.     end;
  612.     { Reset the index to the first item. }
  613.     ItemIndex := 0;
  614.     { if not loading on demand, restore the cursor }
  615.     if not EnableCaching then
  616.       Screen.Cursor := OldCursor;
  617.   end;
  618. end;
  619.  
  620. { Free the icon resources we created. }
  621. procedure TdfsIconListBox.FreeIcons;
  622. var
  623.   x: integer;
  624.   Icon: TIcon;
  625. begin
  626.   { Loop for every icon }
  627.   for x := 0 to Items.Count-1 do begin
  628.     { Get the icon object }
  629.     Icon := TIcon(Items.Objects[x]);  { Don't use GeTdfsIcon here! }
  630.     { Free it.  If it is NIL, Free ignores it, so it is safe }
  631.     Icon.Free;
  632.     { Zero out the TIcon we just freed }
  633.     Items.Objects[x] := NIL;
  634.   end;
  635.   { Reset the number of Icons to reflect that we have no file. }
  636.   FNumberOfIcons := -1;
  637. end;
  638.  
  639. { Disable the control if we don't have a valid filename, and option is enabled }
  640. procedure TdfsIconListBox.UpdateEnabledState;
  641. begin
  642.   if AutoDisable then
  643.     Enabled := FileExists(FileName)
  644.   else
  645.     Enabled := TRUE;
  646. end;
  647.  
  648. (*
  649. { Reset the size of the listbox to reflect changes in orientation and IconsDisplayed }
  650. procedure TdfsIconListBox.ResetSize;
  651. var
  652.   NewWidth, NewHeight: integer;
  653.   Multiplier: integer;
  654. begin
  655.   NewWidth := FItemWidth * XIcons + 2;
  656.   NewHeight := ItemHeight * YIcons + GetSystemMetrics(SM_CYHSCROLL) + 4;
  657.   SetBounds(Left, Top, NewWidth+3, NewHeight);
  658.   // Stupid scrollbar
  659.   Multiplier := NumberOfIcons div YIcons;
  660.   if NumberOfIcons mod YIcons > 0 then
  661.     inc(Multiplier);
  662.   if NewWidth >= FItemWidth * Multiplier + 2 then
  663.     SetBounds(Left, Top, NewWidth+3, NewHeight - GetSystemMetrics(SM_CYHSCROLL));
  664.   { I've had nothing but trouble with Delphi's Columns property.  I'll just do
  665.     it myself, thank you very much. }
  666.   {  Columns := XIcons;}
  667.   { Delphi 4 (maybe other versions, too) screws up in SetColumnWidth.  Things
  668.     get out of whack as the width grows larger. Fix it up after Columns set. }
  669.   if HandleAllocated then
  670. //    SendMessage(Handle, LB_SETCOLUMNWIDTH, FItemWidth, 0);
  671.     SendMessage(Handle, LB_SETCOLUMNWIDTH, NewWidth div XIcons, 0);
  672.  
  673. {
  674.   if Width < FItemWidth * XIcons + 2 then
  675.     Height := ItemHeight * YIcons + GetSystemMetrics(SM_CYHSCROLL) + 1
  676.   else
  677.     Height := ItemHeight * YIcons + 3;
  678.   Width := FItemWidth * XIcons + 2;
  679.   Columns := XIcons;
  680. }
  681. *)
  682. (*  if Orientation = lbVertical then begin
  683.     { Set height to hold the desired number of icons }
  684.     Height := ItemHeight * IconsDisplayed + 2;
  685.     { Set width to an icon plus a scrollbar }
  686.     Width := FItemWidth + GetSystemMetrics(SM_CXVSCROLL) + 10;
  687.     { Make sure we don't have any columns. }
  688.     Columns := 0;
  689.   end else begin
  690.     { Set height to an icon plus a scrollbar }
  691.     Height := ItemHeight + GetSystemMetrics(SM_CYHSCROLL) + 1;
  692.     { Set width to hold the desired number of icons }
  693.     Width := FItemWidth * IconsDisplayed + 2;
  694.     { Set number of columns in the listbox to the desired number of icons }
  695.     Columns := IconsDisplayed;
  696.   end;
  697. end;  *)
  698.  
  699. { Update the filename of the icon file. }
  700. procedure TdfsIconListBox.SetFileName(Value: String);
  701. begin
  702.   { If new value is same as old, don't reload icons.  That's silly. }
  703.   if FFileName = Value then exit;
  704.   FFileName := Value;
  705.   { Initialize icon handles from new icon file. }
  706.   LoadIcons;
  707.   { Call user event handler, if one exists }
  708.   if assigned(FOnFileChange) then
  709.     FOnFileChange(Self);
  710. end;
  711.  
  712. { Update the AutoDisable property }
  713. procedure TdfsIconListBox.SetAutoDisable(Value: boolean);
  714. begin
  715.   { If it's the same, we don't need to do anything }
  716.   if Value = FAutoDisable then exit;
  717.   FAutoDisable := Value;
  718.   { Update the enabled state of control based on new AutoDisable setting }
  719.   UpdateEnabledState;
  720. end;
  721.  
  722. { Update the EnableCaching property }
  723. procedure TdfsIconListBox.SetEnableCaching(Value: boolean);
  724. begin
  725.   { If it's the same, we don't need to do anything }
  726.   if Value = FEnableCaching then exit;
  727.   FEnableCaching := Value;
  728.   { If load on demand is not enabled, we need to load all the icons. }
  729.   if not FEnableCaching then
  730.     LoadIcons;
  731. end;
  732.  
  733. { Used to extract icons from files and assign them to a TIcon object }
  734. function TdfsIconListBox.ReadIcon(const Index: integer): TIcon;
  735. var
  736.   Buff: array[0..255] of char;
  737. begin
  738.   { Create the new icon }
  739.   Result := TIcon.Create;
  740.   { Assign it the icon handle }
  741.   Result.Handle := ExtractIcon(hInstance, StrPCopy(Buff, FileName), Index);
  742. end;
  743.  
  744. { Returns the icon for a given combobox index }
  745. function TdfsIconListBox.GeTdfsIcon(Index: integer): TIcon;
  746. begin
  747.   { If load on demand is enabled... }
  748.   if EnableCaching then
  749.     { Has the icon been loaded yet? }
  750.     if Items.Objects[Index] = NIL then
  751.       { No, we must get the icon and add it to Objects }
  752.       Items.Objects[Index] := ReadIcon(Index);
  753.   { Return the requested icon }
  754.   Result := TIcon(Items.Objects[Index]);
  755. end;
  756.  
  757.  
  758. { Draw the item requested in the given rectangle.  Because of the parent's default }
  759. { behavior, we needn't worry about the State.  That's very nice.                   }
  760. procedure TdfsIconListBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  761. var
  762.   Icon: TIcon;
  763. begin
  764.   { Use the controls canvas for drawing... }
  765.   with Canvas do begin
  766.     try
  767.       { Fill in the rectangle.  The proper brush has already been set up for us,   }
  768.       { so we needn't use State to set it ourselves.                               }
  769.       FillRect(Rect);
  770.       { Get the icon to be drawn }
  771.       Icon := GeTdfsIcon(Index);
  772.       { If nothing has gone wrong, draw the icon.  Theoretically, it should never  }
  773.       { be NIL, but why take the chance?                                           }
  774.       if Icon <> nil then
  775.         { Using the given rectangle, draw the icon on the control's canvas,        }
  776.         { centering it within the rectangle.                                       }
  777.         with Rect do Draw(Left + (Right - Left - Icon.Width) div 2,
  778.                           Top + (Bottom - Top - Icon.Width) div 2, Icon);
  779.     except
  780.       { If anything went wrong, we fall down to here.  You may want to add some    }
  781.       { sort of user notification.  No clean up is necessary since we did not      }
  782.       { create anything.  We'll just ignore the problem and hope it goes away. :)  }
  783.       {!};
  784.     end;
  785.   end;
  786. end;
  787.  
  788. procedure TdfsIconListBox.SetMargin(const Value: integer);
  789. begin
  790.   if Value <> FMargin then
  791.   begin
  792.     FMargin := Value;
  793.     if HandleAllocated then
  794.       SendMessage(Handle, LB_SETCOLUMNWIDTH, GetSystemMetrics(SM_CXICON) +
  795.          FMargin, 0);
  796.     ItemHeight := GetSystemMetrics(SM_CYICON) + FMargin;
  797.  
  798. {    Invalidate;}
  799.   end;
  800. end;
  801.  
  802. function TdfsIconListBox.GetVersion: string;
  803. begin
  804.   Result := DFS_LIST_VERSION;
  805. end;
  806.  
  807. procedure TdfsIconListBox.SetVersion(const Val: string);
  808. begin
  809.   { empty write method, just needed to get it to show up in Object Inspector }
  810. end;
  811.  
  812. procedure TdfsIconListBox.CreateWnd;
  813. begin
  814.   inherited CreateWnd;
  815.   SendMessage(Handle, LB_SETCOLUMNWIDTH, GetSystemMetrics(SM_CXICON) + FMargin,
  816.      0);
  817. end;
  818.  
  819. {$IFDEF DFS_COMPILER_3_UP}
  820. procedure TdfsIconListBox.CMRecreateWnd(var Message: TMessage);
  821. begin
  822.   FRecreating := TRUE;
  823.   try
  824.     inherited;
  825.   finally
  826.     FRecreating := FALSE;
  827.   end;
  828. end;
  829. {$ENDIF}
  830.  
  831. end.
  832.  
  833.