1
0

IEComboBox.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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;
  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. ItemWidth := GetMaxItemWidth + 8;
  180. if Items.Count > DropDowncount then
  181. Inc(ItemWidth, 16);
  182. Self.Perform(CB_SETDROPPEDWIDTH, ItemWidth, 0);
  183. end;
  184. inherited DropDown;
  185. end; {TIECustomComboBox.DropDown}
  186. function TIECustomComboBox.GetTextWidth(Str: string): Integer;
  187. var
  188. DC: HDC;
  189. SaveFont: HFont;
  190. Size: TSize;
  191. begin
  192. DC := GetDC(0);
  193. try
  194. SaveFont := SelectObject(DC, Font.Handle);
  195. GetTextExtentPoint32(DC, PChar(Str), Length(Str), Size);
  196. Result := Size.Cx;
  197. SelectObject(DC, SaveFont);
  198. finally
  199. ReleaseDC(0, DC);
  200. end;
  201. end; {TIECustomComboBox.GetTextWidth}
  202. function TIECustomComboBox.GetMaxItemWidth: Integer;
  203. var
  204. DC: HDC;
  205. SaveFont: HFont;
  206. Size: TSize;
  207. Index: Integer;
  208. begin
  209. Result := 0;
  210. DC := GetDC(0);
  211. try
  212. SaveFont := SelectObject(DC, Font.Handle);
  213. for Index := 0 to Items.Count - 1 do
  214. begin
  215. GetTextExtentPoint32(DC, PChar(ItemText[Index]), Length(ItemText[Index]), Size);
  216. if (ImageList <> nil) and (ItemImage[Index] >= 0) then
  217. Inc(Size.Cx, IconWidth + 6);
  218. Inc(Size.Cx, ItemIndent[Index]);
  219. if Size.Cx > Result then Result := Size.Cx;
  220. end;
  221. SelectObject(DC, SaveFont);
  222. finally
  223. ReleaseDC(0, DC);
  224. end;
  225. end; {TIECustomComboBox.GetMaxItemWidth}
  226. function TIECustomComboBox.GetTopIndex: Integer;
  227. begin
  228. Result := Perform(CB_GETTOPINDEX, 0, 0);
  229. end; {TIECustomComboBox.GetTopIndex}
  230. {$HINTS OFF}
  231. procedure TIECustomComboBox.DoPreloadImages;
  232. var
  233. Index, Dummy: Integer;
  234. begin
  235. for Index := 0 to Items.Count-1 do
  236. Dummy := ItemImage[Index];
  237. end;
  238. {$HINTS ON}
  239. procedure TIECustomComboBox.ResetItemHeight;
  240. var
  241. AHeight: Integer;
  242. Begin
  243. AHeight := Max(GetItemHeight(Font), 10) + 2;
  244. inherited ItemHeight := AHeight;
  245. if HandleAllocated then
  246. begin
  247. {Set height of list items:}
  248. SendMessage(Handle, CB_SETITEMHEIGHT, 0, Max(AHeight, 12));
  249. {Set height of selection field:}
  250. SendMessage(Handle, CB_SETITEMHEIGHT, -1, AHeight);
  251. {Set height of delphi-control:}
  252. Height := AHeight;
  253. end;
  254. end;
  255. procedure TIECustomComboBox.SetTopIndex(Value: Integer);
  256. begin
  257. if Value <> TopIndex then
  258. Perform(CB_SETTOPINDEX, Value, 0);
  259. end; {TIECustomComboBox.SetTopIndex}
  260. procedure TIECustomComboBox.CNCommand(var Message: TWMCommand);
  261. begin
  262. inherited;
  263. case Message.NotifyCode of
  264. CBN_CLOSEUP:
  265. DoCloseUp(FCanceled);
  266. CBN_SELENDCANCEL:
  267. FCanceled := True;
  268. CBN_SELENDOK:
  269. FCanceled := False;
  270. end;
  271. end; {TIECustomComboBox.CNCommand}
  272. function GetItemHeight(Font: TFont): Integer;
  273. var
  274. DC: HDC;
  275. SaveFont: HFont;
  276. Metrics: TTextMetric;
  277. begin
  278. DC := GetDC(0);
  279. try
  280. SaveFont := SelectObject(DC, Font.Handle);
  281. GetTextMetrics(DC, Metrics);
  282. SelectObject(DC, SaveFont);
  283. finally
  284. ReleaseDC(0, DC);
  285. end;
  286. Result := Metrics.tmHeight;
  287. end; {GetItemHeight}
  288. procedure TIECustomComboBox.DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState);
  289. var
  290. Text: string;
  291. Image: Integer;
  292. InList: Boolean;
  293. begin
  294. inherited;
  295. if Style = csOwnerDrawFixed then
  296. with Canvas do
  297. begin
  298. FillRect(Rect);
  299. Pen.Color := clWindowText;
  300. // Rect.Top = 3 when we draw selected item in component rect (not in dropdown)
  301. InList := (Rect.Top <> 3);
  302. Text := GetItemTextEx(Index, InList);
  303. if InList then Rect.Left := Rect.Left + ItemIndent[Index];
  304. if ImageList <> nil then
  305. begin
  306. Image := ItemImage[Index];
  307. if Image >= 0 then
  308. begin
  309. ImageList.Draw(Canvas, Rect.Left + 2, Rect.Top, Image);
  310. Rect.Left := Rect.Left + IconWidth + 6;
  311. end
  312. else Rect.Left := Rect.Left + 2;
  313. end
  314. else Rect.Left := Rect.Left + 2;
  315. DrawText(Canvas.Handle, PChar(Text), Length(Text), Rect,
  316. DrawTextBiDiModeFlags(DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX));
  317. end;
  318. end;
  319. function TIECustomComboBox.GetItemImage(Index: Integer): Integer;
  320. begin
  321. Result := -1;
  322. end;
  323. function TIECustomComboBox.GetItemIndent(Index: Integer): Integer;
  324. begin
  325. Result := 0;
  326. end;
  327. function TIECustomComboBox.GetItemText(Index: Integer): string;
  328. begin
  329. Result := GetItemTextEx(Index, True);
  330. end;
  331. function TIECustomComboBox.GetItemTextEx(Index: Integer; ForList: Boolean): string;
  332. begin
  333. Result := Items[Index];
  334. end;
  335. function TIECustomComboBox.ImageList: TImageList;
  336. var
  337. ImageListHandle: HImageList;
  338. FileInfo: TSHFileInfo;
  339. begin
  340. if FUseSystemImageList then
  341. begin
  342. if not Assigned(FSystemImageList) then
  343. begin
  344. FSystemImageList := TImageList.Create(Self);
  345. ImageListHandle := SHGetFileInfo('', 0, FileInfo, SizeOf(FileInfo),
  346. SHGFI_SYSICONINDEX or SHGFI_SMALLICON);
  347. if ImageListHandle <> 0 then
  348. with FSystemImageList do
  349. begin
  350. ShareImages := True;
  351. Handle := ImageListHandle;
  352. DrawingStyle := dsTransparent;
  353. end;
  354. end;
  355. Result := FSystemImageList;
  356. end
  357. else Result := nil;
  358. end;
  359. procedure TIECustomComboBox.SetUseSystemImageList(Value: Boolean);
  360. begin
  361. if FUseSystemImageList <> Value then
  362. begin
  363. if not FUseSystemImageList then
  364. begin
  365. if ImageList <> nil then
  366. raise Exception.Create('ImageList is already created.');
  367. end
  368. else FreeAndNil(FSystemImageList);
  369. FUseSystemImageList := Value;
  370. end;
  371. end;
  372. initialization
  373. end.