bcleaqled.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. {
  2. *****************************************************************************
  3. See the file COPYING.modifiedLGPL.txt, included in this distribution,
  4. for details about the license.
  5. *****************************************************************************
  6. Author: Boban Spasic
  7. Credits to: circular from Lazarus forum
  8. }
  9. unit BCLeaQLED;
  10. {$mode ObjFPC}{$H+}
  11. interface
  12. uses
  13. Classes, SysUtils, Controls, LResources, Graphics,
  14. BGRABitmapTypes, BGRABitmap, BGRAGradients, BCLeaTheme, BCLeaTypes;
  15. type
  16. TBCLeaQLED = class(TCustomControl)
  17. private
  18. FBitmap: TBGRABitmap;
  19. FTheme: TBCLeaTheme;
  20. FOnChangeValue: TNotifyEvent;
  21. FValue: boolean;
  22. FColorOn: TColor;
  23. FColorOff: TColor;
  24. FBkgColor: TColor;
  25. FStyle: TZStyle;
  26. FSize: integer;
  27. FAltitude: integer;
  28. FClickable: boolean;
  29. FRounding: integer;
  30. //global intensity of the light
  31. FLightSourceIntensity: single;
  32. //minimum distance always added (positive value)
  33. FLightSourceDistanceTerm: single;
  34. //how much actual distance is taken into account (usually 0 or 1)
  35. FLightSourceDistanceFactor: single;
  36. //how much the location of the lightened pixel is taken into account (usually 0 or 1)
  37. FLightDestFactor: single;
  38. //color of the light reflection
  39. FLightColor: TColor;
  40. //how much light is reflected (0..1)
  41. FSpecularFactor: single;
  42. //how concentrated reflected light is (positive value)
  43. FSpecularIndex: single;
  44. //ambiant lighting whereever the point is (0..1)
  45. FAmbientFactor: single;
  46. //diffusion, i.e. how much pixels are lightened by light source (0..1)
  47. FDiffusionFactor: single;
  48. //how much hidden surface are darkened (0..1)
  49. FNegativeDiffusionFactor: single;
  50. //when diffusion saturates, use light color to show it
  51. FDiffuseSaturation: boolean;
  52. FLightPositionX: integer;
  53. FLightPositionY: integer;
  54. FLightPositionZ: integer;
  55. procedure SetValue(AValue: boolean);
  56. procedure SetAltitude(AValue: integer);
  57. procedure SetColorOn(AValue: TColor);
  58. procedure SetColorOff(AValue: TColor);
  59. procedure SetBkgColor(AValue: TColor);
  60. procedure SetStyle(AValue: TZStyle);
  61. procedure SetSize(AValue: integer);
  62. procedure SetClickable(AValue: boolean);
  63. procedure SetTheme(AValue: TBCLeaTheme);
  64. procedure SetRounding(AValue: integer);
  65. protected
  66. procedure SetEnabled(Value: boolean); override;
  67. procedure SetVisible(Value: boolean); override;
  68. procedure Paint; override;
  69. procedure Resize; override;
  70. procedure Redraw;
  71. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
  72. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
  73. procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
  74. public
  75. constructor Create(AOwner: TComponent); override;
  76. destructor Destroy; override;
  77. procedure UpdateTheme;
  78. procedure ApplyTheme;
  79. procedure SaveThemeToFile(AFileName: string);
  80. procedure LoadThemeFromFile(AFileName: string);
  81. procedure ApplyDefaultTheme;
  82. published
  83. property Align;
  84. property BorderSpacing;
  85. property Cursor;
  86. property Enabled;
  87. property Font;
  88. property ParentColor;
  89. property ParentFont;
  90. property ParentShowHint;
  91. property PopupMenu;
  92. property ShowHint;
  93. property TabOrder;
  94. property TabStop default True;
  95. property Anchors;
  96. property Constraints;
  97. property Visible;
  98. property OnClick;
  99. property OnDblClick;
  100. property OnEnter;
  101. property OnExit;
  102. property OnMouseMove;
  103. property OnMouseDown;
  104. property OnMouseUp;
  105. property OnMouseWheel;
  106. property OnMouseWheelDown;
  107. property OnMouseWheelUp;
  108. property OnKeyDown;
  109. property OnKeyUp;
  110. property OnKeyPress;
  111. property OnContextPopup;
  112. property Value: boolean read FValue write SetValue default False;
  113. property ColorOn: TColor read FColorOn write SetColorOn default TColor($00FF9C15);
  114. property ColorOff: TColor read FColorOff write SetColorOff default TColor($009E5A00);
  115. property BackgroundColor: TColor read FBkgColor write SetBkgColor default clBtnFace;
  116. property Size: integer read FSize write SetSize default 30;
  117. property OnChangeValue: TNotifyEvent read FOnChangeValue write FOnChangeValue;
  118. property Style: TZStyle read FStyle write SetStyle default zsRaised;
  119. property Clickable: boolean read FClickable write SetClickable default False;
  120. property Theme: TBCLeaTheme read FTheme write SetTheme;
  121. property Altitude: integer read FAltitude write SetAltitude default 2;
  122. property Rounding: integer read FRounding write SetRounding default 3;
  123. end;
  124. procedure Register;
  125. implementation
  126. procedure Register;
  127. begin
  128. RegisterComponents('BGRA Controls', [TBCLeaQLED]);
  129. end;
  130. constructor TBCLeaQLED.Create(AOwner: TComponent);
  131. begin
  132. inherited Create(AOwner);
  133. with GetControlClassDefaultSize do
  134. SetInitialBounds(0, 0, 50, 50);
  135. FValue := False;
  136. ApplyDefaultTheme;
  137. FBitmap := TBGRABitmap.Create(Width, Height, FBkgColor);
  138. FClickable := False;
  139. end;
  140. destructor TBCLeaQLED.Destroy;
  141. begin
  142. FreeAndNil(FBitmap);
  143. inherited Destroy;
  144. end;
  145. procedure TBCLeaQLED.SetEnabled(Value: boolean);
  146. begin
  147. inherited SetEnabled(Value);
  148. Invalidate;
  149. end;
  150. procedure TBCLeaQLED.SetVisible(Value: boolean);
  151. begin
  152. inherited SetVisible(Value);
  153. Invalidate;
  154. end;
  155. procedure TBCLeaQLED.Paint;
  156. begin
  157. inherited Paint;
  158. Redraw;
  159. end;
  160. procedure TBCLeaQLED.Resize;
  161. begin
  162. inherited Resize;
  163. {$IFDEF LCLgtk2} Invalidate; {$ENDIF}
  164. end;
  165. procedure TBCLeaQLED.SetStyle(AValue: TZStyle);
  166. begin
  167. if FStyle = AValue then
  168. Exit;
  169. FStyle := AValue;
  170. Invalidate;
  171. end;
  172. procedure TBCLeaQLED.SetValue(AValue: boolean);
  173. begin
  174. if FValue = AValue then
  175. exit;
  176. FValue := AValue;
  177. Invalidate;
  178. end;
  179. procedure TBCLeaQLED.SetSize(AValue: integer);
  180. begin
  181. if FSize = AValue then
  182. exit;
  183. FSize := AValue;
  184. if FSize < 1 then FSize := 1;
  185. Invalidate;
  186. end;
  187. procedure TBCLeaQLED.SetColorOn(AValue: TColor);
  188. begin
  189. if FColorOn = AValue then
  190. Exit;
  191. FColorOn := AValue;
  192. Invalidate;
  193. end;
  194. procedure TBCLeaQLED.SetColorOff(AValue: TColor);
  195. begin
  196. if FColorOff = AValue then
  197. Exit;
  198. FColorOff := AValue;
  199. Invalidate;
  200. end;
  201. procedure TBCLeaQLED.SetBkgColor(AValue: TColor);
  202. begin
  203. if FBkgColor = AValue then
  204. Exit;
  205. FBkgColor := AValue;
  206. Invalidate;
  207. end;
  208. procedure TBCLeaQLED.SetAltitude(AValue: integer);
  209. begin
  210. if FAltitude = AValue then
  211. Exit;
  212. FAltitude := AValue;
  213. Invalidate;
  214. end;
  215. procedure TBCLeaQLED.SetRounding(AValue: integer);
  216. begin
  217. if FRounding = AValue then
  218. Exit;
  219. FRounding := AValue;
  220. Invalidate;
  221. end;
  222. procedure TBCLeaQLED.SetClickable(AValue: boolean);
  223. begin
  224. if FClickable = AValue then
  225. Exit;
  226. FClickable := AValue;
  227. Invalidate;
  228. end;
  229. procedure TBCLeaQLED.SetTheme(AValue: TBCLeaTheme);
  230. begin
  231. if FTheme = AValue then
  232. Exit;
  233. if Assigned(FTheme) then
  234. FTheme := nil;
  235. FTheme := AValue;
  236. ApplyTheme;
  237. end;
  238. procedure TBCLeaQLED.UpdateTheme;
  239. begin
  240. if Assigned(FTheme) then
  241. begin
  242. FTheme.QLED_ColorOn := FColorOn;
  243. FTheme.QLED_ColorOff := FColorOff;
  244. FTheme.QLED_BkgColor := FBkgColor;
  245. FTheme.QLED_Style := FStyle;
  246. FTheme.QLED_Size := FSize;
  247. FTheme.QLED_Altitude := FAltitude;
  248. FTheme.QLED_Rounding := FRounding;
  249. end;
  250. end;
  251. procedure TBCLeaQLED.ApplyTheme;
  252. begin
  253. if Assigned(FTheme) then
  254. begin
  255. FColorOn := FTheme.QLED_ColorOn;
  256. FColorOff := FTheme.QLED_ColorOff;
  257. FBkgColor := FTheme.QLED_BkgColor;
  258. FStyle := FTheme.QLED_Style;
  259. FSize := FTheme.QLED_Size;
  260. FAltitude := FTHeme.QLED_Altitude;
  261. FRounding := FTheme.QLED_Rounding;
  262. FLightSourceIntensity := FTheme.COM_LightSourceIntensity;
  263. FLightSourceDistanceTerm := FTheme.COM_LightSourceDistanceTerm;
  264. FLightSourceDistanceFactor := FTheme.COM_LightSourceDistanceFactor;
  265. FLightDestFactor := FTheme.COM_LightDestFactor;
  266. FLightColor := FTheme.COM_LightColor;
  267. FSpecularFactor := FTheme.COM_SpecularFactor;
  268. FSpecularIndex := FTheme.COM_SpecularIndex;
  269. FAmbientFactor := FTheme.COM_AmbientFactor;
  270. FDiffusionFactor := FTheme.COM_DiffusionFactor;
  271. FNegativeDiffusionFactor := FTheme.COM_NegativeDiffusionFactor;
  272. FDiffuseSaturation := FTheme.COM_DiffuseSaturation;
  273. FLightPositionX := FTheme.COM_LightPositionX;
  274. FLightPositionY := FTheme.COM_LightPositionY;
  275. FLightPositionZ := FTheme.COM_LightPositionZ;
  276. Invalidate;
  277. end
  278. else
  279. begin
  280. ApplyDefaultTheme;
  281. end;
  282. end;
  283. procedure TBCLeaQLED.SaveThemeToFile(AFileName: string);
  284. begin
  285. if Assigned(FTheme) then
  286. FTheme.SaveThemeToFile(AFileName);
  287. end;
  288. procedure TBCLeaQLED.LoadThemeFromFile(AFileName: string);
  289. begin
  290. if Assigned(FTheme) then
  291. FTheme.LoadThemeFromFile(AFileName);
  292. end;
  293. procedure TBCLeaQLED.ApplyDefaultTheme;
  294. begin
  295. FColorOn := TColor($00FF9C15);
  296. FColorOff := TColor($009E5A00);
  297. FBkgColor := clBtnFace;
  298. FStyle := zsRaised;
  299. FSize := 30;
  300. FAltitude := 2;
  301. FRounding := 3;
  302. FAmbientFactor := 0.3;
  303. FSpecularIndex := 10;
  304. FSpecularFactor := 0.6;
  305. FLightDestFactor := 1;
  306. FLightPositionX := -100;
  307. FLightPositionY := -100;
  308. FLightPositionZ := 100;
  309. FLightSourceIntensity := 500;
  310. FLightSourceDistanceTerm := 150;
  311. FLightSourceDistanceFactor := 1;
  312. FNegativeDiffusionFactor := 0.1;
  313. FLightColor := clWhite;
  314. FDiffuseSaturation := False;
  315. FDiffusionFactor := 0.9;
  316. end;
  317. procedure TBCLeaQLED.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
  318. begin
  319. inherited MouseDown(Button, Shift, X, Y);
  320. if FClickable and (Button = mbLeft) then
  321. begin
  322. FValue := not FValue;
  323. Redraw;
  324. if Assigned(FOnChangeValue) then
  325. FOnChangeValue(Self);
  326. end;
  327. end;
  328. procedure TBCLeaQLED.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
  329. begin
  330. inherited MouseUp(Button, Shift, X, Y);
  331. end;
  332. procedure TBCLeaQLED.MouseMove(Shift: TShiftState; X, Y: integer);
  333. begin
  334. inherited MouseMove(Shift, X, Y);
  335. end;
  336. procedure TBCLeaQLED.Redraw;
  337. var
  338. Blur: TBGRABitmap;
  339. Mask, Mask2: TBGRABitmap;
  340. Phong: TPhongShading;
  341. ScaledPhongSize, ScaledBlurSize, ScaledSize: integer;
  342. img: TBGRABitmap;
  343. imgSize: integer;
  344. Margin: integer;
  345. begin
  346. FBitmap.SetSize(Width, Height);
  347. FBitmap.Fill(FBkgColor);
  348. if (Width < 2) or (Height < 2) then Exit;
  349. ScaledSize := Scale96ToForm(FSize);
  350. ScaledPhongSize := Scale96ToForm(5);
  351. ScaledBlurSize := Scale96ToForm(10);
  352. Margin := ScaledBlurSize;
  353. imgSize := ScaledSize + 2*Margin;
  354. img := TBGRABitmap.Create(imgSize, imgSize, ColorToBGRA(ColorToRGB(FBkgColor)));
  355. if Enabled then
  356. begin
  357. if FValue then
  358. img.FillRoundRectAntialias(Margin, Margin, Margin+ScaledSize, Margin+ScaledSize, FRounding, FRounding, FColorOn)
  359. else
  360. img.FillRoundRectAntialias(Margin, Margin, Margin+ScaledSize, Margin+ScaledSize, FRounding, FRounding, FColorOff);
  361. end else
  362. img.FillRoundRectAntialias(Margin, Margin, Margin+ScaledSize, Margin+ScaledSize, FRounding, FRounding, clGray);
  363. if (FStyle = zsRaised) or (FStyle = zsLowered) then
  364. begin
  365. Mask := img.FilterGrayscale as TBGRABitmap;
  366. if (FStyle = zsRaised) then
  367. Mask.Negative;
  368. Blur := Mask.FilterBlurRadial(ScaledPhongSize, ScaledPhongSize, rbFast) as TBGRABitmap;
  369. Blur.FillMask(0, 0, Mask, BGRAPixelTransparent, dmSet);
  370. Mask.Free;
  371. Phong := TPhongShading.Create;
  372. begin
  373. Phong.AmbientFactor := FAmbientFactor;
  374. Phong.SpecularIndex := FSpecularIndex;
  375. Phong.LightDestFactor := FLightDestFactor;
  376. Phong.LightPosition := Point(FLightPositionX, FLightPositionY);
  377. Phong.LightPositionZ := FLightPositionZ;
  378. Phong.LightSourceIntensity := FLightSourceIntensity;
  379. Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
  380. Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
  381. Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
  382. Phong.SpecularFactor := FSpecularFactor;
  383. Phong.DiffusionFactor := FDiffusionFactor;
  384. Phong.DiffuseSaturation := FDiffuseSaturation;
  385. Phong.LightColor := FLightColor;
  386. end;
  387. Phong.Draw(img, Blur, FAltitude, 0, 0, img);
  388. Phong.Free;
  389. Blur.Free;
  390. Mask := TBGRABitmap.Create(imgSize, imgSize, BGRABlack);
  391. Mask.FillRoundRectAntialias(Margin, Margin, Margin+ScaledSize, Margin+ScaledSize, FRounding, FRounding, BGRAWhite);
  392. Mask2 := TBGRABitmap.Create(imgSize, imgSize, ColorToBGRA(ColorToRGB(FBkgColor)));
  393. Mask2.PutImage(0, 0, img, dmSet);
  394. Mask2.ApplyMask(Mask);
  395. Mask.Free;
  396. FBitmap.PutImage((FBitmap.Width - imgSize) div 2, (FBitmap.Height - imgSize) div 2, Mask2, dmDrawWithTransparency);
  397. Mask2.Free;
  398. end
  399. else
  400. begin
  401. Mask := TBGRABitmap.Create(imgSize, imgSize, BGRABlack);
  402. Mask.FillRoundRectAntialias(Margin, Margin, Margin+ScaledSize, Margin+ScaledSize, FRounding, FRounding, BGRAWhite);
  403. Mask2 := TBGRABitmap.Create(imgSize, imgSize, ColorToBGRA(ColorToRGB(FBkgColor)));
  404. Mask2.PutImage(0, 0, img, dmSet);
  405. Mask2.ApplyMask(Mask);
  406. Mask.Free;
  407. FBitmap.PutImage((FBitmap.Width-imgSize) div 2, (FBitmap.Height-imgSize) div 2, Mask2, dmDrawWithTransparency);
  408. Mask2.Free;
  409. end;
  410. img.Free;
  411. if FValue then
  412. begin
  413. Mask := TBGRABitmap.Create(imgSize, imgSize);
  414. Mask.FillRoundRectAntialias(Margin, Margin, Margin+ScaledSize, Margin+ScaledSize, FRounding, FRounding, FColorOn);
  415. Mask := Mask.FilterBlurRadial(ScaledBlurSize, ScaledBlurSize, rbFast);
  416. FBitmap.BlendImageOver((FBitmap.Width-imgSize) div 2, (FBitmap.Height-imgSize) div 2, Mask, boGlow);
  417. Mask.Free;
  418. end;
  419. FBitmap.Draw(Canvas, 0, 0, True);
  420. end;
  421. end.