bcmaterialdesignbutton.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. // SPDX-License-Identifier: LGPL-3.0-linking-exception
  2. {******************************* CONTRIBUTOR(S) ******************************
  3. - Edivando S. Santos Brasil | [email protected]
  4. (Compatibility with delphi VCL 11/2018)
  5. ***************************** END CONTRIBUTOR(S) *****************************}
  6. unit BCMaterialDesignButton;
  7. {$I bgracontrols.inc}
  8. interface
  9. uses
  10. Classes, SysUtils, {$IFDEF FPC}LResources,{$ENDIF}
  11. Types, Controls, Graphics, ExtCtrls, BCBaseCtrls, BGRABitmap, BGRABitmapTypes;
  12. type
  13. { TBCMaterialDesignButton }
  14. TBCMaterialDesignButton = class(TBGRAGraphicCtrl)
  15. private
  16. FNormalColor: TColor;
  17. FNormalColorEffect: TColor;
  18. FRoundBorders: single;
  19. FShadow: boolean;
  20. FShadowColor: TColor;
  21. FShadowSize: integer;
  22. FTextColor: TColor;
  23. FTextFont: string;
  24. FTextQuality: TBGRAFontQuality;
  25. FTextShadow: boolean;
  26. FTextShadowColor: TColor;
  27. FTextShadowOffsetX: integer;
  28. FTextShadowOffsetY: integer;
  29. FTextShadowSize: integer;
  30. FTextSize: integer;
  31. FTextStyle: TFontStyles;
  32. FTimer: TTimer;
  33. FBGRA: TBGRABitmap;
  34. FBGRAShadow: TBGRABitmap;
  35. FMousePos: TPoint;
  36. FCircleSize: single;
  37. FCircleAlpha: byte;
  38. procedure SetFNormalColor(AValue: TColor);
  39. procedure SetFNormalColorEffect(AValue: TColor);
  40. procedure SetFRoundBorders(AValue: single);
  41. procedure SetFShadow(AValue: boolean);
  42. procedure SetFShadowColor(AValue: TColor);
  43. procedure SetFShadowSize(AValue: integer);
  44. procedure SetFTextColor(AValue: TColor);
  45. procedure SetFTextFont(AValue: string);
  46. procedure SetFTextQuality(AValue: TBGRAFontQuality);
  47. procedure SetFTextShadow(AValue: boolean);
  48. procedure SetFTextShadowColor(AValue: TColor);
  49. procedure SetFTextShadowOffsetX(AValue: integer);
  50. procedure SetFTextShadowOffsetY(AValue: integer);
  51. procedure SetFTextShadowSize(AValue: integer);
  52. procedure SetFTextSize(AValue: integer);
  53. procedure SetFTextStyle(AValue: TFontStyles);
  54. protected
  55. procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
  56. {%H-}WithThemeSpace: boolean); override;
  57. procedure OnStartTimer({%H-}Sender: TObject);
  58. procedure OnTimer({%H-}Sender: TObject);
  59. procedure Paint; override;
  60. procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  61. X, Y: integer); override;
  62. class function GetControlClassDefaultSize: TSize; override;
  63. procedure TextChanged; override;
  64. procedure UpdateShadow;
  65. public
  66. constructor Create(AOwner: TComponent); override;
  67. destructor Destroy; override;
  68. procedure ClickMe;
  69. published
  70. property RoundBorders: single read FRoundBorders write SetFRoundBorders {$IFDEF FPC}default 5{$ENDIF};
  71. property NormalColor: TColor read FNormalColor write SetFNormalColor default clWhite;
  72. property NormalColorEffect: TColor read FNormalColorEffect
  73. write SetFNormalColorEffect default clSilver;
  74. property Shadow: boolean read FShadow write SetFShadow default True;
  75. property ShadowColor: TColor read FShadowColor write SetFShadowColor default clGray;
  76. property ShadowSize: integer read FShadowSize write SetFShadowSize default 5;
  77. property TextColor: TColor read FTextColor write SetFTextColor default clBlack;
  78. property TextSize: integer read FTextSize write SetFTextSize default 16;
  79. property TextShadow: boolean read FTextShadow write SetFTextShadow default True;
  80. property TextShadowColor: TColor read FTextShadowColor
  81. write SetFTextShadowColor default clBlack;
  82. property TextShadowSize: integer read FTextShadowSize
  83. write SetFTextShadowSize default 2;
  84. property TextShadowOffsetX: integer read FTextShadowOffsetX
  85. write SetFTextShadowOffsetX default 0;
  86. property TextShadowOffsetY: integer read FTextShadowOffsetY
  87. write SetFTextShadowOffsetY default 0;
  88. property TextStyle: TFontStyles read FTextStyle write SetFTextStyle default [];
  89. property TextFont: string read FTextFont write SetFTextFont;
  90. property TextQuality: TBGRAFontQuality read FTextQuality
  91. write SetFTextQuality default fqFineAntialiasing;
  92. published
  93. property Action;
  94. property Align;
  95. property Anchors;
  96. property AutoSize;
  97. property BidiMode;
  98. property BorderSpacing;
  99. {$IFDEF FPC} //#
  100. property OnChangeBounds;
  101. {$ENDIF}
  102. property Caption;
  103. property Constraints;
  104. property DragCursor;
  105. property DragKind;
  106. property DragMode;
  107. property Enabled;
  108. property OnClick;
  109. property OnContextPopup;
  110. property OnDragDrop;
  111. property OnDragOver;
  112. property OnEndDrag;
  113. property OnMouseDown;
  114. property OnMouseMove;
  115. property OnMouseUp;
  116. property OnMouseEnter;
  117. property OnMouseLeave;
  118. property OnMouseWheel;
  119. property OnMouseWheelDown;
  120. property OnMouseWheelUp;
  121. property OnResize;
  122. property OnStartDrag;
  123. property ParentBidiMode;
  124. property ParentFont;
  125. property ParentShowHint;
  126. property PopupMenu;
  127. property ShowHint;
  128. property Visible;
  129. end;
  130. {$IFDEF FPC}procedure Register;{$ENDIF}
  131. implementation
  132. function DrawTextShadow(AWidth, AHeight: integer; AText: string;
  133. AFontHeight: integer; ATextColor, AShadowColor: TBGRAPixel;
  134. AOffSetX, AOffSetY: integer; ARadius: integer = 0; AFontStyle: TFontStyles = [];
  135. AFontName: string = 'Default'; AShowShadow: boolean = True;
  136. AFontQuality: TBGRAFontQuality = fqFineAntialiasing): TBGRACustomBitmap;
  137. var
  138. bmpOut, bmpSdw: TBGRABitmap;
  139. begin
  140. bmpOut := TBGRABitmap.Create(AWidth, AHeight);
  141. bmpOut.FontAntialias := True;
  142. bmpOut.FontHeight := AFontHeight;
  143. bmpOut.FontStyle := AFontStyle;
  144. bmpOut.FontName := AFontName;
  145. bmpOut.FontQuality := AFontQuality;
  146. if AShowShadow then
  147. begin
  148. bmpSdw := TBGRABitmap.Create(AWidth, AHeight);
  149. bmpSdw.FontAntialias := True;
  150. bmpSdw.FontHeight := AFontHeight;
  151. bmpSdw.FontStyle := AFontStyle;
  152. bmpSdw.FontName := AFontName;
  153. bmpSdw.FontQuality := AFontQuality;
  154. bmpSdw.TextRect(Rect(0, 0, bmpSdw.Width, bmpSdw.Height), AText, taCenter, tlCenter, AShadowColor);
  155. BGRAReplace(bmpSdw, bmpSdw.FilterBlurRadial(ARadius, rbFast));
  156. bmpOut.PutImage(0 + AOffSetX, 0 + AOffSetY, bmpSdw,
  157. dmDrawWithTransparency);
  158. bmpSdw.Free;
  159. end;
  160. bmpOut.TextRect(Rect(0, 0, bmpOut.Width, bmpOut.Height), AText, taCenter, tlCenter, ATextColor);
  161. Result := bmpOut;
  162. end;
  163. {$IFDEF FPC}procedure Register;
  164. begin
  165. RegisterComponents('BGRA Button Controls', [TBCMaterialDesignButton]);
  166. end;
  167. {$ENDIF}
  168. { TBCMaterialDesignButton }
  169. procedure TBCMaterialDesignButton.SetFRoundBorders(AValue: single);
  170. begin
  171. if FRoundBorders = AValue then
  172. Exit;
  173. FRoundBorders := AValue;
  174. UpdateShadow;
  175. Invalidate;
  176. end;
  177. procedure TBCMaterialDesignButton.SetFShadow(AValue: boolean);
  178. begin
  179. if FShadow = AValue then
  180. Exit;
  181. FShadow := AValue;
  182. InvalidatePreferredSize;
  183. AdjustSize;
  184. UpdateShadow;
  185. Invalidate;
  186. end;
  187. procedure TBCMaterialDesignButton.SetFShadowColor(AValue: TColor);
  188. begin
  189. if FShadowColor = AValue then
  190. Exit;
  191. FShadowColor := AValue;
  192. UpdateShadow;
  193. Invalidate;
  194. end;
  195. procedure TBCMaterialDesignButton.SetFShadowSize(AValue: integer);
  196. begin
  197. if FShadowSize = AValue then
  198. Exit;
  199. FShadowSize := AValue;
  200. InvalidatePreferredSize;
  201. AdjustSize;
  202. UpdateShadow;
  203. Invalidate;
  204. end;
  205. procedure TBCMaterialDesignButton.SetFTextColor(AValue: TColor);
  206. begin
  207. if FTextColor = AValue then
  208. Exit;
  209. FTextColor := AValue;
  210. Invalidate;
  211. end;
  212. procedure TBCMaterialDesignButton.SetFTextFont(AValue: string);
  213. begin
  214. if FTextFont = AValue then
  215. Exit;
  216. FTextFont := AValue;
  217. InvalidatePreferredSize;
  218. AdjustSize;
  219. Invalidate;
  220. end;
  221. procedure TBCMaterialDesignButton.SetFTextQuality(AValue: TBGRAFontQuality);
  222. begin
  223. if FTextQuality = AValue then
  224. Exit;
  225. FTextQuality := AValue;
  226. InvalidatePreferredSize;
  227. AdjustSize;
  228. Invalidate;
  229. end;
  230. procedure TBCMaterialDesignButton.SetFTextShadow(AValue: boolean);
  231. begin
  232. if FTextShadow = AValue then
  233. Exit;
  234. FTextShadow := AValue;
  235. InvalidatePreferredSize;
  236. AdjustSize;
  237. Invalidate;
  238. end;
  239. procedure TBCMaterialDesignButton.SetFTextShadowColor(AValue: TColor);
  240. begin
  241. if FTextShadowColor = AValue then
  242. Exit;
  243. FTextShadowColor := AValue;
  244. UpdateShadow;
  245. Invalidate;
  246. end;
  247. procedure TBCMaterialDesignButton.SetFTextShadowOffsetX(AValue: integer);
  248. begin
  249. if FTextShadowOffsetX = AValue then
  250. Exit;
  251. FTextShadowOffsetX := AValue;
  252. InvalidatePreferredSize;
  253. AdjustSize;
  254. Invalidate;
  255. end;
  256. procedure TBCMaterialDesignButton.SetFTextShadowOffsetY(AValue: integer);
  257. begin
  258. if FTextShadowOffsetY = AValue then
  259. Exit;
  260. FTextShadowOffsetY := AValue;
  261. InvalidatePreferredSize;
  262. AdjustSize;
  263. Invalidate;
  264. end;
  265. procedure TBCMaterialDesignButton.SetFTextShadowSize(AValue: integer);
  266. begin
  267. if FTextShadowSize = AValue then
  268. Exit;
  269. FTextShadowSize := AValue;
  270. InvalidatePreferredSize;
  271. AdjustSize;
  272. Invalidate;
  273. end;
  274. procedure TBCMaterialDesignButton.SetFTextSize(AValue: integer);
  275. begin
  276. if FTextSize = AValue then
  277. Exit;
  278. FTextSize := AValue;
  279. InvalidatePreferredSize;
  280. AdjustSize;
  281. Invalidate;
  282. end;
  283. procedure TBCMaterialDesignButton.SetFTextStyle(AValue: TFontStyles);
  284. begin
  285. if FTextStyle = AValue then
  286. Exit;
  287. FTextStyle := AValue;
  288. InvalidatePreferredSize;
  289. AdjustSize;
  290. Invalidate;
  291. end;
  292. procedure TBCMaterialDesignButton.CalculatePreferredSize(
  293. var PreferredWidth, PreferredHeight: integer; WithThemeSpace: boolean);
  294. var
  295. ts: TSize;
  296. begin
  297. inherited CalculatePreferredSize(PreferredWidth, PreferredHeight,
  298. WithThemeSpace);
  299. if Caption <> '' then
  300. begin
  301. FBGRA.FontQuality := FTextQuality;
  302. FBGRA.FontName := FTextFont;
  303. FBGRA.FontStyle := FTextStyle;
  304. FBGRA.FontHeight := FTextSize;
  305. FBGRA.FontAntialias := True;
  306. ts := FBGRA.TextSize(Caption);
  307. Inc(PreferredWidth, ts.cx + 26);
  308. Inc(PreferredHeight, ts.cy + 10);
  309. end;
  310. if FShadow then
  311. begin
  312. Inc(PreferredWidth, FShadowSize * 2);
  313. Inc(PreferredHeight, FShadowSize * 2);
  314. end;
  315. end;
  316. procedure TBCMaterialDesignButton.SetFNormalColor(AValue: TColor);
  317. begin
  318. if FNormalColor = AValue then
  319. Exit;
  320. FNormalColor := AValue;
  321. Invalidate;
  322. end;
  323. procedure TBCMaterialDesignButton.SetFNormalColorEffect(AValue: TColor);
  324. begin
  325. if FNormalColorEffect = AValue then
  326. Exit;
  327. FNormalColorEffect := AValue;
  328. Invalidate;
  329. end;
  330. procedure TBCMaterialDesignButton.OnStartTimer(Sender: TObject);
  331. begin
  332. FCircleAlpha := 255;
  333. FCircleSize := 5;
  334. end;
  335. procedure TBCMaterialDesignButton.OnTimer(Sender: TObject);
  336. begin
  337. FCircleSize := FCircleSize + 8;
  338. if FCircleAlpha - 10 > 0 then
  339. FCircleAlpha := FCircleAlpha - 10
  340. else
  341. FCircleAlpha := 0;
  342. if FCircleAlpha <= 0 then
  343. FTimer.Enabled := False;
  344. Invalidate;
  345. end;
  346. procedure TBCMaterialDesignButton.Paint;
  347. var
  348. temp: TBGRABitmap;
  349. round_rect_left: integer;
  350. round_rect_width: integer;
  351. round_rect_height: integer;
  352. text_height: integer;
  353. begin
  354. if (FBGRA.Width <> Width) or (FBGRA.Height <> Height) then
  355. begin
  356. FBGRA.SetSize(Width, Height);
  357. FBGRAShadow.SetSize(Width, Height);
  358. UpdateShadow;
  359. end;
  360. FBGRA.FillTransparent;
  361. if FShadow then
  362. FBGRA.PutImage(0, 0, FBGRAShadow, dmDrawWithTransparency);
  363. temp := TBGRABitmap.Create(Width, Height, FNormalColor);
  364. temp.EllipseAntialias(FMousePos.X, FMousePos.Y, FCircleSize, FCircleSize,
  365. ColorToBGRA(FNormalColorEffect, FCircleAlpha), 1,
  366. ColorToBGRA(FNormalColorEffect, FCircleAlpha));
  367. if FShadow then
  368. begin
  369. round_rect_left := FShadowSize;
  370. round_rect_width := Width - FShadowSize;
  371. round_rect_height := Height - FShadowSize;
  372. end
  373. else
  374. begin
  375. round_rect_left := 0;
  376. round_rect_width := width;
  377. round_rect_height := height;
  378. end;
  379. FBGRA.FillRoundRectAntialias(round_rect_left, 0, round_rect_width, round_rect_height,
  380. FRoundBorders, FRoundBorders, temp, [rrDefault], False);
  381. temp.Free;
  382. if Caption <> '' then
  383. begin
  384. if FShadow then
  385. text_height := Height - FShadowSize
  386. else
  387. text_height := Height;
  388. temp := DrawTextShadow(Width, text_height, Caption,
  389. FTextSize, FTextColor, FTextShadowColor, FTextShadowOffsetX,
  390. FTextShadowOffsetY, FTextShadowSize, FTextStyle, FTextFont,
  391. FTextShadow, FTextQuality) as TBGRABitmap;
  392. FBGRA.PutImage(0, 0, temp, dmDrawWithTransparency);
  393. temp.Free;
  394. end;
  395. FBGRA.Draw(Canvas, 0, 0, False);
  396. end;
  397. procedure TBCMaterialDesignButton.MouseDown(Button: TMouseButton;
  398. Shift: TShiftState; X, Y: integer);
  399. begin
  400. FTimer.Enabled := False;
  401. FMousePos := Point(X, Y);
  402. FTimer.Enabled := True;
  403. inherited MouseDown(Button, Shift, X, Y);
  404. end;
  405. class function TBCMaterialDesignButton.GetControlClassDefaultSize: TSize;
  406. begin
  407. Result.CX := 123;
  408. Result.CY := 33;
  409. end;
  410. procedure TBCMaterialDesignButton.TextChanged;
  411. begin
  412. InvalidatePreferredSize;
  413. AdjustSize;
  414. Invalidate;
  415. end;
  416. procedure TBCMaterialDesignButton.UpdateShadow;
  417. begin
  418. FBGRAShadow.FillTransparent;
  419. if FShadow then
  420. begin
  421. FBGRAShadow.RoundRectAntialias(FShadowSize, FShadowSize, Width - FShadowSize,
  422. Height - FShadowSize, FRoundBorders, FRoundBorders,
  423. FShadowColor, 1, FShadowColor, [rrDefault]);
  424. BGRAReplace(FBGRAShadow, FBGRAShadow.FilterBlurRadial(FShadowSize,
  425. FShadowSize, rbFast) as TBGRABitmap);
  426. end;
  427. end;
  428. constructor TBCMaterialDesignButton.Create(AOwner: TComponent);
  429. begin
  430. inherited Create(AOwner);
  431. with GetControlClassDefaultSize do
  432. SetInitialBounds(0, 0, CX, CY);
  433. FTimer := TTimer.Create(Self);
  434. FTimer.Interval := 15;
  435. FTimer.Enabled := False;
  436. {$IFDEF FPC}//#
  437. FTimer.OnStartTimer := OnStartTimer;
  438. {$ENDIF}
  439. FTimer.OnTimer := OnTimer;
  440. FBGRA := TBGRABitmap.Create(Width, Height);
  441. FBGRAShadow := TBGRABitmap.Create(Width, Height);
  442. FRoundBorders := 5;
  443. FNormalColor := clWhite;
  444. FNormalColorEffect := clSilver;
  445. FShadow := True;
  446. FShadowColor := clGray;
  447. FShadowSize := 5;
  448. FTextColor := clBlack;
  449. FTextSize := 16;
  450. FTextShadow := True;
  451. FTextShadowColor := clBlack;
  452. FTextShadowSize := 2;
  453. FTextShadowOffsetX := 0;
  454. FTextShadowOffsetY := 0;
  455. FTextStyle := [];
  456. FTextFont := 'default';
  457. FTextQuality := fqFineAntialiasing;
  458. end;
  459. destructor TBCMaterialDesignButton.Destroy;
  460. begin
  461. FTimer.Enabled := False;
  462. {$IFDEF FPC}//#
  463. FTimer.OnStartTimer := nil;
  464. {$ENDIF}
  465. FTimer.OnTimer := nil;
  466. FreeAndNil(FBGRA);
  467. FreeAndNil(FBGRAShadow);
  468. inherited Destroy;
  469. end;
  470. procedure TBCMaterialDesignButton.ClickMe;
  471. begin
  472. FMousePos := Point(Width div 2, Height div 2);
  473. FTimer.Enabled := True;
  474. inherited Click;
  475. end;
  476. end.