bcleaselector.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  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: hedgehog, circular and lainz from Lazarus forum
  8. Based on TFluentProgressRing from hedgehog
  9. 2024-11-20 Massimo Magnano Added TextLayout
  10. }
  11. unit BCLeaSelector;
  12. {$mode ObjFPC}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, Controls, Graphics, ExtCtrls, LResources,
  16. BGRABitmapTypes, BGRABitmap, BGRATextFX, BGRAGradients, BCLeaTypes, BCLeaTheme;
  17. type
  18. { TBCLeaSelector }
  19. TBCLeaSelector = class(TCustomControl)
  20. private
  21. FBitmap: TBGRABitmap;
  22. FTheme: TBCLeaTheme;
  23. FOnChangeValue: TNotifyEvent;
  24. FTicksCount: integer;
  25. FValue: integer;
  26. FLineColor: TColor;
  27. FLineBkgColor: TColor;
  28. FLineWidth: integer;
  29. FVerticalPos: single;
  30. FDeltaPos: single;
  31. FSettingVerticalPos: boolean;
  32. FSensitivity: integer;
  33. FMinAngle: integer;
  34. FMaxAngle: integer;
  35. FFontShadowColor: TColor;
  36. FFontShadowOffsetX: integer;
  37. FFontShadowOffsetY: integer;
  38. FFontShadowRadius: integer;
  39. FDrawText: boolean;
  40. FDrawTicks: boolean;
  41. FBkgColor: TColor;
  42. FItems: TStrings;
  43. FMinTicksAngle: integer;
  44. FMaxTicksAngle: integer;
  45. FPointerSize: integer;
  46. FStyle: TZStyle;
  47. FDrawTextPhong: boolean;
  48. FAltitude: integer;
  49. //global intensity of the light
  50. FLightSourceIntensity: single;
  51. //minimum distance always added (positive value)
  52. FLightSourceDistanceTerm: single;
  53. //how much actual distance is taken into account (usually 0 or 1)
  54. FLightSourceDistanceFactor: single;
  55. //how much the location of the lightened pixel is taken into account (usually 0 or 1)
  56. FLightDestFactor: single;
  57. //color of the light reflection
  58. FLightColor: TColor;
  59. //how much light is reflected (0..1)
  60. FSpecularFactor: single;
  61. //how concentrated reflected light is (positive value)
  62. FSpecularIndex: single;
  63. //ambiant lighting whereever the point is (0..1)
  64. FAmbientFactor: single;
  65. //diffusion, i.e. how much pixels are lightened by light source (0..1)
  66. FDiffusionFactor: single;
  67. //how much hidden surface are darkened (0..1)
  68. FNegativeDiffusionFactor: single;
  69. //when diffusion saturates, use light color to show it
  70. FDiffuseSaturation: boolean;
  71. FLightPositionX: integer;
  72. FLightPositionY: integer;
  73. FLightPositionZ: integer;
  74. rTextLayout: TTextLayout;
  75. procedure SetLineBkgColor(AValue: TColor);
  76. procedure SetLineColor(AValue: TColor);
  77. procedure SetTextLayout(AValue: TTextLayout);
  78. procedure SetTicksCount(AValue: integer);
  79. procedure SetValue(AValue: integer);
  80. procedure SetLineWidth(AValue: integer);
  81. procedure UpdateVerticalPos(X, Y: integer);
  82. procedure SetSensitivity(AValue: integer);
  83. procedure SetMinAngle(AValue: integer);
  84. procedure SetMaxAngle(AValue: integer);
  85. procedure SetDrawText(AValue: boolean);
  86. procedure SetDrawTicks(AValue: boolean);
  87. procedure SetBkgColor(AValue: TColor);
  88. procedure SetFFontShadowColor(AValue: TColor);
  89. procedure SetFFontShadowOffsetX(AValue: integer);
  90. procedure SetFFontShadowOffsetY(AValue: integer);
  91. procedure SetFFontShadowRadius(AValue: integer);
  92. procedure SetItems(const Value: TStrings);
  93. procedure ItemsChanged(Sender: TObject);
  94. procedure SetMinTicksAngle(AValue: integer);
  95. procedure SetMaxTicksAngle(AValue: integer);
  96. procedure SetPointerSize(AValue: integer);
  97. procedure SetStyle(AValue: TZStyle);
  98. procedure SetDrawTextPhong(AValue: boolean);
  99. procedure SetTheme(AValue: TBCLeaTheme);
  100. procedure SetAltitude(AValue: integer);
  101. protected
  102. procedure SetEnabled(Value: boolean); override;
  103. procedure SetVisible(Value: boolean); override;
  104. procedure Paint; override;
  105. procedure Resize; override;
  106. procedure Redraw;
  107. procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
  108. procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
  109. procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
  110. public
  111. constructor Create(AOwner: TComponent); override;
  112. destructor Destroy; override;
  113. procedure UpdateTheme;
  114. procedure ApplyTheme;
  115. procedure SaveThemeToFile(AFileName: string);
  116. procedure LoadThemeFromFile(AFileName: string);
  117. procedure ApplyDefaultTheme;
  118. published
  119. property Align;
  120. property BorderSpacing;
  121. property Cursor;
  122. property Enabled;
  123. property Font;
  124. property ParentColor;
  125. property ParentFont;
  126. property ParentShowHint;
  127. property PopupMenu;
  128. property ShowHint;
  129. property TabOrder;
  130. property TabStop default True;
  131. property Anchors;
  132. property Constraints;
  133. property Visible;
  134. property OnClick;
  135. property OnDblClick;
  136. property OnEnter;
  137. property OnExit;
  138. property OnMouseMove;
  139. property OnMouseDown;
  140. property OnMouseUp;
  141. property OnMouseWheel;
  142. property OnMouseWheelDown;
  143. property OnMouseWheelUp;
  144. property OnKeyDown;
  145. property OnKeyUp;
  146. property OnKeyPress;
  147. property OnConTextPopup;
  148. property TicksCount: integer read FTicksCount write SetTicksCount default 3;
  149. property Value: integer read FValue write SetValue default 0;
  150. property LineColor: TColor read FLineColor write SetLineColor default TColor($009E5A00);
  151. property LineBkgColor: TColor read FLineBkgColor write SetLineBkgColor default TColor($00D3D3D3);
  152. property LineWidth: integer read FLineWidth write SetLineWidth default 8;
  153. property OnChangeValue: TNotifyEvent read FOnChangeValue write FOnChangeValue;
  154. //Greater value is less sensitive
  155. property Sensitivity: integer read FSensitivity write SetSensitivity default 10;
  156. property MinAngle: integer read FMinAngle write SetMinAngle default 20;
  157. property MaxAngle: integer read FMaxAngle write SetMaxAngle default 340;
  158. property FontShadowColor: TColor read FFontShadowColor write SetFFontShadowColor default clBlack;
  159. property FontShadowOffsetX: integer read FFontShadowOffsetX write SetFFontShadowOffsetX default 2;
  160. property FontShadowOffsetY: integer read FFontShadowOffsetY write SetFFontShadowOffsetY default 2;
  161. property FontShadowRadius: integer read FFontSHadowRadius write SetFFontShadowRadius default 4;
  162. property DrawText: boolean read FDrawText write SetDrawText default True;
  163. property DrawTicks: boolean read FDrawTicks write SetDrawTicks default False;
  164. property BackgroundColor: TColor read FBkgColor write SetBkgColor default clBtnFace;
  165. property Items: TStrings read FItems write SetItems;
  166. property MinTicksAngle: integer read FMinTicksAngle write SetMinTicksAngle default 20;
  167. property MaxTicksAngle: integer read FMaxTicksAngle write SetMaxTicksAngle default 340;
  168. property PointerSize: integer read FPointerSize write SetPointerSize default 3;
  169. property Style: TZStyle read FStyle write SetStyle default zsRaised;
  170. property DrawTextPhong: boolean read FDrawTextPhong write SetDrawTextPhong default False;
  171. property Theme: TBCLeaTheme read FTheme write SetTheme;
  172. property Altitude: integer read FAltitude write SetAltitude default 2;
  173. property TextLayout: TTextLayout read rTextLayout write SetTextLayout default tlCenter;
  174. end;
  175. procedure Register;
  176. implementation
  177. procedure Register;
  178. begin
  179. RegisterComponents('BGRA Controls', [TBCLeaSelector]);
  180. end;
  181. { TBCLeaSelector }
  182. procedure TBCLeaSelector.SetMaxAngle(AValue: integer);
  183. begin
  184. if FMaxAngle = AValue then
  185. exit;
  186. FMaxAngle := AValue;
  187. if FMaxAngle > 350 then
  188. FMaxAngle := 350;
  189. if FMinAngle > FMaxAngle then
  190. FMaxAngle := FMinAngle;
  191. Invalidate;
  192. end;
  193. procedure TBCLeaSelector.SetMinAngle(AValue: integer);
  194. begin
  195. if FMinAngle = AValue then
  196. exit;
  197. FMinAngle := AValue;
  198. if FMinAngle < 10 then
  199. FMinAngle := 10;
  200. if FMinAngle > FMaxAngle then
  201. FMinAngle := FMaxAngle;
  202. Invalidate;
  203. end;
  204. procedure TBCLeaSelector.SetMaxTicksAngle(AValue: integer);
  205. begin
  206. if FMaxTicksAngle = AValue then
  207. exit;
  208. FMaxTicksAngle := AValue;
  209. if FMaxTicksAngle > 350 then
  210. FMaxTicksAngle := 350;
  211. if FMinTicksAngle > FMaxTicksAngle then
  212. FMaxTicksAngle := FMinTicksAngle;
  213. Invalidate;
  214. end;
  215. procedure TBCLeaSelector.SetMinTicksAngle(AValue: integer);
  216. begin
  217. if FMinTicksAngle = AValue then
  218. exit;
  219. FMinTicksAngle := AValue;
  220. if FMinTicksAngle < 10 then
  221. FMinTicksAngle := 10;
  222. if FMinTicksAngle > FMaxTicksAngle then
  223. FMinTicksAngle := FMaxTicksAngle;
  224. Invalidate;
  225. end;
  226. procedure TBCLeaSelector.SetSensitivity(AValue: integer);
  227. begin
  228. if FSensitivity = AValue then
  229. exit;
  230. if AValue <> 0 then
  231. FSensitivity := AValue
  232. else
  233. FSensitivity := 10;
  234. end;
  235. procedure TBCLeaSelector.SetLineBkgColor(AValue: TColor);
  236. begin
  237. if FLineBkgColor = AValue then
  238. Exit;
  239. FLineBkgColor := AValue;
  240. Invalidate;
  241. end;
  242. procedure TBCLeaSelector.SetLineColor(AValue: TColor);
  243. begin
  244. if FLineColor = AValue then
  245. Exit;
  246. FLineColor := AValue;
  247. Invalidate;
  248. end;
  249. procedure TBCLeaSelector.SetTextLayout(AValue: TTextLayout);
  250. begin
  251. if rTextLayout=AValue then Exit;
  252. rTextLayout:=AValue;
  253. Invalidate;
  254. end;
  255. procedure TBCLeaSelector.SetTicksCount(AValue: integer);
  256. begin
  257. if FTicksCount = AValue then
  258. exit;
  259. if FTicksCount < 2 then
  260. exit;
  261. FTicksCount := AValue;
  262. if FItems.Count < FTicksCount then
  263. begin
  264. while FItems.Count <= FTicksCount do
  265. FItems.Add('Item ' + IntToStr(FItems.Count + 1));
  266. end;
  267. Invalidate;
  268. end;
  269. procedure TBCLeaSelector.SetValue(AValue: integer);
  270. begin
  271. if FValue = AValue then
  272. exit;
  273. FValue := AValue;
  274. if FValue < 1 then
  275. FValue := 1;
  276. if FValue > FTicksCount then
  277. FValue := FTicksCount;
  278. Invalidate;
  279. end;
  280. procedure TBCLeaSelector.SetPointerSize(AValue: integer);
  281. begin
  282. if FPointerSize = AValue then
  283. exit;
  284. FPointerSize := AValue;
  285. if FPointerSize < 1 then
  286. FPointerSize := 1;
  287. if FPointerSize > 10 then
  288. FPointerSize := 10;
  289. Invalidate;
  290. end;
  291. procedure TBCLeaSelector.SetLineWidth(AValue: integer);
  292. begin
  293. if FLineWidth = AValue then exit;
  294. FLineWidth := AValue;
  295. if Visible then Redraw;
  296. end;
  297. procedure TBCLeaSelector.SetEnabled(Value: boolean);
  298. begin
  299. inherited SetEnabled(Value);
  300. Invalidate;
  301. end;
  302. procedure TBCLeaSelector.SetVisible(Value: boolean);
  303. begin
  304. inherited SetVisible(Value);
  305. Invalidate;
  306. end;
  307. procedure TBCLeaSelector.Paint;
  308. begin
  309. inherited Paint;
  310. Redraw;
  311. end;
  312. procedure TBCLeaSelector.Resize;
  313. begin
  314. inherited Resize;
  315. {$IFDEF LCLgtk2} Invalidate; {$ENDIF}
  316. end;
  317. procedure TBCLeaSelector.Redraw;
  318. const
  319. pi15 = pi * 1.5;
  320. var
  321. TextBmp: TBGRABitmap;
  322. TextStr: string;
  323. EffectiveSize: integer;
  324. EffectiveLineWidth: single;
  325. r: single;
  326. RMinAngle, RMaxAngle, RMinTicksAngle, RMaxTicksAngle, RAngle: single;
  327. Blur: TBGRABitmap;
  328. Mask, Mask2: TBGRABitmap;
  329. Phong: TPhongShading;
  330. ScaledPhongSize: int64;
  331. i: integer;
  332. TextSize: TSize;
  333. procedure DoDrawArc(a, b: single; c: TColor);
  334. begin
  335. FBitmap.Canvas2D.lineCapLCL := pecRound;
  336. FBitmap.Canvas2D.strokeStyle(c);
  337. FBitmap.Canvas2D.beginPath;
  338. FBitmap.Canvas2D.arc(0, 0, r, a, b, False);
  339. FBitmap.Canvas2D.stroke;
  340. end;
  341. procedure DoDrawTicks(a, b: single; c: TColor);
  342. begin
  343. FBitmap.Canvas2D.lineCapLCL := pecFlat;
  344. FBitmap.Canvas2D.strokeStyle(c);
  345. FBitmap.Canvas2D.beginPath;
  346. FBitmap.Canvas2D.arc(0, 0, r, a, b, False);
  347. FBitmap.Canvas2D.stroke;
  348. end;
  349. begin
  350. FBitmap.SetSize(Width, Height);
  351. FBitmap.Fill(FBkgColor);
  352. if Width < Height then
  353. EffectiveSize := Width
  354. else
  355. EffectiveSize := Height;
  356. if EffectiveSize < 2 then exit;
  357. FBitmap.Canvas2D.resetTransform;
  358. FBitmap.Canvas2D.translate((FBitmap.Width-1)/2, (FBitmap.Height-1)/2);
  359. FBitmap.Canvas2D.rotate(pi15);
  360. if FLineWidth = 0 then
  361. EffectiveLineWidth := EffectiveSize / 12
  362. else
  363. EffectiveLineWidth := FLineWidth;
  364. r := (EffectiveSize - EffectiveLineWidth) / 2;
  365. FBitmap.Canvas2D.lineWidth := EffectiveLineWidth;
  366. RMinAngle := (180 + FMinAngle) * pi / 180;
  367. RMaxAngle := ((180 + FMaxAngle) * pi / 180) - RMinAngle;
  368. RMinTicksAngle := (180 + FMinTicksAngle) * pi / 180;
  369. RMaxTicksAngle := ((180 + FMaxTicksAngle) * pi / 180) - RMinTicksAngle;
  370. // background line
  371. if FLineBkgColor <> clNone then
  372. DoDrawArc(RMinAngle, (RMaxAngle + RMinAngle), FLineBkgColor);
  373. if FDrawTicks then
  374. begin
  375. for i := 0 to FTicksCount - 1 do
  376. begin
  377. RAngle := (RMaxTicksAngle / (FTicksCount - 1)) * (i - ((FTicksCount - 1) / 2));
  378. DoDrawTicks(RAngle - FPointerSize / 200, RAngle + FPointerSize / 200, clBlack);
  379. end;
  380. end;
  381. RAngle := (RMaxTicksAngle / (FTicksCount - 1)) * (FValue - ((FTicksCount - 1) / 2));
  382. if Enabled then
  383. begin
  384. if FValue >= 0 then
  385. DoDrawArc(RAngle - FPointerSize / 100, RAngle + FPointerSize / 100, FLineColor);
  386. end
  387. else
  388. DoDrawArc(RAngle - FPointerSize / 100, RAngle + FPointerSize / 100, clGray);
  389. if FDrawText and FDrawTextPhong then
  390. begin
  391. //draw text before we apply phong
  392. if FItems.Count >= FValue then
  393. TextStr := FItems[FValue]
  394. else
  395. TextStr := 'NaN';
  396. TextBmp := TextShadow(FBitmap.Width, FBitmap.Height, TextStr, Font.Height,
  397. Font.Color, FontShadowColor, FontShadowOFfsetX,
  398. FontShadowOffsetY, FontShadowRadius, Font.Style, Font.Name) as TBGRABitmap;
  399. TextSize:= TextBmp.TextSize(TextStr);
  400. TextSize.cy:= TextSize.cy+FontShadowOffsetY; //+2*FontShadowRadius ?
  401. Case rTextLayout of
  402. tlTop: FBitmap.PutImage(0, -(HalfUp(((EffectiveSize-TextSize.cy) / 2))-Trunc(EffectiveLineWidth)),
  403. TextBmp, dmDrawWithTransparency);
  404. tlCenter: FBitmap.PutImage(0, 0, TextBmp, dmDrawWithTransparency);
  405. tlBottom: FBitmap.PutImage(0, +(HalfUp(((EffectiveSize-TextSize.cy) / 2))-Trunc(EffectiveLineWidth)),
  406. TextBmp, dmDrawWithTransparency);
  407. end;
  408. TextBmp.Free;
  409. end;
  410. if (FStyle = zsRaised) or (FStyle = zsLowered) then
  411. begin
  412. ScaledPhongSize := round(EffectiveLineWidth / 2);
  413. Mask := FBitmap.FilterGrayscale as TBGRABitmap;
  414. if FStyle = zsRaised then
  415. Mask.Negative;
  416. Blur := Mask.FilterBlurRadial(ScaledPhongSize, ScaledPhongSize, rbFast) as TBGRABitmap;
  417. Blur.FillMask(0, 0, Mask, BGRAPixelTransparent, dmSet);
  418. Mask.Free;
  419. Phong := TPhongShading.Create;
  420. begin
  421. Phong.AmbientFactor := FAmbientFactor;
  422. Phong.SpecularIndex := FSpecularIndex;
  423. Phong.LightDestFactor := FLightDestFactor;
  424. Phong.LightPosition := Point(FLightPositionX + (FBitmap.Width - EffectiveSize) div 2,
  425. FLightPositionY + (FBitmap.Height - EffectiveSize) div 2);
  426. Phong.LightPositionZ := FLightPositionZ;
  427. Phong.LightSourceIntensity := FLightSourceIntensity;
  428. Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
  429. Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
  430. Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
  431. Phong.SpecularFactor := FSpecularFactor;
  432. Phong.DiffusionFactor := FDiffusionFactor;
  433. Phong.DiffuseSaturation := FDiffuseSaturation;
  434. Phong.LightColor := FLightColor;
  435. end;
  436. Phong.Draw(FBitmap, Blur, FAltitude, 0, 0, FBitmap);
  437. Phong.Free;
  438. Blur.Free;
  439. //cut out phong-affected area outside the ring and fill with background color
  440. Mask := TBGRABitmap.Create(FBitmap.Width, FBitmap.Height, BGRABlack);
  441. Mask.FillEllipseAntialias((FBitmap.Width-1)/2, (FBitmap.Height-1)/2, EffectiveSize div 2, EffectiveSize div 2, BGRAWhite);
  442. Mask2 := TBGRABitmap.Create(FBitmap.Width, FBitmap.Height, ColorToBGRA(ColorToRGB(FBkgColor)));
  443. Mask2.PutImage(0, 0, FBitmap, dmSet);
  444. Mask2.ApplyMask(Mask);
  445. Mask.Free;
  446. FBitmap.Fill(FBkgColor);
  447. FBitmap.PutImage(0, 0, Mask2, dmDrawWithTransparency);
  448. Mask2.Free;
  449. end;
  450. if FDrawText and not FDrawTextPhong then
  451. begin
  452. if FItems.Count >= FValue then
  453. TextStr := FItems[FValue]
  454. else
  455. TextStr := 'NaN';
  456. TextBmp := TextShadow(FBitmap.Width, FBitmap.Height, TextStr, Font.Height,
  457. Font.Color, FontShadowColor, FontShadowOFfsetX,
  458. FontShadowOffsetY, FontShadowRadius, Font.Style, Font.Name) as TBGRABitmap;
  459. TextSize:= TextBmp.TextSize(TextStr);
  460. TextSize.cy:= TextSize.cy+FontShadowOffsetY; //+2*FontShadowRadius ?
  461. Case rTextLayout of
  462. tlTop: FBitmap.PutImage(0, -(HalfUp(((EffectiveSize-TextSize.cy) / 2))-Trunc(EffectiveLineWidth)),
  463. TextBmp, dmDrawWithTransparency);
  464. tlCenter: FBitmap.PutImage(0, 0, TextBmp, dmDrawWithTransparency);
  465. tlBottom: FBitmap.PutImage(0, +(HalfUp(((EffectiveSize-TextSize.cy) / 2))-Trunc(EffectiveLineWidth)),
  466. TextBmp, dmDrawWithTransparency);
  467. end;
  468. TextBmp.Free;
  469. end;
  470. FBitmap.Draw(Canvas, 0, 0, True);
  471. end;
  472. constructor TBCLeaSelector.Create(AOwner: TComponent);
  473. begin
  474. inherited Create(AOwner);
  475. with GetControlClassDefaultSize do
  476. SetInitialBounds(0, 0, 100, 100);
  477. TabStop:=True;
  478. FTicksCount := 3;
  479. FMinAngle := 20;
  480. FMaxAngle := 340;
  481. FMinTicksAngle := 150;
  482. FMaxTicksAngle := 210;
  483. FValue := 0;
  484. FDeltaPos := 0;
  485. FSensitivity := 10;
  486. FDrawText := True;
  487. rTextLayout:= tlCenter;
  488. FDrawTicks := False;
  489. ApplyDefaultTheme;
  490. FBitmap := TBGRABitmap.Create(Width, Height, FBkgColor);
  491. FItems := TStringList.Create;
  492. FItems.Add('Item 1');
  493. FItems.Add('Item 2');
  494. FItems.Add('Item 3');
  495. TStringList(FItems).OnChange := @ItemsChanged;
  496. Font.Color := clBlack;
  497. Font.Height := 20;
  498. end;
  499. destructor TBCLeaSelector.Destroy;
  500. begin
  501. FreeAndNil(FBitmap);
  502. TStringList(FItems).OnChange := nil;
  503. FreeAndNil(FItems);
  504. inherited Destroy;
  505. end;
  506. procedure TBCLeaSelector.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
  507. begin
  508. inherited MouseDown(Button, Shift, X, Y);
  509. if Button = mbLeft then
  510. begin
  511. FDeltaPos := ((ClientHeight / FSensitivity) - (Y / FSensitivity)) * ((FTicksCount - 1) / ClientHeight);
  512. FSettingVerticalPos := True;
  513. FVerticalPos := FValue;
  514. end;
  515. end;
  516. procedure TBCLeaSelector.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
  517. begin
  518. inherited MouseUp(Button, Shift, X, Y);
  519. if Button = mbLeft then
  520. FSettingVerticalPos := False;
  521. end;
  522. procedure TBCLeaSelector.MouseMove(Shift: TShiftState; X, Y: integer);
  523. begin
  524. inherited MouseMove(Shift, X, Y);
  525. if FSettingVerticalPos then
  526. UpdateVerticalPos(X, Y);
  527. end;
  528. procedure TBCLeaSelector.UpdateVerticalPos(X, Y: integer);
  529. var
  530. FPreviousPos: single;
  531. FCurrPos: single;
  532. begin
  533. FPreviousPos := FVerticalPos;
  534. FCurrPos := ((ClientHeight / FSensitivity) - (Y / FSensitivity)) * ((FTicksCount - 1) / ClientHeight);
  535. FVerticalPos := FVerticalPos - FDeltaPos + FCurrPos;
  536. if FVerticalPos < 0 then FVerticalPos := 0;
  537. if FVerticalPos > (FTicksCount - 1) then FVerticalPos := FTicksCount - 1;
  538. FValue := round(FVerticalPos);
  539. if FValue < 0 then
  540. FValue := 0;
  541. if FValue > (FTicksCount - 1) then
  542. FValue := FTicksCount - 1;
  543. Redraw;
  544. if (FPreviousPos <> FVerticalPos) and Assigned(FOnChangeValue) then
  545. FOnChangeValue(Self);
  546. end;
  547. procedure TBCLeaSelector.SetFFontShadowColor(AValue: TColor);
  548. begin
  549. if FFontShadowColor = AValue then
  550. Exit;
  551. FFontShadowColor := AValue;
  552. Invalidate;
  553. end;
  554. procedure TBCLeaSelector.SetDrawText(AValue: boolean);
  555. begin
  556. if FDrawText = AValue then Exit;
  557. FDrawText := AValue;
  558. Invalidate;
  559. end;
  560. procedure TBCLeaSelector.SetFFontShadowOffsetX(AValue: integer);
  561. begin
  562. if FFontShadowOffsetX = AValue then
  563. Exit;
  564. FFontShadowOffsetX := AValue;
  565. Invalidate;
  566. end;
  567. procedure TBCLeaSelector.SetFFontShadowOffsetY(AValue: integer);
  568. begin
  569. if FFontShadowOffsetY = AValue then
  570. Exit;
  571. FFontShadowOffsetY := AValue;
  572. Invalidate;
  573. end;
  574. procedure TBCLeaSelector.SetFFontShadowRadius(AValue: integer);
  575. begin
  576. if FFontSHadowRadius = AValue then
  577. Exit;
  578. FFontSHadowRadius := AValue;
  579. Invalidate;
  580. end;
  581. procedure TBCLeaSelector.SetAltitude(AValue: integer);
  582. begin
  583. if FAltitude = AValue then
  584. Exit;
  585. FAltitude := AValue;
  586. Invalidate;
  587. end;
  588. procedure TBCLeaSelector.SetBkgColor(AValue: TColor);
  589. begin
  590. if FBkgColor = AValue then
  591. Exit;
  592. FBkgColor := AValue;
  593. Invalidate;
  594. end;
  595. procedure TBCLeaSelector.SetDrawTicks(AValue: boolean);
  596. begin
  597. if FDrawTicks = AValue then
  598. Exit;
  599. FDrawTicks := AValue;
  600. Invalidate;
  601. end;
  602. procedure TBCLeaSelector.SetStyle(AValue: TZStyle);
  603. begin
  604. if FStyle = AValue then
  605. Exit;
  606. FStyle := AValue;
  607. Invalidate;
  608. end;
  609. procedure TBCLeaSelector.SetDrawTextPhong(AValue: boolean);
  610. begin
  611. if FDrawTextPhong = AValue then
  612. Exit;
  613. FDrawTextPhong := AValue;
  614. Invalidate;
  615. end;
  616. procedure TBCLeaSelector.SetItems(const Value: TStrings);
  617. var
  618. i: integer;
  619. begin
  620. FItems.Clear;
  621. for i := 0 to (FTicksCount - 1) do
  622. begin
  623. if i < Value.Count then
  624. FItems.Add(Value[i])
  625. else
  626. FItems.Add(' ');
  627. end;
  628. ItemsChanged(self);
  629. end;
  630. procedure TBCLeaSelector.ItemsChanged(Sender: TObject);
  631. begin
  632. Invalidate;
  633. if Assigned(FOnChangeValue) then FOnChangeValue(self);
  634. end;
  635. procedure TBCLeaSelector.SetTheme(AValue: TBCLeaTheme);
  636. begin
  637. if FTheme = AValue then
  638. Exit;
  639. if Assigned(FTheme) then
  640. FTheme := nil;
  641. FTheme := AValue;
  642. ApplyTheme;
  643. end;
  644. procedure TBCLeaSelector.UpdateTheme;
  645. begin
  646. if Assigned(FTheme) then
  647. begin
  648. FTheme.SEL_LineWidth := FLineWidth;
  649. FTheme.SEL_LineColor := FLineColor;
  650. FTheme.SEL_LineBkgColor := FLineBkgColor;
  651. FTheme.SEL_BkgColor := FBkgColor;
  652. FTheme.SEL_FontShadowColor := FFontShadowColor;
  653. FTheme.SEL_FontShadowOffsetX := FFontShadowOffsetX;
  654. FTheme.SEL_FontShadowOffsetY := FFontShadowOffsetY;
  655. FTheme.SEL_FontShadowRadius := FFontShadowRadius;
  656. FTheme.SEL_PointerSize := FPointerSize;
  657. FTheme.SEL_Style := FStyle;
  658. FTheme.SEL_DrawTextPhong := FDrawTextPhong;
  659. FTheme.SEL_Altitude := FAltitude;
  660. end;
  661. end;
  662. procedure TBCLeaSelector.ApplyTheme;
  663. begin
  664. if Assigned(FTheme) then
  665. begin
  666. FLineWidth := FTheme.SEL_LineWidth;
  667. FLineColor := FTheme.SEL_LineColor;
  668. FLineBkgColor := FTheme.SEL_LineBkgColor;
  669. FBkgColor := FTheme.SEL_BkgColor;
  670. FFontShadowColor := FTheme.SEL_FontShadowColor;
  671. FFontShadowOffsetX := FTheme.SEL_FontShadowOffsetX;
  672. FFontShadowOffsetY := FTheme.SEL_FontShadowOffsetY;
  673. FFontShadowRadius := FTheme.SEL_FontShadowRadius;
  674. FPointerSize := FTheme.SEL_PointerSize;
  675. FStyle := FTheme.SEL_Style;
  676. FDrawTextPhong := FTheme.SEL_DrawTextPhong;
  677. FAltitude := FTheme.SEL_Altitude;
  678. FLightSourceIntensity := FTheme.COM_LightSourceIntensity;
  679. FLightSourceDistanceTerm := FTheme.COM_LightSourceDistanceTerm;
  680. FLightSourceDistanceFactor := FTheme.COM_LightSourceDistanceFactor;
  681. FLightDestFactor := FTheme.COM_LightDestFactor;
  682. FLightColor := FTheme.COM_LightColor;
  683. FSpecularFactor := FTheme.COM_SpecularFactor;
  684. FSpecularIndex := FTheme.COM_SpecularIndex;
  685. FAmbientFactor := FTheme.COM_AmbientFactor;
  686. FDiffusionFactor := FTheme.COM_DiffusionFactor;
  687. FNegativeDiffusionFactor := FTheme.COM_NegativeDiffusionFactor;
  688. FDiffuseSaturation := FTheme.COM_DiffuseSaturation;
  689. FLightPositionX := FTheme.COM_LightPositionX;
  690. FLightPositionY := FTheme.COM_LightPositionY;
  691. FLightPositionZ := FTheme.COM_LightPositionZ;
  692. Invalidate;
  693. end
  694. else
  695. begin
  696. ApplyDefaultTheme;
  697. end;
  698. end;
  699. procedure TBCLeaSelector.SaveThemeToFile(AFileName: string);
  700. begin
  701. if Assigned(FTheme) then
  702. FTheme.SaveThemeToFile(AFileName);
  703. end;
  704. procedure TBCLeaSelector.LoadThemeFromFile(AFileName: string);
  705. begin
  706. if Assigned(FTheme) then
  707. FTheme.LoadThemeFromFile(AFileName);
  708. end;
  709. procedure TBCLeaSelector.ApplyDefaultTheme;
  710. begin
  711. FLineWidth := 8;
  712. FLineColor := TColor($009E5A00);
  713. FLineBkgColor := TColor($00D3D3D3);
  714. FBkgColor := clBtnFace;
  715. FFontShadowColor := clBlack;
  716. FFontShadowOffsetX := 2;
  717. FFontShadowOffsetY := 2;
  718. FFontShadowRadius := 4;
  719. FPointerSize := 3;
  720. FStyle := zsRaised;
  721. FDrawTextPhong := False;
  722. FAltitude := 2;
  723. FAmbientFactor := 0.3;
  724. FSpecularIndex := 10;
  725. FSpecularFactor := 0.6;
  726. FLightDestFactor := 1;
  727. FLightPositionX := -100;
  728. FLightPositionY := -100;
  729. FLightPositionZ := 100;
  730. FLightSourceIntensity := 500;
  731. FLightSourceDistanceTerm := 150;
  732. FLightSourceDistanceFactor := 1;
  733. FNegativeDiffusionFactor := 0.1;
  734. FLightColor := clWhite;
  735. FDiffuseSaturation := False;
  736. FDiffusionFactor := 0.9;
  737. end;
  738. end.