superspinnercommon.pas 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. // SPDX-License-Identifier: LGPL-3.0-linking-exception
  2. {
  3. Part of BGRA Controls. Made by third party.
  4. For detailed information see readme.txt
  5. Site: https://sourceforge.net/p/bgra-controls/
  6. Wiki: http://wiki.lazarus.freepascal.org/BGRAControls
  7. Forum: http://forum.lazarus.freepascal.org/index.php/board,46.0.html
  8. }
  9. {******************************* CONTRIBUTOR(S) ******************************
  10. - Sandy Ganz | [email protected]
  11. Evolved from BGRAKnob and SuperGauge, changed style to be more inline with
  12. SuperGauge settings and related. Mostly support classes
  13. ***************************** END CONTRIBUTOR(S) *****************************}
  14. unit SuperSpinnerCommon;
  15. {$I bgracontrols.inc}
  16. interface
  17. uses
  18. Classes, SysUtils, {$IFDEF FPC}LResources,{$ELSE}Types, {$ENDIF} Forms, Controls, Graphics, Dialogs,
  19. BGRABitmap, BGRABitmapTypes, BGRAGradients;
  20. type
  21. TSSPositionStyle = (psNone, psFilledCircle, psHollowCircle, psShaded, psIndentCircle, psLines);
  22. TSSStyle = (ssFlat, ssShaded, ssPhong);
  23. TSSCapStyle = (csNone, csFlat, csShaded, csPhong, csOutline);
  24. TSSDirection = (sdCW, sdCCW);
  25. { TSSOrigin }
  26. TSSOrigin = packed record
  27. CenterPoint: TPoint;
  28. Radius: integer;
  29. end;
  30. { TSSFrameSettings }
  31. TSSFrameSettings = class(TPersistent)
  32. private
  33. FBorderColor: TColor;
  34. FBorderWidth: integer;
  35. FOnChange: TNotifyEvent;
  36. FDirty: boolean;
  37. procedure SetBorderWidth(AValue: integer);
  38. procedure SetBorderColor(AValue: TColor);
  39. procedure SetOnChange(AValue: TNotifyEvent);
  40. procedure DirtyOnChange;
  41. protected
  42. public
  43. constructor Create;
  44. destructor Destroy; override;
  45. property OnChange: TNotifyEvent read FOnChange write SetOnChange;
  46. property Dirty: boolean read FDirty write FDirty;
  47. published
  48. property BorderWidth: integer read FBorderWidth write SetBorderWidth default 5;
  49. property BorderColor: TColor read FBorderColor write SetBorderColor default clGray;
  50. end;
  51. { TSSPositionSettings }
  52. TSSPositionSettings = class(TPersistent)
  53. private
  54. FEdgeColor: TColor;
  55. FEdgeThickness: integer;
  56. FFillColor: TColor;
  57. FStyle:TSSPositionStyle;
  58. FMargin: integer;
  59. FCenterMargin: integer;
  60. FLineWidth: integer; // total width of position
  61. FLineCount: integer; // Number of lines to be draw
  62. FRadius: integer;
  63. FOpacity: byte;
  64. FDirty: boolean;
  65. FOnChange: TNotifyEvent;
  66. procedure SetEdgeColor(AValue: TColor);
  67. procedure SetEdgeThickness(AValue: integer);
  68. procedure SetColor(AValue: TColor);
  69. procedure SetStyle(const AValue: TSSPositionStyle);
  70. procedure SetMargin(const AValue: integer);
  71. procedure SetCenterMargin(const AValue: integer);
  72. procedure SetLineWidth(const AValue: integer);
  73. procedure SetLineCount(const AValue: integer);
  74. procedure SetRadius(const AValue: integer);
  75. procedure SetOpacity(const AValue: byte);
  76. procedure SetOnChange(AValue: TNotifyEvent);
  77. procedure DirtyOnChange;
  78. protected
  79. public
  80. property Dirty: boolean read FDirty write FDirty;
  81. constructor Create;
  82. destructor Destroy; override;
  83. property OnChange: TNotifyEvent read FOnChange write SetOnChange;
  84. published
  85. property FillColor: TColor read FFillColor write SetColor default clBlack;
  86. property Style: TSSPositionStyle read FStyle write SetStyle default psLines;
  87. property Margin: integer read FMargin write SetMargin default 15;
  88. property CenterMargin: integer read FCenterMargin write SetCenterMargin default 20;
  89. property LineWidth: integer read FLineWidth write SetLineWidth default 4;
  90. property LineCount: integer read FLineCount write SetLineCount default 10;
  91. property Radius: integer read FRadius write SetRadius default 20;
  92. property Opacity: byte read FOpacity write SetOpacity default 192;
  93. property EdgeColor: TColor read FEdgeColor write SetEdgeColor default clGray;
  94. property EdgeThickness: integer read FEdgeThickness write SetEdgeThickness default 2;
  95. end;
  96. { TSSCapSettings }
  97. TSSCapSettings = class(TPersistent)
  98. private
  99. FEdgeColor: TColor;
  100. FEdgeThickness: integer;
  101. FFillColor: TColor;
  102. FOnChange: TNotifyEvent;
  103. FRadius: integer;
  104. FCurveExponent: single;
  105. FStyle: TSSCapStyle;
  106. FDirty: boolean;
  107. procedure SetEdgeColor(AValue: TColor);
  108. procedure SetEdgeThickness(AValue: integer);
  109. procedure SetFillColor(AValue: TColor);
  110. procedure SetOnChange(AValue: TNotifyEvent);
  111. procedure SetRadius(AValue: integer);
  112. procedure SetLightIntensity(const AValue: integer);
  113. function GetLightIntensity: integer;
  114. procedure SetCurveExponent(const AValue: single);
  115. procedure SetStyle(const AValue: TSSCapStyle);
  116. procedure DirtyOnChange;
  117. protected
  118. public
  119. FPhong: TPhongShading;
  120. property Dirty: boolean read FDirty write FDirty;
  121. constructor Create;
  122. destructor Destroy; override;
  123. property OnChange: TNotifyEvent read FOnChange write SetOnChange;
  124. published
  125. property EdgeColor: TColor read FEdgeColor write SetEdgeColor default clGray;
  126. property FillColor: TColor read FFillColor write SetFillColor default clWhite;
  127. property Radius: integer read FRadius write SetRadius default 20;
  128. property EdgeThickness: integer read FEdgeThickness write SetEdgeThickness default 2;
  129. property LightIntensity: integer read GetLightIntensity write SetLightIntensity default 300;
  130. property CurveExponent: single read FCurveExponent write SetCurveExponent default 0.05;
  131. property Style: TSSCapStyle read FStyle write SetStyle default csPhong;
  132. end;
  133. { TSSKnobSettings }
  134. TSSKnobSettings = class(TPersistent)
  135. private
  136. FEdgeColor: TColor;
  137. FEdgeThickness: integer;
  138. FFillColor: TColor;
  139. FOnChange: TNotifyEvent;
  140. FCurveExponent: single;
  141. FStyle: TSSStyle;
  142. FDirty: boolean;
  143. procedure SetEdgeColor(AValue: TColor);
  144. procedure SetEdgeThickness(AValue: integer);
  145. procedure SetFillColor(AValue: TColor);
  146. procedure SetOnChange(AValue: TNotifyEvent);
  147. procedure SetLightIntensity(const AValue: integer);
  148. function GetLightIntensity: integer;
  149. procedure SetCurveExponent(const AValue: single);
  150. procedure SetStyle(const AValue: TSSStyle);
  151. procedure DirtyOnChange;
  152. protected
  153. public
  154. FPhong: TPhongShading;
  155. property Dirty: boolean read FDirty write FDirty;
  156. constructor Create;
  157. destructor Destroy; override;
  158. property OnChange: TNotifyEvent read FOnChange write SetOnChange;
  159. published
  160. property EdgeColor: TColor read FEdgeColor write SetEdgeColor default clMedGray;
  161. property FillColor: TColor read FFillColor write SetFillColor default clWhite;
  162. property EdgeThickness: integer read FEdgeThickness write SetEdgeThickness default 2;
  163. property LightIntensity: integer read GetLightIntensity write SetLightIntensity default 300;
  164. property CurveExponent: single read FCurveExponent write SetCurveExponent default 0.05;
  165. property Style: TSSStyle read FStyle write SetStyle default ssPhong;
  166. end;
  167. function Initializebitmap(var Bitmap: TBGRABitmap; Width, Height: integer): TSSOrigin;
  168. implementation
  169. // Helper for all bitmap setup
  170. function Initializebitmap(var Bitmap: TBGRABitmap; Width, Height: integer): TSSOrigin;
  171. begin
  172. Bitmap.SetSize(Width, Height);
  173. // Clear bitmap to transparent
  174. BitMap.Fill(BGRA(0, 0, 0, 0));
  175. // Get origin information
  176. Result.CenterPoint.x := Width div 2;
  177. Result.CenterPoint.y := Height div 2;
  178. // Take the smallest so radius will always fit
  179. if Result.CenterPoint.x < Result.CenterPoint.y then
  180. Result.Radius := Result.CenterPoint.x
  181. else
  182. Result.Radius := Result.CenterPoint.y;
  183. end;
  184. { TSSFrameSettings }
  185. constructor TSSFrameSettings.Create;
  186. begin
  187. FBorderColor := clGray;
  188. FBorderWidth := 5;
  189. FDirty := True;
  190. end;
  191. destructor TSSFrameSettings.Destroy;
  192. begin
  193. inherited Destroy;
  194. end;
  195. procedure TSSFrameSettings.SetBorderWidth(AValue: integer);
  196. begin
  197. if (FBorderWidth = AValue) or (AValue < 0) then
  198. Exit;
  199. FBorderWidth := AValue;
  200. DirtyOnChange;
  201. end;
  202. procedure TSSFrameSettings.SetBorderColor(AValue: TColor);
  203. begin
  204. if FBorderColor = AValue then
  205. Exit;
  206. FBorderColor := AValue;
  207. DirtyOnChange;
  208. end;
  209. procedure TSSFrameSettings.SetOnChange(AValue: TNotifyEvent);
  210. begin
  211. FOnChange := AValue;
  212. if Assigned(FOnChange) then
  213. FOnChange(Self);
  214. end;
  215. procedure TSSFrameSettings.DirtyOnChange;
  216. begin
  217. FDirty := True; // if we get here a prop must have changed, mark dirty
  218. if Assigned(FOnChange) then
  219. FOnChange(Self);
  220. end;
  221. { TSSPositionSettings }
  222. constructor TSSPositionSettings.Create;
  223. begin
  224. FOpacity := 192;
  225. FStyle := psLines;
  226. FEdgeColor := clGray;
  227. FFillColor := clBlack;
  228. FMargin := 15;
  229. FCenterMargin := 40;
  230. FLineWidth := 4;
  231. FLineCount := 10;
  232. FRadius := 20;
  233. FEdgeThickness := 2;
  234. FDirty := True;
  235. end;
  236. destructor TSSPositionSettings.Destroy;
  237. begin
  238. inherited Destroy;
  239. end;
  240. procedure TSSPositionSettings.SetStyle(const AValue: TSSPositionStyle);
  241. begin
  242. if FStyle = AValue then
  243. Exit;
  244. FStyle := AValue;
  245. DirtyOnChange;
  246. end;
  247. procedure TSSPositionSettings.SetOpacity(const AValue: byte);
  248. begin
  249. if FOpacity = AValue then
  250. Exit;
  251. FOpacity := AValue;
  252. DirtyOnChange;
  253. end;
  254. procedure TSSPositionSettings.SetEdgeColor(AValue: TColor);
  255. begin
  256. if FEdgeColor = AValue then
  257. Exit;
  258. FEdgeColor := AValue;
  259. DirtyOnChange;
  260. end;
  261. procedure TSSPositionSettings.SetEdgeThickness(AValue: integer);
  262. begin
  263. if (FEdgeThickness = AValue) or (AValue < 0) then
  264. Exit;
  265. FEdgeThickness := AValue;
  266. DirtyOnChange;
  267. end;
  268. procedure TSSPositionSettings.SetColor(AValue: TColor);
  269. begin
  270. if FFillColor = AValue then
  271. Exit;
  272. FFillColor := AValue;
  273. DirtyOnChange;
  274. end;
  275. procedure TSSPositionSettings.SetOnChange(AValue: TNotifyEvent);
  276. begin
  277. FOnChange := AValue;
  278. // no dirty needed possibly, call directly
  279. if Assigned(FOnChange) then
  280. FOnChange(Self);
  281. end;
  282. // Diameter of the the spinner circle, ignored for lines
  283. procedure TSSPositionSettings.SetRadius(const AValue: integer);
  284. begin
  285. if FRadius = AValue then
  286. Exit;
  287. FRadius := AValue;
  288. DirtyOnChange;
  289. end;
  290. // Line width for hollow circle, and lines types. Ignored for others
  291. procedure TSSPositionSettings.SetLineWidth(const AValue: integer);
  292. begin
  293. if FLineWidth = AValue then
  294. Exit;
  295. FLineWidth := AValue;
  296. DirtyOnChange;
  297. end;
  298. // Line count, for lines, Ignored for others
  299. procedure TSSPositionSettings.SetLineCount(const AValue: integer);
  300. begin
  301. if FLineCount = AValue then
  302. Exit;
  303. FLineCount := AValue;
  304. DirtyOnChange;
  305. end;
  306. // Offset from the edge of the knob
  307. procedure TSSPositionSettings.SetMargin(const AValue: integer);
  308. begin
  309. if FMargin = AValue then
  310. Exit;
  311. FMargin := AValue;
  312. DirtyOnChange;
  313. end;
  314. // Offset from the center of the knob
  315. procedure TSSPositionSettings.SetCenterMargin(const AValue: integer);
  316. begin
  317. if FCenterMargin = AValue then
  318. Exit;
  319. FCenterMargin := AValue;
  320. DirtyOnChange;
  321. end;
  322. procedure TSSPositionSettings.DirtyOnChange;
  323. begin
  324. FDirty := True; // if we get here some props must have changed, mark dirty
  325. if Assigned(FOnChange) then
  326. FOnChange(Self);
  327. end;
  328. { TSSSpinnerCapSettings }
  329. constructor TSSCapSettings.Create;
  330. begin
  331. // create a phong shader, will need to delete on clean up
  332. FPhong := TPhongShading.Create;
  333. FPhong.LightPositionZ := 100;
  334. FPhong.LightSourceIntensity := 300;
  335. FPhong.NegativeDiffusionFactor := 0.8;
  336. FPhong.AmbientFactor := 0.5;
  337. FPhong.DiffusionFactor := 0.6;
  338. FCurveExponent := 0.05;
  339. FStyle := csPhong;
  340. FEdgeColor := clGray;
  341. FFillColor := clWhite;
  342. FRadius := 20;
  343. FEdgeThickness := 2;
  344. FDirty := True;
  345. end;
  346. destructor TSSCapSettings.Destroy;
  347. begin
  348. FPhong.Free;
  349. inherited Destroy;
  350. end;
  351. procedure TSSCapSettings.SetStyle(const AValue: TSSCapStyle);
  352. begin
  353. if FStyle = AValue then
  354. Exit;
  355. FStyle := AValue;
  356. DirtyOnChange;
  357. end;
  358. procedure TSSCapSettings.SetLightIntensity(const AValue: integer);
  359. begin
  360. if AValue = FPhong.LightSourceIntensity then
  361. Exit;
  362. FPhong.LightSourceIntensity := AValue;
  363. DirtyOnChange;
  364. end;
  365. function TSSCapSettings.GetLightIntensity: integer;
  366. begin
  367. Result := round(FPhong.LightSourceIntensity);
  368. end;
  369. procedure TSSCapSettings.SetCurveExponent(const AValue: single);
  370. begin
  371. if FCurveExponent = AValue then
  372. Exit;
  373. FCurveExponent := AValue;
  374. DirtyOnChange;
  375. end;
  376. procedure TSSCapSettings.SetEdgeColor(AValue: TColor);
  377. begin
  378. if FEdgeColor = AValue then
  379. Exit;
  380. FEdgeColor := AValue;
  381. DirtyOnChange;
  382. end;
  383. procedure TSSCapSettings.SetEdgeThickness(AValue: integer);
  384. begin
  385. if (FEdgeThickness = AValue) or (AValue < 0) then
  386. Exit;
  387. FEdgeThickness := AValue;
  388. DirtyOnChange;
  389. end;
  390. procedure TSSCapSettings.SetFillColor(AValue: TColor);
  391. begin
  392. if FFillColor = AValue then
  393. Exit;
  394. FFillColor := AValue;
  395. DirtyOnChange;
  396. end;
  397. procedure TSSCapSettings.SetOnChange(AValue: TNotifyEvent);
  398. begin
  399. FOnChange := AValue;
  400. // no dirty needed possibly, call directly
  401. if Assigned(FOnChange) then
  402. FOnChange(Self);
  403. end;
  404. procedure TSSCapSettings.SetRadius(AValue: integer);
  405. begin
  406. if FRadius = AValue then
  407. Exit;
  408. FRadius := AValue;
  409. DirtyOnChange;
  410. end;
  411. procedure TSSCapSettings.DirtyOnChange;
  412. begin
  413. FDirty := True; // if we get here some props must have changed, mark dirty
  414. if Assigned(FOnChange) then
  415. FOnChange(Self);
  416. end;
  417. { TSSKnobSettings }
  418. constructor TSSKnobSettings.Create;
  419. begin
  420. // create a phong shader, will need to delete on clean up
  421. FPhong := TPhongShading.Create;
  422. FPhong.LightPositionZ := 100;
  423. FPhong.LightSourceIntensity := 300;
  424. FPhong.NegativeDiffusionFactor := 0.8;
  425. FPhong.AmbientFactor := 0.5;
  426. FPhong.DiffusionFactor := 0.6;
  427. FCurveExponent := 0.2;
  428. FStyle := ssPhong;
  429. FEdgeColor := clMedGray;
  430. FFillColor := clWhite;
  431. FEdgeThickness := 2;
  432. FDirty := True;
  433. end;
  434. destructor TSSKnobSettings.Destroy;
  435. begin
  436. FPhong.Free;
  437. inherited Destroy;
  438. end;
  439. procedure TSSKnobSettings.SetStyle(const AValue: TSSStyle);
  440. begin
  441. if FStyle = AValue then
  442. Exit;
  443. FStyle := AValue;
  444. DirtyOnChange;
  445. end;
  446. procedure TSSKnobSettings.SetLightIntensity(const AValue: integer);
  447. begin
  448. if AValue = FPhong.LightSourceIntensity then
  449. Exit;
  450. FPhong.LightSourceIntensity := AValue;
  451. DirtyOnChange;
  452. end;
  453. function TSSKnobSettings.GetLightIntensity: integer;
  454. begin
  455. Result := round(FPhong.LightSourceIntensity);
  456. end;
  457. procedure TSSKnobSettings.SetCurveExponent(const AValue: single);
  458. begin
  459. if FCurveExponent = AValue then
  460. Exit;
  461. FCurveExponent := AValue;
  462. DirtyOnChange;
  463. end;
  464. procedure TSSKnobSettings.SetEdgeColor(AValue: TColor);
  465. begin
  466. if FEdgeColor = AValue then
  467. Exit;
  468. FEdgeColor := AValue;
  469. DirtyOnChange;
  470. end;
  471. procedure TSSKnobSettings.SetEdgeThickness(AValue: integer);
  472. begin
  473. if (FEdgeThickness = AValue) or (AValue < 0) then
  474. Exit;
  475. FEdgeThickness := AValue;
  476. DirtyOnChange;
  477. end;
  478. procedure TSSKnobSettings.SetFillColor(AValue: TColor);
  479. begin
  480. if FFillColor = AValue then
  481. Exit;
  482. FFillColor := AValue;
  483. DirtyOnChange;
  484. end;
  485. procedure TSSKnobSettings.SetOnChange(AValue: TNotifyEvent);
  486. begin
  487. FOnChange := AValue;
  488. // no dirty needed possibly, call directly
  489. if Assigned(FOnChange) then
  490. FOnChange(Self);
  491. end;
  492. procedure TSSKnobSettings.DirtyOnChange;
  493. begin
  494. FDirty := True; // if we get here some props must have changed, mark dirty
  495. if Assigned(FOnChange) then
  496. FOnChange(Self);
  497. end;
  498. end.