bcfluentprogressring.pas 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. {
  2. 2024 by hedgehog
  3. }
  4. unit BCFluentProgressRing;
  5. {$mode ObjFPC}{$H+}
  6. interface
  7. uses
  8. Classes, SysUtils, Controls, Graphics, ExtCtrls,
  9. BGRAGraphicControl, BGRABitmapTypes;
  10. type
  11. { TBCFluentProgressRing }
  12. TBCFluentProgressRing = class(TBGRAGraphicControl)
  13. private
  14. FPeriod: Int64;
  15. FIndeterminate: boolean;
  16. FStartTickCount: QWord;
  17. FAnimationTime: Int64;
  18. FTimer: TTimer;
  19. FMaxValue: integer;
  20. FMinValue: integer;
  21. FValue: integer;
  22. FLineColor: TColor;
  23. FLineBkgColor: TColor;
  24. FLineWidth: integer;
  25. procedure SetIndeterminate(AValue: boolean);
  26. procedure SetLineBkgColor(AValue: TColor);
  27. procedure SetLineColor(AValue: TColor);
  28. procedure SetMaxValue(AValue: integer);
  29. procedure SetMinValue(AValue: integer);
  30. procedure SetValue(AValue: integer);
  31. procedure SetLineWidth(AValue: integer);
  32. protected
  33. procedure SetEnabled(Value: Boolean); override;
  34. procedure SetVisible(Value: Boolean); override;
  35. procedure RedrawBitmapContent; override;
  36. procedure TimerEvent({%H-}Sender: TObject);
  37. procedure TimerStart({%H-}Sender: TObject);
  38. public
  39. constructor Create(AOwner: TComponent); override;
  40. published
  41. property MinValue: integer read FMinValue write SetMinValue default 0;
  42. property MaxValue: integer read FMaxValue write SetMaxValue default 100;
  43. property Value: integer read FValue write SetValue default 0;
  44. property LineColor: TColor read FLineColor write SetLineColor default
  45. TColor($009E5A00);
  46. property LineBkgColor: TColor read FLineBkgColor write SetLineBkgColor default
  47. TColor($00D3D3D3);
  48. property LineWidth: integer read FLineWidth write SetLineWidth default 0;
  49. property Indeterminate: boolean read FIndeterminate write SetIndeterminate default false;
  50. end;
  51. procedure Register;
  52. implementation
  53. uses Math;
  54. procedure Register;
  55. begin
  56. RegisterComponents('BGRA Controls', [TBCFluentProgressRing]);
  57. end;
  58. { TBCFluentProgressRing }
  59. procedure TBCFluentProgressRing.SetMaxValue(AValue: integer);
  60. begin
  61. if FMaxValue = AValue then
  62. exit;
  63. FMaxValue := AValue;
  64. if FValue > FMaxValue then
  65. FValue := FMaxValue;
  66. if FMinValue > FMaxValue then
  67. FMinValue := FMaxValue;
  68. DiscardBitmap;
  69. end;
  70. procedure TBCFluentProgressRing.SetLineBkgColor(AValue: TColor);
  71. begin
  72. if FLineBkgColor = AValue then
  73. Exit;
  74. FLineBkgColor := AValue;
  75. DiscardBitmap;
  76. end;
  77. procedure TBCFluentProgressRing.SetIndeterminate(AValue: boolean);
  78. begin
  79. if FIndeterminate=AValue then Exit;
  80. FIndeterminate:=AValue;
  81. if Enabled and Visible then
  82. begin
  83. FTimer.Enabled:= FIndeterminate;
  84. DiscardBitmap;
  85. end;
  86. end;
  87. procedure TBCFluentProgressRing.SetLineColor(AValue: TColor);
  88. begin
  89. if FLineColor = AValue then
  90. Exit;
  91. FLineColor := AValue;
  92. DiscardBitmap;
  93. end;
  94. procedure TBCFluentProgressRing.SetMinValue(AValue: integer);
  95. begin
  96. if FMinValue = AValue then
  97. exit;
  98. FMinValue := AValue;
  99. if FValue < FMinValue then
  100. FValue := FMinValue;
  101. if FMaxValue < FMinValue then
  102. FMaxValue := FMinValue;
  103. DiscardBitmap;
  104. end;
  105. procedure TBCFluentProgressRing.SetValue(AValue: integer);
  106. begin
  107. if FValue = AValue then
  108. exit;
  109. FValue := AValue;
  110. if FValue < FMinValue then
  111. FValue := FMinValue;
  112. if FValue > FMaxValue then
  113. FValue := FMaxValue;
  114. DiscardBitmap;
  115. end;
  116. procedure TBCFluentProgressRing.SetLineWidth(AValue: integer);
  117. begin
  118. if FLineWidth = AValue then exit;
  119. FLineWidth := AValue;
  120. if Visible then DiscardBitmap;
  121. end;
  122. procedure TBCFluentProgressRing.SetEnabled(Value: Boolean);
  123. begin
  124. inherited SetEnabled(Value);
  125. FTimer.Enabled := Value and Visible and FIndeterminate;
  126. DiscardBitmap;
  127. end;
  128. procedure TBCFluentProgressRing.SetVisible(Value: Boolean);
  129. begin
  130. inherited SetVisible(Value);
  131. FTimer.Enabled := Enabled and Value and FIndeterminate;
  132. DiscardBitmap;
  133. end;
  134. procedure TBCFluentProgressRing.RedrawBitmapContent;
  135. const
  136. pi2= 2*pi;
  137. pi15 = pi*1.5;
  138. var
  139. EffectiveSize: integer;
  140. EffectiveLineWidth: single;
  141. a, da, r: single;
  142. procedure DoDrawArc(a, b: single; c: TColor);
  143. begin
  144. Bitmap.Canvas2D.strokeStyle(c);
  145. Bitmap.Canvas2D.beginPath;
  146. Bitmap.Canvas2D.arc(0, 0, r, a, b, false);
  147. Bitmap.Canvas2D.stroke;
  148. end;
  149. begin
  150. if Width< Height then
  151. EffectiveSize:= Width
  152. else
  153. EffectiveSize:= Height;
  154. if EffectiveSize<2 then exit;
  155. Bitmap.FillTransparent;
  156. Bitmap.Canvas2D.resetTransform;
  157. Bitmap.Canvas2D.translate(Bitmap.Width/2, Bitmap.Height/2);
  158. Bitmap.Canvas2D.rotate(pi15);
  159. if FLineWidth=0 then
  160. EffectiveLineWidth:=EffectiveSize / 12
  161. else
  162. EffectiveLineWidth:= FLineWidth;
  163. r:= (EffectiveSize -EffectiveLineWidth)/2;
  164. Bitmap.Canvas2D.lineWidth:= EffectiveLineWidth;
  165. // background line
  166. if (FValue < FMaxValue) and (FLineBkgColor<>clNone) then
  167. DoDrawArc(0, pi2, FLineBkgColor);
  168. Bitmap.Canvas2D.lineCapLCL:= pecRound;
  169. if FIndeterminate and FTimer.Enabled then
  170. begin
  171. FAnimationTime:= (GetTickCount64 - FStartTickCount) mod FPeriod;
  172. a:= 3*FAnimationTime*pi2/FPeriod - pi;
  173. da:= max(2*abs(1 - 2*FAnimationTime/FPeriod), 0.01);
  174. DoDrawArc(a-da, a+da, FLineColor);
  175. end
  176. else if FValue > FMinValue then
  177. begin
  178. if Enabled then
  179. DoDrawArc(0, pi2 * FValue / FMaxValue, FLineColor)
  180. else
  181. DoDrawArc(0, pi2 * FValue / FMaxValue, clGray);
  182. end;
  183. end;
  184. procedure TBCFluentProgressRing.TimerEvent(Sender: TObject);
  185. begin
  186. DiscardBitmap;
  187. end;
  188. procedure TBCFluentProgressRing.TimerStart(Sender: TObject);
  189. begin
  190. FStartTickCount:= GetTickCount64;
  191. FAnimationTime:=0;
  192. end;
  193. constructor TBCFluentProgressRing.Create(AOwner: TComponent);
  194. begin
  195. inherited Create(AOwner);
  196. FPeriod:= 2400;
  197. FTimer:= TTimer.Create(self);
  198. FTimer.Interval := 15;
  199. FTimer.Enabled := false;
  200. FTimer.OnTimer := @TimerEvent;
  201. FTimer.OnStartTimer:= @TimerStart;
  202. with GetControlClassDefaultSize do
  203. SetInitialBounds(0, 0, 100, 100);
  204. FMaxValue := 100;
  205. FMinValue := 0;
  206. FValue := 0;
  207. FLineWidth:=0;
  208. FLineColor := TColor($009E5A00);
  209. FLineBkgColor := TColor($00D3D3D3);
  210. end;
  211. end.