IEComboBox.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. unit IEComboBox;
  2. {==================================================================
  3. Components TIECustomCombobox / Version 1.4 / January 2000
  4. TIEComboBox
  5. TIEDriveBox
  6. ==================================================================
  7. Description:
  8. ============
  9. TIECustomComboBox is a combobox with variable width of the dropdown list and
  10. provides the additional event OnCloseUp.
  11. TIEComboBox publishes the properties of the class TIECustomComboBox including
  12. the property Align wich might be was forgotten by Borland.
  13. TIEDriveComboBox realizes a selection control for the aviable drives of
  14. the system with icons. The drive icons are taken from the system image
  15. list.
  16. Author:
  17. =======
  18. (c) Ingo Eckel 1999
  19. Sodener Weg 38
  20. 65812 Bad Soden
  21. Germany
  22. For detailed documentation and history see the documentation in TIEDriveComboBox.htm.
  23. V1.3:
  24. - Property DisplayStyle changed.
  25. {==================================================================}
  26. {Required compiler options:}
  27. {$A+,B-,X+,H+,P+}
  28. interface
  29. uses
  30. StdCtrls, Controls, Messages, Types, Classes, Graphics;
  31. const
  32. IconWidth = 16;
  33. type
  34. TIECloseUpEvent = procedure (Sender: TObject; Canceled: Boolean) of object;
  35. // =======================================================================
  36. // Class TIECustomComboBox
  37. // =======================================================================
  38. TIECustomComboBox = class(TCustomComboBox)
  39. private
  40. FDropDownFixedWidth: Integer;
  41. FOnCloseUp: TIECloseUpEvent;
  42. FCanceled: Boolean;
  43. FUseSystemImageList: Boolean;
  44. FSystemImageList: TImageList;
  45. function GetTopIndex: Integer;
  46. procedure SetTopIndex(Value: Integer);
  47. procedure SetUseSystemImageList(Value: Boolean);
  48. procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  49. protected
  50. procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); override;
  51. function GetItemImage(Index: Integer): Integer; virtual;
  52. function GetItemIndent(Index: Integer): Integer; virtual;
  53. function GetItemText(Index: Integer): string;
  54. function GetItemTextEx(Index: Integer; ForList: Boolean): string; virtual;
  55. function ImageList: TImageList; virtual;
  56. procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
  57. procedure DoCloseUp(Canceled: Boolean); virtual;
  58. procedure DropDown; override;
  59. function GetMaxItemWidth: Integer;
  60. procedure ResetItemHeight;
  61. public
  62. constructor Create(AOwner: TComponent); override;
  63. destructor Destroy; override;
  64. function GetTextWidth(Str: string): Integer;
  65. procedure DoPreloadImages;
  66. property ItemImage[Index: Integer]: Integer read GetItemImage;
  67. property ItemIndent[Index: Integer]: Integer read GetItemIndent;
  68. property ItemText[Index: Integer]: string read GetItemText;
  69. property TopIndex: Integer read GetTopIndex write SetTopIndex;
  70. property UseSystemImageList: Boolean read FUseSystemImageList write SetUseSystemImageList;
  71. property DropDownFixedWidth: Integer read FDropDownFixedWidth write FDropDownFixedWidth default 0;
  72. property OnCloseUp: TIECloseUpEvent read FOnCloseUp write FOnCloseUp;
  73. published
  74. end;
  75. // =======================================================================
  76. // Class TIEComboBox
  77. // =======================================================================
  78. TIEComboBox = class(TIECustomComboBox)
  79. published
  80. property DropDownFixedWidth;
  81. property OnCloseUp;
  82. property Style; {Must be published before Items}
  83. property Align;
  84. property Anchors;
  85. property BiDiMode;
  86. property Color;
  87. property Constraints;
  88. property Ctl3D;
  89. property DragCursor;
  90. property DragKind;
  91. property DragMode;
  92. property DropDownCount;
  93. property Enabled;
  94. property Font;
  95. property ImeMode;
  96. property ImeName;
  97. property ItemHeight;
  98. property Items;
  99. property MaxLength;
  100. property ParentBiDiMode;
  101. property ParentColor;
  102. property ParentCtl3D;
  103. property ParentFont;
  104. property ParentShowHint;
  105. property PopupMenu;
  106. property ShowHint;
  107. property Sorted;
  108. property TabOrder;
  109. property TabStop;
  110. property Text;
  111. property Visible;
  112. property OnChange;
  113. property OnClick;
  114. property OnDblClick;
  115. property OnDragDrop;
  116. property OnDragOver;
  117. property OnDrawItem;
  118. property OnDropDown;
  119. property OnEndDock;
  120. property OnEndDrag;
  121. property OnEnter;
  122. property OnExit;
  123. property OnKeyDown;
  124. property OnKeyPress;
  125. property OnKeyUp;
  126. property OnMeasureItem;
  127. property OnStartDock;
  128. property OnStartDrag;
  129. end;
  130. function GetItemHeight(Font: TFont): Integer;
  131. procedure Register;
  132. implementation
  133. uses
  134. SysUtils, Forms, Dialogs, Imglist, ShellAPI, CommCtrl, Math, Windows, PasTools;
  135. procedure Register;
  136. begin
  137. RegisterComponents('DriveDir', [TIEComboBox]);
  138. end;
  139. // =======================================================================
  140. // Class TIECustomComboBox
  141. // =======================================================================
  142. constructor TIECustomComboBox.Create(AOwner: TComponent);
  143. begin
  144. inherited Create(AOwner);
  145. FCanceled := True;
  146. FUseSystemImageList := False;
  147. FSystemImageList := nil;
  148. end; {TIECustomComboBox.Create}
  149. destructor TIECustomComboBox.Destroy;
  150. begin
  151. FreeAndNil(FSystemImageList);
  152. inherited;
  153. end;
  154. procedure TIECustomComboBox.CMFontChanged(var Message: TMessage);
  155. begin
  156. inherited;
  157. ResetItemHeight;
  158. RecreateWnd;
  159. end; {CMFontChanged}
  160. procedure TIECustomComboBox.DoCloseUp(Canceled: Boolean);
  161. begin
  162. if Assigned(FOnCloseUp) then
  163. FOnCloseUp(Self, Canceled);
  164. end; { DoCloseUp }
  165. procedure TIECustomComboBox.DropDown;
  166. var
  167. ItemWidth: Integer;
  168. begin
  169. {Check to see if DropDownFixed Width > 0. Then just set the
  170. width of the list box. Otherwise, loop through the items
  171. and set the width of the list box to 8 pixels > than the
  172. widest string to buffer the right side. Anything less than
  173. 8 for some reason touches the end of the item on high-res
  174. monitor settings.}
  175. if (FDropDownFixedWidth > 0) then
  176. Self.Perform(CB_SETDROPPEDWIDTH, FDropDownFixedWidth, 0)
  177. else
  178. begin
  179. // The same code is in THistoryComboBox.DropDown
  180. ItemWidth := GetMaxItemWidth + ScaleByPixelsPerInch(8);
  181. if Items.Count > DropDownCount then
  182. Inc(ItemWidth, GetSystemMetrics(SM_CXVSCROLL));
  183. Self.Perform(CB_SETDROPPEDWIDTH, ItemWidth, 0);
  184. end;
  185. inherited DropDown;
  186. end; {TIECustomComboBox.DropDown}
  187. function TIECustomComboBox.GetTextWidth(Str: string): Integer;
  188. var
  189. DC: HDC;
  190. SaveFont: HFont;
  191. Size: TSize;
  192. begin
  193. DC := GetDC(0);
  194. try
  195. SaveFont := SelectObject(DC, Font.Handle);
  196. GetTextExtentPoint32(DC, PChar(Str), Length(Str), Size);
  197. Result := Size.Cx;
  198. SelectObject(DC, SaveFont);
  199. finally
  200. ReleaseDC(0, DC);
  201. end;
  202. end; {TIECustomComboBox.GetTextWidth}
  203. function TIECustomComboBox.GetMaxItemWidth: Integer;
  204. var
  205. DC: HDC;
  206. SaveFont: HFont;
  207. Size: TSize;
  208. Index: Integer;
  209. begin
  210. Result := 0;
  211. DC := GetDC(0);
  212. try
  213. SaveFont := SelectObject(DC, Font.Handle);
  214. for Index := 0 to Items.Count - 1 do
  215. begin
  216. GetTextExtentPoint32(DC, PChar(ItemText[Index]), Length(ItemText[Index]), Size);
  217. if (ImageList <> nil) and (ItemImage[Index] >= 0) then
  218. Inc(Size.Cx, IconWidth + 6);
  219. Inc(Size.Cx, ItemIndent[Index]);
  220. if Size.Cx > Result then Result := Size.Cx;
  221. end;
  222. SelectObject(DC, SaveFont);
  223. finally
  224. ReleaseDC(0, DC);
  225. end;
  226. end; {TIECustomComboBox.GetMaxItemWidth}
  227. function TIECustomComboBox.GetTopIndex: Integer;
  228. begin
  229. Result := Perform(CB_GETTOPINDEX, 0, 0);
  230. end; {TIECustomComboBox.GetTopIndex}
  231. {$HINTS OFF}
  232. procedure TIECustomComboBox.DoPreloadImages;
  233. var
  234. Index, Dummy: Integer;
  235. begin
  236. for Index := 0 to Items.Count-1 do
  237. Dummy := ItemImage[Index];
  238. end;
  239. {$HINTS ON}
  240. procedure TIECustomComboBox.ResetItemHeight;
  241. var
  242. AHeight: Integer;
  243. Begin
  244. AHeight := Max(GetItemHeight(Font), 10) + 2;
  245. inherited ItemHeight := AHeight;
  246. if HandleAllocated then
  247. begin
  248. {Set height of list items:}
  249. SendMessage(Handle, CB_SETITEMHEIGHT, 0, Max(AHeight, 12));
  250. {Set height of selection field:}
  251. SendMessage(Handle, CB_SETITEMHEIGHT, -1, AHeight);
  252. {Set height of delphi-control:}
  253. Height := AHeight;
  254. end;
  255. end;
  256. procedure TIECustomComboBox.SetTopIndex(Value: Integer);
  257. begin
  258. if Value <> TopIndex then
  259. Perform(CB_SETTOPINDEX, Value, 0);
  260. end; {TIECustomComboBox.SetTopIndex}
  261. procedure TIECustomComboBox.CNCommand(var Message: TWMCommand);
  262. begin
  263. inherited;
  264. case Message.NotifyCode of
  265. CBN_CLOSEUP:
  266. DoCloseUp(FCanceled);
  267. CBN_SELENDCANCEL:
  268. FCanceled := True;
  269. CBN_SELENDOK:
  270. FCanceled := False;
  271. end;
  272. end; {TIECustomComboBox.CNCommand}
  273. function GetItemHeight(Font: TFont): Integer;
  274. var
  275. DC: HDC;
  276. SaveFont: HFont;
  277. Metrics: TTextMetric;
  278. begin
  279. DC := GetDC(0);
  280. try
  281. SaveFont := SelectObject(DC, Font.Handle);
  282. GetTextMetrics(DC, Metrics);
  283. SelectObject(DC, SaveFont);
  284. finally
  285. ReleaseDC(0, DC);
  286. end;
  287. Result := Metrics.tmHeight;
  288. end; {GetItemHeight}
  289. procedure TIECustomComboBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  290. var
  291. Text: string;
  292. Image: Integer;
  293. InList: Boolean;
  294. begin
  295. inherited;
  296. if Style = csOwnerDrawFixed then
  297. with Canvas do
  298. begin
  299. FillRect(Rect);
  300. Pen.Color := clWindowText;
  301. // Rect.Top = 3 when we draw selected item in component rect (not in dropdown)
  302. InList := (Rect.Top <> 3);
  303. Text := GetItemTextEx(Index, InList);
  304. if InList then Rect.Left := Rect.Left + ItemIndent[Index];
  305. if ImageList <> nil then
  306. begin
  307. Image := ItemImage[Index];
  308. if Image >= 0 then
  309. begin
  310. ImageList.Draw(Canvas, Rect.Left + 2, Rect.Top, Image);
  311. Rect.Left := Rect.Left + IconWidth + 6;
  312. end
  313. else Rect.Left := Rect.Left + 2;
  314. end
  315. else Rect.Left := Rect.Left + 2;
  316. DrawText(Canvas.Handle, PChar(Text), Length(Text), Rect,
  317. DrawTextBiDiModeFlags(DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX));
  318. end;
  319. end;
  320. function TIECustomComboBox.GetItemImage(Index: Integer): Integer;
  321. begin
  322. Result := -1;
  323. end;
  324. function TIECustomComboBox.GetItemIndent(Index: Integer): Integer;
  325. begin
  326. Result := 0;
  327. end;
  328. function TIECustomComboBox.GetItemText(Index: Integer): string;
  329. begin
  330. Result := GetItemTextEx(Index, True);
  331. end;
  332. function TIECustomComboBox.GetItemTextEx(Index: Integer; ForList: Boolean): string;
  333. begin
  334. Result := Items[Index];
  335. end;
  336. function TIECustomComboBox.ImageList: TImageList;
  337. var
  338. ImageListHandle: HImageList;
  339. FileInfo: TSHFileInfo;
  340. begin
  341. if FUseSystemImageList then
  342. begin
  343. if not Assigned(FSystemImageList) then
  344. begin
  345. FSystemImageList := TImageList.Create(Self);
  346. ImageListHandle := SHGetFileInfo('', 0, FileInfo, SizeOf(FileInfo),
  347. SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  348. if ImageListHandle <> 0 then
  349. with FSystemImageList do
  350. begin
  351. ShareImages := True;
  352. Handle := ImageListHandle;
  353. DrawingStyle := dsTransparent;
  354. end;
  355. end;
  356. Result := FSystemImageList;
  357. end
  358. else Result := nil;
  359. end;
  360. procedure TIECustomComboBox.SetUseSystemImageList(Value: Boolean);
  361. begin
  362. if FUseSystemImageList <> Value then
  363. begin
  364. if not FUseSystemImageList then
  365. begin
  366. if ImageList <> nil then
  367. raise Exception.Create('ImageList is already created.');
  368. end
  369. else FreeAndNil(FSystemImageList);
  370. FUseSystemImageList := Value;
  371. end;
  372. end;
  373. initialization
  374. end.