bccheckcombobox.pas 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. unit BCCheckComboBox;
  2. {$mode delphi}
  3. interface
  4. uses
  5. {$ifdef WINDOWS}Windows,{$endif} Classes, SysUtils, LResources, Forms, Controls, ExtCtrls, Graphics, Dialogs, BCButton,
  6. StdCtrls, BCTypes, BCBaseCtrls, BGRABitmap, BGRABitmapTypes, LMessages, LCLType,
  7. CheckLst, BGRATheme;
  8. type
  9. { TBCCheckComboBox }
  10. TBCCheckComboBox = class(TBCStyleCustomControl)
  11. private
  12. FButton: TBCButton;
  13. FCanvasScaleMode: TBCCanvasScaleMode;
  14. FDropDownBorderSize: integer;
  15. FDropDownCount: integer;
  16. FDropDownColor: TColor;
  17. FDropDownFontColor: TColor;
  18. FDropDownFontHighlight: TColor;
  19. FDropDownHighlight: TColor;
  20. FFocusBorderColor: TColor;
  21. FFocusBorderOpacity: byte;
  22. FItems: TStringList;
  23. FItemIndex: integer;
  24. FForm: TForm;
  25. FFormHideDate: TDateTime;
  26. FHoverItem: integer;
  27. FItemHeight: integer;
  28. FListBox: TCheckListBox;
  29. FDropDownBorderColor: TColor;
  30. FOnDrawItem: TDrawItemEvent;
  31. FOnDrawSelectedItem: TOnAfterRenderBCButton;
  32. FOnChange: TNotifyEvent;
  33. FOnDropDown: TNotifyEvent;
  34. FDrawingDropDown: boolean;
  35. FTimerCheckFormHide: TTimer;
  36. FQueryFormHide: boolean;
  37. procedure ButtonClick(Sender: TObject);
  38. procedure DrawCheckBox(aCaption: string; State: TBGRAThemeButtonState;
  39. aFocused: boolean; Checked: boolean; ARect: TRect;
  40. ASurface: TBGRAThemeSurface);
  41. procedure FormDeactivate(Sender: TObject);
  42. procedure FormHide(Sender: TObject);
  43. function GetArrowFlip: boolean;
  44. function GetCaption: String;
  45. function GetComboCanvas: TCanvas;
  46. function GetArrowSize: integer;
  47. function GetArrowWidth: integer;
  48. function GetGlobalOpacity: byte;
  49. function GetItemText: string;
  50. function GetDropDownColor: TColor;
  51. function GetItemIndex: integer;
  52. function GetItems: TStrings;
  53. function GetMemoryUsage: TBCButtonMemoryUsage;
  54. function GetOnDrawSelectedItem: TOnAfterRenderBCButton;
  55. function GetRounding: TBCRounding;
  56. function GetStateClicked: TBCButtonState;
  57. function GetStateHover: TBCButtonState;
  58. function GetStateNormal: TBCButtonState;
  59. function GetStaticButton: boolean;
  60. procedure ListBoxKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState
  61. );
  62. procedure ListBoxMouseUp({%H-}Sender: TObject; {%H-}Button: TMouseButton;
  63. {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
  64. procedure ListBoxMouseLeave(Sender: TObject);
  65. procedure ListBoxMouseMove(Sender: TObject; {%H-}Shift: TShiftState; X,
  66. Y: Integer);
  67. procedure ListBoxSelectionChange(Sender: TObject; {%H-}User: boolean);
  68. procedure ListBoxDrawItem(Control: TWinControl; Index: Integer;
  69. ARect: TRect; State: TOwnerDrawState);
  70. procedure OnAfterRenderButton(Sender: TObject; const ABGRA: TBGRABitmap;
  71. AState: TBCButtonState; ARect: TRect);
  72. procedure OnTimerCheckFormHide(Sender: TObject);
  73. procedure SetArrowFlip(AValue: boolean);
  74. procedure SetArrowSize(AValue: integer);
  75. procedure SetArrowWidth(AValue: integer);
  76. procedure SetCanvasScaleMode(AValue: TBCCanvasScaleMode);
  77. procedure SetCaption(AValue: String);
  78. procedure SetDropDownColor(AValue: TColor);
  79. procedure SetGlobalOpacity(AValue: byte);
  80. procedure SetItemIndex(AValue: integer);
  81. procedure SetItems(AValue: TStrings);
  82. procedure SetMemoryUsage(AValue: TBCButtonMemoryUsage);
  83. procedure SetOnDrawSelectedItem(AValue: TOnAfterRenderBCButton);
  84. procedure SetRounding(AValue: TBCRounding);
  85. procedure SetStateClicked(AValue: TBCButtonState);
  86. procedure SetStateHover(AValue: TBCButtonState);
  87. procedure SetStateNormal(AValue: TBCButtonState);
  88. procedure SetStaticButton(AValue: boolean);
  89. protected
  90. function GetStyleExtension: String; override;
  91. procedure WMSetFocus(var {%H-}Message: {$IFDEF FPC}TLMSetFocus{$ELSE}TWMSetFocus{$ENDIF}); message {$IFDEF FPC}LM_SETFOCUS{$ELSE}WM_SETFOCUS{$ENDIF};
  92. procedure WMKillFocus(var Message: {$IFDEF FPC}TLMKillFocus{$ELSE}TWMKillFocus{$ENDIF}); message {$IFDEF FPC}LM_KILLFOCUS{$ELSE}WM_KILLFOCUS{$ENDIF};
  93. procedure UpdateFocus(AFocused: boolean);
  94. procedure KeyDown(var Key: Word; {%H-}Shift: TShiftState); override;
  95. procedure UTF8KeyPress(var UTF8Key: TUTF8Char); override;
  96. procedure CreateForm;
  97. procedure FreeForm;
  98. function GetListBox: TCheckListBox;
  99. procedure UpdateButtonCanvasScaleMode;
  100. public
  101. constructor Create(AOwner: TComponent); override;
  102. destructor Destroy; override;
  103. { Assign the properties from Source to this instance }
  104. procedure Assign(Source: TPersistent); override;
  105. procedure Clear;
  106. property HoverItem: integer read FHoverItem;
  107. property Button: TBCButton read FButton write FButton;
  108. property ListBox: TCheckListBox read GetListBox;
  109. property Text: string read GetItemText;
  110. published
  111. property Anchors;
  112. property Canvas: TCanvas read GetComboCanvas;
  113. property CanvasScaleMode: TBCCanvasScaleMode read FCanvasScaleMode write SetCanvasScaleMode default csmAuto;
  114. property Caption: String read GetCaption write SetCaption;
  115. property Items: TStrings read GetItems write SetItems;
  116. property ItemIndex: integer read GetItemIndex write SetItemIndex;
  117. property ItemHeight: integer read FItemHeight write FItemHeight default 0;
  118. property ArrowSize: integer read GetArrowSize write SetArrowSize;
  119. property ArrowWidth: integer read GetArrowWidth write SetArrowWidth;
  120. property ArrowFlip: boolean read GetArrowFlip write SetArrowFlip default false;
  121. property FocusBorderColor: TColor read FFocusBorderColor write FFocusBorderColor default clBlack;
  122. property FocusBorderOpacity: byte read FFocusBorderOpacity write FFocusBorderOpacity default 255;
  123. property DropDownBorderColor: TColor read FDropDownBorderColor write FDropDownBorderColor default clWindowText;
  124. property DropDownBorderSize: integer read FDropDownBorderSize write FDropDownBorderSize default 1;
  125. property DropDownColor: TColor read GetDropDownColor write SetDropDownColor default clWindow;
  126. property DropDownFontColor: TColor read FDropDownFontColor write FDropDownFontColor default clWindowText;
  127. property DropDownCount: integer read FDropDownCount write FDropDownCount default 8;
  128. property DropDownHighlight: TColor read FDropDownHighlight write FDropDownHighlight default clHighlight;
  129. property DropDownFontHighlight: TColor read FDropDownFontHighlight write FDropDownFontHighlight default clHighlightText;
  130. property GlobalOpacity: byte read GetGlobalOpacity write SetGlobalOpacity;
  131. property MemoryUsage: TBCButtonMemoryUsage read GetMemoryUsage write SetMemoryUsage;
  132. property Rounding: TBCRounding read GetRounding write SetRounding;
  133. property StateClicked: TBCButtonState read GetStateClicked write SetStateClicked;
  134. property StateHover: TBCButtonState read GetStateHover write SetStateHover;
  135. property StateNormal: TBCButtonState read GetStateNormal write SetStateNormal;
  136. property StaticButton: boolean read GetStaticButton write SetStaticButton;
  137. property OnDropDown: TNotifyEvent read FOnDropDown write FOnDropDown;
  138. property OnDrawItem: TDrawItemEvent read FOnDrawItem write FOnDrawItem;
  139. property OnDrawSelectedItem: TOnAfterRenderBCButton read GetOnDrawSelectedItem write SetOnDrawSelectedItem;
  140. property OnChange: TNotifyEvent read FOnChange write FOnChange;
  141. property TabStop;
  142. property TabOrder;
  143. end;
  144. procedure Register;
  145. implementation
  146. uses math, PropEdits, BGRAText;
  147. procedure Register;
  148. begin
  149. RegisterComponents('BGRA Controls', [TBCCheckComboBox]);
  150. end;
  151. { TBCCheckComboBox }
  152. procedure TBCCheckComboBox.ButtonClick(Sender: TObject);
  153. const MinDelayReopen = 500/(1000*60*60*24);
  154. var
  155. p: TPoint;
  156. h: Integer;
  157. s: TSize;
  158. begin
  159. {$IFDEF DARWIN}
  160. if Assigned(FForm) and not FForm.Visible then FreeForm;
  161. {$ENDIF}
  162. CreateForm;
  163. if FForm.Visible then
  164. FForm.Visible := false
  165. else
  166. if Now > FFormHideDate+MinDelayReopen then
  167. begin
  168. p := ControlToScreen(Point(FButton.Left, FButton.Top + FButton.Height));
  169. FForm.Left := p.X;
  170. FForm.Top := p.Y;
  171. FForm.Color := FDropDownBorderColor;
  172. FListBox.Font.Name := Button.StateNormal.FontEx.Name;
  173. FListBox.Font.Style := Button.StateNormal.FontEx.Style;
  174. FListBox.Font.Height := FontEmHeightSign*Button.StateNormal.FontEx.Height;
  175. self.Canvas.Font.Assign(FListBox.Font);
  176. if Assigned(FOnDrawItem) and (FItemHeight <> 0) then
  177. h := FItemHeight else h := self.Canvas.GetTextHeight('Hg');
  178. {$IFDEF WINDOWS}inc(h,6);{$ENDIF}
  179. FListBox.ItemHeight := h;
  180. {$IFDEF LINUX}inc(h,6);{$ENDIF}
  181. {$IFDEF DARWIN}inc(h,2);{$ENDIF}
  182. s := TSize.Create(FButton.Width, h*min(Items.Count, FDropDownCount) + 2*FDropDownBorderSize);
  183. FForm.ClientWidth := s.cx;
  184. FForm.ClientHeight := s.cy;
  185. FListBox.SetBounds(FDropDownBorderSize,FDropDownBorderSize,
  186. s.cx - 2*FDropDownBorderSize,
  187. s.cy - 2*FDropDownBorderSize);
  188. if FForm.Top + FForm.Height > Screen.WorkAreaTop + Screen.WorkAreaHeight then
  189. FForm.Top := FForm.Top - FForm.Height - Self.Height;
  190. if Assigned(FOnDropDown) then FOnDropDown(self);
  191. FForm.Visible := True;
  192. if FListBox.CanSetFocus then
  193. FListBox.SetFocus;
  194. FTimerCheckFormHide.Enabled:= true;
  195. FQueryFormHide := false;
  196. end;
  197. end;
  198. procedure TBCCheckComboBox.FormDeactivate(Sender: TObject);
  199. begin
  200. FQueryFormHide := true;
  201. end;
  202. procedure TBCCheckComboBox.FormHide(Sender: TObject);
  203. begin
  204. FFormHideDate := Now;
  205. end;
  206. function TBCCheckComboBox.GetArrowFlip: boolean;
  207. begin
  208. result := Button.FlipArrow;
  209. end;
  210. function TBCCheckComboBox.GetCaption: String;
  211. begin
  212. Result := Button.Caption;
  213. end;
  214. function TBCCheckComboBox.GetComboCanvas: TCanvas;
  215. begin
  216. if FDrawingDropDown then
  217. result := ListBox.Canvas
  218. else
  219. result := inherited Canvas;
  220. end;
  221. function TBCCheckComboBox.GetArrowSize: integer;
  222. begin
  223. result := Button.DropDownArrowSize;
  224. end;
  225. function TBCCheckComboBox.GetArrowWidth: integer;
  226. begin
  227. result := Button.DropDownWidth;
  228. end;
  229. function TBCCheckComboBox.GetGlobalOpacity: byte;
  230. begin
  231. result := Button.GlobalOpacity;
  232. end;
  233. function TBCCheckComboBox.GetItemText: string;
  234. begin
  235. if ItemIndex<>-1 then
  236. result := Items[ItemIndex]
  237. else
  238. result := '';
  239. end;
  240. function TBCCheckComboBox.GetDropDownColor: TColor;
  241. begin
  242. if Assigned(FListBox) then
  243. result := FListBox.Color
  244. else result := FDropDownColor;
  245. end;
  246. function TBCCheckComboBox.GetItemIndex: integer;
  247. begin
  248. if Assigned(FListBox) then
  249. result := FListBox.ItemIndex
  250. else
  251. begin
  252. if FItemIndex >= Items.Count then
  253. FItemIndex := -1;
  254. result := FItemIndex;
  255. end;
  256. end;
  257. function TBCCheckComboBox.GetItems: TStrings;
  258. begin
  259. if Assigned(FListBox) then
  260. Result := FListBox.Items
  261. else Result := FItems;
  262. end;
  263. function TBCCheckComboBox.GetMemoryUsage: TBCButtonMemoryUsage;
  264. begin
  265. result := Button.MemoryUsage;
  266. end;
  267. function TBCCheckComboBox.GetOnDrawSelectedItem: TOnAfterRenderBCButton;
  268. begin
  269. result := FOnDrawSelectedItem;
  270. end;
  271. function TBCCheckComboBox.GetRounding: TBCRounding;
  272. begin
  273. result := Button.Rounding;
  274. end;
  275. function TBCCheckComboBox.GetStateClicked: TBCButtonState;
  276. begin
  277. result := Button.StateClicked;
  278. end;
  279. function TBCCheckComboBox.GetStateHover: TBCButtonState;
  280. begin
  281. result := Button.StateHover;
  282. end;
  283. function TBCCheckComboBox.GetStateNormal: TBCButtonState;
  284. begin
  285. result := Button.StateNormal;
  286. end;
  287. function TBCCheckComboBox.GetStaticButton: boolean;
  288. begin
  289. result := Button.StaticButton;
  290. end;
  291. procedure TBCCheckComboBox.ListBoxKeyDown(Sender: TObject; var Key: Word;
  292. Shift: TShiftState);
  293. begin
  294. if (Key = VK_RETURN) or (Key = VK_ESCAPE) then
  295. begin
  296. ButtonClick(nil);
  297. Key := 0;
  298. end;
  299. end;
  300. procedure TBCCheckComboBox.ListBoxMouseUp(Sender: TObject; Button: TMouseButton;
  301. Shift: TShiftState; X, Y: Integer);
  302. begin
  303. FQueryFormHide := true;
  304. end;
  305. procedure TBCCheckComboBox.ListBoxMouseLeave(Sender: TObject);
  306. begin
  307. FHoverItem := -1;
  308. FListBox.Repaint;
  309. end;
  310. procedure TBCCheckComboBox.ListBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
  311. Y: Integer);
  312. var
  313. TempItem: integer;
  314. begin
  315. TempItem := FListBox.ItemAtPos(Point(x, y), True);
  316. if TempItem <> FHoverItem then
  317. begin
  318. FHoverItem := TempItem;
  319. if (FHoverItem<>-1) and ([ssLeft,ssRight]*Shift <> []) then
  320. FListBox.ItemIndex := FHoverItem;
  321. FListBox.Repaint;
  322. end;
  323. end;
  324. procedure TBCCheckComboBox.ListBoxSelectionChange(Sender: TObject; User: boolean);
  325. begin
  326. Button.Caption := GetItemText;
  327. if User and Assigned(FOnChange) then FOnChange(self);
  328. end;
  329. procedure TBCCheckComboBox.ListBoxDrawItem(Control: TWinControl; Index: Integer;
  330. ARect: TRect; State: TOwnerDrawState);
  331. var
  332. surface: TBGRAThemeSurface;
  333. parentForm: TCustomForm;
  334. lclDPI: Integer;
  335. begin
  336. parentForm := GetParentForm(Control, False);
  337. if Assigned(parentForm) then
  338. lclDPI := parentForm.PixelsPerInch
  339. else lclDPI := Screen.PixelsPerInch;
  340. surface := TBGRAThemeSurface.Create(ARect, TCheckListBox(Control).Canvas, Control.GetCanvasScaleFactor, lclDPI);
  341. try
  342. DrawCheckBox(TCheckListBox(Control).Items[Index], btbsNormal, False, TCheckListBox(Control).Checked[Index], ARect, surface);
  343. finally
  344. surface.Free;
  345. end;
  346. end;
  347. procedure TBCCheckComboBox.DrawCheckBox(aCaption: string; State: TBGRAThemeButtonState;
  348. aFocused: boolean; Checked: boolean; ARect: TRect; ASurface: TBGRAThemeSurface
  349. );
  350. var
  351. Style: TTextStyle;
  352. aColor: TBGRAPixel;
  353. aleft, atop, aright, abottom: integer;
  354. penWidth: single;
  355. begin
  356. with ASurface do
  357. begin
  358. DestCanvas.Font.Color := clBlack;
  359. case State of
  360. btbsHover: aColor := BGRA(0, 120, 215);
  361. btbsActive: aColor := BGRA(0, 84, 153);
  362. btbsDisabled:
  363. begin
  364. DestCanvas.Font.Color := clGray;
  365. aColor := BGRA(204, 204, 204);
  366. end;
  367. else {btbsNormal}
  368. aColor := BGRABlack;
  369. end;
  370. Bitmap.Fill(BGRAWhite);
  371. BitmapRect := ARect;
  372. penWidth := ASurface.ScaleForBitmap(10) / 10;
  373. aleft := round(penWidth);
  374. aright := Bitmap.Height-round(penWidth);
  375. atop := round(penWidth);
  376. abottom := Bitmap.Height-round(penWidth);
  377. Bitmap.RectangleAntialias(aleft-0.5+penWidth/2, atop-0.5+penWidth/2,
  378. aright-0.5-penWidth/2, abottom-0.5-penWidth/2,
  379. aColor, penWidth);
  380. aleft := round(penWidth*2);
  381. aright := Bitmap.Height-round(penWidth*2);
  382. atop := round(penWidth*2);
  383. abottom := Bitmap.Height-round(penWidth*2);
  384. if Checked then
  385. Bitmap.DrawPolyLineAntialias(Bitmap.ComputeBezierSpline(
  386. [BezierCurve(pointF(aleft + 2, atop + 3), PointF((aleft + aright - 1) / 2, abottom - 3)),
  387. BezierCurve(PointF((aleft + aright - 1) / 2, abottom - 3), PointF(
  388. (aleft + aright - 1) / 2, (atop * 2 + abottom - 1) / 3), PointF(aright - 2, atop))]),
  389. Color, penWidth*1.5);
  390. DrawBitmap;
  391. if aCaption <> '' then
  392. begin
  393. fillchar(Style, sizeof(Style), 0);
  394. Style.Alignment := taLeftJustify;
  395. Style.Layout := tlCenter;
  396. Style.Wordbreak := True;
  397. DestCanvas.TextRect(ARect,
  398. ARect.Height, 0, aCaption, Style);
  399. end;
  400. end;
  401. end;
  402. procedure TBCCheckComboBox.OnAfterRenderButton(Sender: TObject;
  403. const ABGRA: TBGRABitmap; AState: TBCButtonState; ARect: TRect);
  404. var
  405. focusMargin: integer;
  406. begin
  407. if Assigned(FOnDrawSelectedItem) then
  408. FOnDrawSelectedItem(self, ABGRA, AState, ARect);
  409. if Focused then
  410. begin
  411. focusMargin := round(2 * Button.CanvasScale);
  412. ABGRA.RectangleAntialias(ARect.Left + focusMargin, ARect.Top + focusMargin,
  413. ARect.Right - focusMargin - 1, ARect.Bottom - focusMargin - 1,
  414. ColorToBGRA(FocusBorderColor, FocusBorderOpacity),
  415. Button.CanvasScale);
  416. end;
  417. end;
  418. procedure TBCCheckComboBox.OnTimerCheckFormHide(Sender: TObject);
  419. {$ifdef WINDOWS}
  420. function IsDropDownOnTop: boolean;
  421. begin
  422. result := Assigned(FForm) and (GetForegroundWindow = FForm.Handle);
  423. end;
  424. {$endif}
  425. begin
  426. if Assigned(FForm) and FForm.Visible and
  427. ({$IFDEF DARWIN}not FForm.Active or {$ENDIF}
  428. {$IFDEF WINDOWS}not IsDropDownOnTop or{$ENDIF}
  429. FQueryFormHide) then
  430. begin
  431. FForm.Visible := false;
  432. FQueryFormHide := false;
  433. FTimerCheckFormHide.Enabled := false;
  434. end;
  435. end;
  436. procedure TBCCheckComboBox.SetArrowFlip(AValue: boolean);
  437. begin
  438. Button.FlipArrow:= AValue;
  439. end;
  440. procedure TBCCheckComboBox.SetArrowSize(AValue: integer);
  441. begin
  442. Button.DropDownArrowSize:= AValue;
  443. end;
  444. procedure TBCCheckComboBox.SetArrowWidth(AValue: integer);
  445. begin
  446. Button.DropDownWidth:= AValue;
  447. end;
  448. procedure TBCCheckComboBox.SetCanvasScaleMode(AValue: TBCCanvasScaleMode);
  449. begin
  450. if FCanvasScaleMode=AValue then Exit;
  451. FCanvasScaleMode:=AValue;
  452. UpdateButtonCanvasScaleMode;
  453. end;
  454. procedure TBCCheckComboBox.SetCaption(AValue: String);
  455. begin
  456. Button.Caption := AValue;
  457. end;
  458. procedure TBCCheckComboBox.SetDropDownColor(AValue: TColor);
  459. begin
  460. if Assigned(FListBox) then
  461. FListBox.Color := AValue
  462. else FDropDownColor:= AValue;
  463. end;
  464. procedure TBCCheckComboBox.SetGlobalOpacity(AValue: byte);
  465. begin
  466. Button.GlobalOpacity := AValue;
  467. end;
  468. procedure TBCCheckComboBox.SetItemIndex(AValue: integer);
  469. begin
  470. if Assigned(FListBox) then
  471. FListBox.ItemIndex := AValue
  472. else
  473. begin
  474. if AValue <> FItemIndex then
  475. begin
  476. FItemIndex := AValue;
  477. Button.Caption := GetItemText;
  478. end;
  479. end;
  480. end;
  481. procedure TBCCheckComboBox.SetItems(AValue: TStrings);
  482. begin
  483. if Assigned(FListBox) then
  484. FListBox.Items.Assign(AValue)
  485. else FItems.Assign(AValue);
  486. end;
  487. procedure TBCCheckComboBox.SetMemoryUsage(AValue: TBCButtonMemoryUsage);
  488. begin
  489. Button.MemoryUsage := AValue;
  490. end;
  491. procedure TBCCheckComboBox.SetOnDrawSelectedItem(AValue: TOnAfterRenderBCButton);
  492. begin
  493. if @FOnDrawSelectedItem = @AValue then Exit;
  494. FOnDrawSelectedItem:= AValue;
  495. FButton.ShowCaption := not Assigned(AValue);
  496. UpdateButtonCanvasScaleMode;
  497. end;
  498. procedure TBCCheckComboBox.SetRounding(AValue: TBCRounding);
  499. begin
  500. Button.Rounding := AValue;
  501. end;
  502. procedure TBCCheckComboBox.SetStateClicked(AValue: TBCButtonState);
  503. begin
  504. Button.StateClicked := AValue;
  505. end;
  506. procedure TBCCheckComboBox.SetStateHover(AValue: TBCButtonState);
  507. begin
  508. Button.StateHover := AValue;
  509. end;
  510. procedure TBCCheckComboBox.SetStateNormal(AValue: TBCButtonState);
  511. begin
  512. Button.StateNormal := AValue;
  513. end;
  514. procedure TBCCheckComboBox.SetStaticButton(AValue: boolean);
  515. begin
  516. Button.StaticButton:= AValue;
  517. end;
  518. function TBCCheckComboBox.GetStyleExtension: String;
  519. begin
  520. result := 'bccombo';
  521. end;
  522. procedure TBCCheckComboBox.WMSetFocus(var Message: TLMSetFocus);
  523. begin
  524. UpdateFocus(True);
  525. end;
  526. procedure TBCCheckComboBox.WMKillFocus(var Message: TLMKillFocus);
  527. begin
  528. if Message.FocusedWnd <> Handle then
  529. UpdateFocus(False);
  530. end;
  531. procedure TBCCheckComboBox.UpdateFocus(AFocused: boolean);
  532. var
  533. lForm: TCustomForm;
  534. oldCaption: string;
  535. begin
  536. lForm := GetParentForm(Self);
  537. if lForm = nil then
  538. exit;
  539. {$IFDEF FPC}//#
  540. if AFocused then
  541. ActiveDefaultControlChanged(lForm.ActiveControl)
  542. else
  543. ActiveDefaultControlChanged(nil);
  544. {$ENDIF}
  545. oldCaption := FButton.Caption;
  546. FButton.Caption := FButton.Caption + '1';
  547. FButton.Caption := oldCaption;
  548. Invalidate;
  549. end;
  550. procedure TBCCheckComboBox.KeyDown(var Key: Word; Shift: TShiftState);
  551. begin
  552. if Key = VK_RETURN then
  553. begin
  554. ButtonClick(nil);
  555. Key := 0;
  556. end
  557. else if Key = VK_DOWN then
  558. begin
  559. if ItemIndex + 1 < Items.Count then
  560. begin
  561. ItemIndex := ItemIndex + 1;
  562. Button.Caption := GetItemText;
  563. if Assigned(FOnChange) then
  564. FOnChange(Self);
  565. end;
  566. Key := 0;
  567. end
  568. else if Key = VK_UP then
  569. begin
  570. if ItemIndex - 1 >= 0 then
  571. begin
  572. ItemIndex := ItemIndex - 1;
  573. Button.Caption := GetItemText;
  574. if Assigned(FOnChange) then
  575. FOnChange(Self);
  576. end;
  577. Key := 0;
  578. end;
  579. end;
  580. procedure TBCCheckComboBox.UTF8KeyPress(var UTF8Key: TUTF8Char);
  581. var
  582. i: integer;
  583. begin
  584. for i:=0 to Items.Count-1 do
  585. begin
  586. if (Items[i] <> '') and Items[i].ToLower.StartsWith(LowerCase(UTF8Key)) then
  587. begin
  588. if ItemIndex <> i then
  589. begin
  590. ItemIndex := i;
  591. Button.Caption := GetItemText;
  592. if Assigned(FOnChange) then
  593. FOnChange(Self);
  594. break;
  595. end;
  596. end;
  597. end;
  598. end;
  599. procedure TBCCheckComboBox.CreateForm;
  600. begin
  601. if FForm = nil then
  602. begin
  603. FForm := TForm.Create(Self);
  604. FForm.Visible := False;
  605. FForm.ShowInTaskBar:= stNever;
  606. FForm.BorderStyle := bsNone;
  607. FForm.OnDeactivate:= FormDeactivate;
  608. FForm.OnHide:=FormHide;
  609. FForm.FormStyle := fsStayOnTop;
  610. end;
  611. if FListBox = nil then
  612. begin
  613. FListBox := TCheckListBox.Create(self);
  614. FListBox.Parent := FForm;
  615. FListBox.BorderStyle := bsNone;
  616. //FListBox.OnSelectionChange := ListBoxSelectionChange;
  617. FListBox.OnMouseLeave:=ListBoxMouseLeave;
  618. FListBox.OnMouseMove:=ListBoxMouseMove;
  619. //FListBox.OnMouseUp:= ListBoxMouseUp;
  620. FListBox.Style := lbOwnerDrawFixed;
  621. FListBox.OnDrawItem:= ListBoxDrawItem;
  622. FListBox.Options := []; // do not draw focus rect
  623. FListBox.OnKeyDown:=ListBoxKeyDown;
  624. if Assigned(FItems) then
  625. begin
  626. FListBox.Items.Assign(FItems);
  627. FreeAndNil(FItems);
  628. end;
  629. FListBox.ItemIndex := FItemIndex;
  630. FListBox.Color := FDropDownColor;
  631. end;
  632. end;
  633. procedure TBCCheckComboBox.FreeForm;
  634. begin
  635. if Assigned(FListBox) then
  636. begin
  637. if FListBox.LCLRefCount > 0 then exit;
  638. if FItems = nil then
  639. FItems := TStringList.Create;
  640. FItems.Assign(FListBox.Items);
  641. FItemIndex := FListBox.ItemIndex;
  642. FDropDownColor:= FListBox.Color;
  643. FreeAndNil(FListBox);
  644. end;
  645. FreeAndNil(FForm);
  646. end;
  647. function TBCCheckComboBox.GetListBox: TCheckListBox;
  648. begin
  649. CreateForm;
  650. result := FListBox;
  651. end;
  652. procedure TBCCheckComboBox.UpdateButtonCanvasScaleMode;
  653. begin
  654. if (CanvasScaleMode = csmFullResolution) or
  655. ((CanvasScaleMode = csmAuto) and not Assigned(FOnDrawSelectedItem)) then
  656. FButton.CanvasScaleMode:= csmFullResolution
  657. else FButton.CanvasScaleMode:= csmScaleBitmap;
  658. end;
  659. constructor TBCCheckComboBox.Create(AOwner: TComponent);
  660. begin
  661. inherited Create(AOwner);
  662. FButton := TBCButton.Create(Self);
  663. FButton.Align := alClient;
  664. FButton.Parent := Self;
  665. FButton.OnClick := ButtonClick;
  666. FButton.DropDownArrow := True;
  667. FButton.OnAfterRenderBCButton := OnAfterRenderButton;
  668. UpdateButtonCanvasScaleMode;
  669. FItems := TStringList.Create;
  670. FHoverItem := -1;
  671. FItemIndex := -1;
  672. DropDownBorderSize := 1;
  673. DropDownColor := clWindow;
  674. DropDownBorderColor := clWindowText;
  675. DropDownCount := 8;
  676. DropDownFontColor := clWindowText;
  677. DropDownHighlight := clHighlight;
  678. DropDownFontHighlight := clHighlightText;
  679. FTimerCheckFormHide := TTimer.Create(self);
  680. FTimerCheckFormHide.Interval:= 30;
  681. FTimerCheckFormHide.OnTimer:= OnTimerCheckFormHide;
  682. end;
  683. destructor TBCCheckComboBox.Destroy;
  684. begin
  685. FreeAndNil(FItems);
  686. inherited Destroy;
  687. end;
  688. procedure TBCCheckComboBox.Assign(Source: TPersistent);
  689. var
  690. src: TBCCheckComboBox;
  691. begin
  692. if Source is TBCCheckComboBox then
  693. begin
  694. src := TBCCheckComboBox(Source);
  695. Button.Assign(src.Button);
  696. Items.Assign(src.Items);
  697. ItemIndex := src.ItemIndex;
  698. DropDownBorderColor := src.DropDownBorderColor;
  699. DropDownBorderSize := src.DropDownBorderSize;
  700. DropDownColor := src.DropDownColor;
  701. DropDownFontColor := src.DropDownFontColor;
  702. DropDownCount := src.DropDownCount;
  703. DropDownHighlight := src.DropDownHighlight;
  704. DropDownFontHighlight := src.DropDownFontHighlight;
  705. end else
  706. inherited Assign(Source);
  707. end;
  708. procedure TBCCheckComboBox.Clear;
  709. begin
  710. Items.Clear;
  711. end;
  712. end.