HistoryComboBox.pas 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. unit HistoryComboBox;
  2. interface
  3. uses
  4. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  5. StdCtrls;
  6. type
  7. TUIStateAwareComboBox = class(TComboBox)
  8. protected
  9. procedure ComboWndProc(var Message: TMessage; ComboWnd: HWnd; ComboProc: TWindowProcPtr); override;
  10. end;
  11. type
  12. THistorySaveOn = set of (soExit, soDropDown);
  13. const
  14. DefaultHistorySaveOn = [soExit, soDropDown];
  15. DefaultMaxHistorySize = 30;
  16. type
  17. THistoryComboBox = class;
  18. THistoryComboBoxGetData = procedure(Sender: THistoryComboBox; var Data: Pointer) of object;
  19. THistoryComboBoxSetData = procedure(Sender: THistoryComboBox; Data: Pointer) of object;
  20. THistoryComboBox = class(TUIStateAwareComboBox)
  21. private
  22. { Private declarations }
  23. FSaveOn: THistorySaveOn;
  24. FMaxHistorySize: Integer;
  25. FOnGetData: THistoryComboBoxGetData;
  26. FOnSetData: THistoryComboBoxSetData;
  27. procedure SetMaxHistorySize(AMaxHistorySize: Integer);
  28. function GetMaxItemWidth: Integer;
  29. protected
  30. { Protected declarations }
  31. procedure DoExit; override;
  32. procedure DropDown; override;
  33. procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  34. procedure Change; override;
  35. public
  36. { Public declarations }
  37. constructor Create(AOwner: TComponent); override;
  38. procedure SaveToHistory; virtual;
  39. published
  40. { Published declarations }
  41. property SaveOn: THistorySaveOn read FSaveOn write FSaveOn default DefaultHistorySaveOn;
  42. property MaxHistorySize: Integer read FMaxHistorySize write SetMaxHistorySize default DefaultMaxHistorySize;
  43. property OnGetData: THistoryComboBoxGetData read FOnGetData write FOnGetData;
  44. property OnSetData: THistoryComboBoxSetData read FOnSetData write FOnSetData;
  45. end;
  46. procedure SaveToHistory(Strings: TStrings; T: string; Data: Pointer = nil; MaxHistorySize: Integer = DefaultMaxHistorySize);
  47. procedure Register;
  48. implementation
  49. uses
  50. PasTools;
  51. procedure Register;
  52. begin
  53. RegisterComponents('Martin', [THistoryComboBox]);
  54. end;
  55. procedure SaveToHistory(Strings: TStrings; T: string; Data: Pointer; MaxHistorySize: Integer);
  56. begin
  57. if T <> '' then
  58. begin
  59. while Strings.IndexOf(T) >= 0 do Strings.Delete(Strings.IndexOf(T));
  60. Strings.InsertObject(0, T, TObject(Data));
  61. end;
  62. while Strings.Count > MaxHistorySize do
  63. Strings.Delete(Strings.Count-1);
  64. end;
  65. { TUIStateAwareComboBox }
  66. procedure TUIStateAwareComboBox.ComboWndProc(var Message: TMessage; ComboWnd: HWnd; ComboProc: TWindowProcPtr);
  67. begin
  68. inherited;
  69. if Message.Msg = WM_SYSKEYDOWN then
  70. begin
  71. UpdateUIState(TWMKey(Message).CharCode);
  72. end;
  73. end;
  74. { THistoryComboBox }
  75. constructor THistoryComboBox.Create(AOwner: TComponent);
  76. begin
  77. inherited;
  78. FSaveOn := DefaultHistorySaveOn;
  79. FMaxHistorySize := DefaultMaxHistorySize;
  80. FOnGetData := nil;
  81. FOnSetData := nil;
  82. end;
  83. procedure THistoryComboBox.KeyDown(var Key: Word; Shift: TShiftState);
  84. begin
  85. if ((Key = VK_DOWN) or (Key = VK_UP)) and
  86. (not (ssAlt in Shift)) and (soDropDown in SaveOn) then
  87. begin
  88. if Items.IndexOf(Text) < 0 then SaveToHistory;
  89. end;
  90. if DroppedDown and (Key = VK_DELETE) and (ssCtrl in Shift) and (SaveOn <> []) then
  91. begin
  92. Items.Clear;
  93. Key := 0;
  94. end;
  95. inherited;
  96. end;
  97. procedure THistoryComboBox.SetMaxHistorySize(AMaxHistorySize: Integer);
  98. begin
  99. FMaxHistorySize := AMaxHistorySize;
  100. while Items.Count > FMaxHistorySize do
  101. Items.Delete(Items.Count-1);
  102. end;
  103. procedure THistoryComboBox.DoExit;
  104. begin
  105. inherited;
  106. if soExit in SaveOn then SaveToHistory;
  107. end;
  108. procedure THistoryComboBox.DropDown;
  109. var
  110. ItemWidth: Integer;
  111. begin
  112. inherited;
  113. if soDropDown in SaveOn then SaveToHistory;
  114. ItemWidth := GetMaxItemWidth + ScaleByPixelsPerInch(8, Self);
  115. if Items.Count > DropDownCount then
  116. Inc(ItemWidth, GetSystemMetricsForControl(Self, SM_CXVSCROLL));
  117. Self.Perform(CB_SETDROPPEDWIDTH, ItemWidth, 0);
  118. end;
  119. procedure THistoryComboBox.Change;
  120. var
  121. Index: Integer;
  122. begin
  123. inherited Change;
  124. if Assigned(OnSetData) then
  125. begin
  126. // note that ItemIndex is not reliable
  127. Index := Items.IndexOf(Text);
  128. if Index >= 0 then OnSetData(Self, Items.Objects[Index]);
  129. end;
  130. end;
  131. procedure THistoryComboBox.SaveToHistory;
  132. var
  133. Data: Pointer;
  134. begin
  135. if Text <> '' then
  136. begin
  137. Data := nil;
  138. if Assigned(OnGetData) then
  139. OnGetData(Self, Data);
  140. HistoryComboBox.SaveToHistory(Items, Text, Data, MaxHistorySize);
  141. ItemIndex := 0;
  142. end;
  143. end;
  144. function THistoryComboBox.GetMaxItemWidth: Integer;
  145. var
  146. DC: HDC;
  147. SaveFont: HFont;
  148. Size: TSize;
  149. Index: Integer;
  150. begin
  151. Result := 0;
  152. DC := GetDC(0);
  153. try
  154. SaveFont := SelectObject(DC, Font.Handle);
  155. for Index := 0 to Items.Count - 1 do
  156. begin
  157. GetTextExtentPoint32(DC, PChar(Items[Index]), Length(Items[Index]), Size);
  158. if Size.Cx > Result then Result := Size.Cx;
  159. end;
  160. SelectObject(DC, SaveFont);
  161. finally
  162. ReleaseDC(0, DC);
  163. end;
  164. end;
  165. initialization
  166. end.