bclealed.pas 13 KB

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