1
0

HistoryComboBox.pas 5.5 KB

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