djjd47130

TSmoothMove Delphi Component

Aug 6th, 2016
229
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Delphi 7.21 KB | None | 0 0
  1. unit JD.SmoothMove;
  2.  
  3. (*
  4.   JD Smooth Move Component (TSmoothMove)
  5.  
  6.   Designed for animation of values to provide a sliding effect of UI controls.
  7.   Can be used for other purposes. Used as a VCL alternative for the
  8.   Float Animations as found in the Firemonkey framework.
  9.  
  10.   This component is event driven. Be sure to assign a handler for the
  11.   OnValue event. This will be triggered for every change of the value.
  12.   Use this handler to update the position or otherwise value of whatever
  13.   this component is supposed to control.
  14. *)
  15.  
  16. interface
  17.  
  18. uses
  19.   System.SysUtils, System.Classes;
  20.  
  21. type
  22.   TSmoothMoveEffect = (seNone, seNormal, seSmooth);
  23.  
  24.   TSmoothMoveEvent = procedure(Sender: TObject; const Position: Double) of object;
  25.  
  26. const
  27.   SM_DEF_DELAY = 15;
  28.   SM_DEF_VALUE = 100.0;
  29.   SM_DEF_STEP = 15.0;
  30.   SM_DEF_EFFECT = seNormal;
  31.   SM_DEF_ENABLED = True;
  32.  
  33. type
  34.   TSmoothMoveThread = class;
  35.   TSmoothMove = class;
  36.  
  37.   TSmoothMoveThread = class(TThread)
  38.   private
  39.     FDelay: Integer;
  40.     FOnValue: TNotifyEvent;
  41.     procedure SetDelay(const Value: Integer);
  42.     procedure DoOnValue;
  43.   protected
  44.     procedure Execute; override;
  45.   public
  46.     constructor Create; reintroduce;
  47.     destructor Destroy; override;
  48.   public
  49.     property Delay: Integer read FDelay write SetDelay;
  50.   public
  51.     property OnValue: TNotifyEvent read FOnValue write FOnValue;
  52.   end;
  53.  
  54.   TSmoothMove = class(TComponent)
  55.   private
  56.     FThread: TSmoothMoveThread;
  57.     FInvalidated: Boolean;
  58.     FEnabled: Boolean;
  59.     FValue: Double;
  60.     FPosition: Double;
  61.     FOnValue: TSmoothMoveEvent;
  62.     FStep: Double;
  63.     FEffect: TSmoothMoveEffect;
  64.     procedure TimerExec(Sender: TObject);
  65.     procedure SetValue(const Value: Double);
  66.     function GetDelay: Integer;
  67.     procedure SetDelay(const Value: Integer);
  68.     procedure SetStep(const Value: Double);
  69.     function GetEnabled: Boolean;
  70.     procedure SetEnabled(const Value: Boolean);
  71.     procedure SetEffect(const Value: TSmoothMoveEffect);
  72.   protected
  73.     procedure DoOnValue; virtual;
  74.   public
  75.     constructor Create(AOwner: TComponent); override;
  76.     destructor Destroy; override;
  77.   public
  78.  
  79.     ///<summary>
  80.     ///  Returns the current position.
  81.     ///</summary>
  82.     property Position: Double read FPosition;
  83.  
  84.     ///<summary>
  85.     ///  Forcefully sets the current position to the desired value.
  86.     ///</summary>
  87.     procedure Reset;
  88.  
  89.   published
  90.  
  91.     ///<summary>
  92.     ///  Controls the amount of time between each modification of the position.
  93.     ///</summary>
  94.     property Delay: Integer read GetDelay write SetDelay default SM_DEF_DELAY;
  95.  
  96.     ///<summary>
  97.     ///  Controls the type of animation effect.
  98.     ///</summary>
  99.     property Effect: TSmoothMoveEffect read FEffect write SetEffect default SM_DEF_EFFECT;
  100.  
  101.     ///<summary>
  102.     ///  Controls whether to enable the animation.
  103.     ///</summary>
  104.     property Enabled: Boolean read GetEnabled write SetEnabled default SM_DEF_ENABLED;
  105.  
  106.     ///<summary>
  107.     ///  Controls how much to modify the position on each modification.
  108.     ///</summary>
  109.     property Step: Double read FStep write SetStep;
  110.  
  111.     ///<summary>
  112.     ///  Specifies the desired target value.
  113.     ///</summary>
  114.     property Value: Double read FValue write SetValue;
  115.  
  116.   published
  117.  
  118.     ///<summary>
  119.     ///  Triggered upon each modification of the current position.
  120.     ///</summary>
  121.     property OnValue: TSmoothMoveEvent read FOnValue write FOnValue;
  122.  
  123.   end;
  124.  
  125. implementation
  126.  
  127. { TSmoothMoveThread }
  128.  
  129. constructor TSmoothMoveThread.Create;
  130. begin
  131.   inherited Create(False);
  132.   FDelay:= 100;
  133. end;
  134.  
  135. destructor TSmoothMoveThread.Destroy;
  136. begin
  137.  
  138.   inherited;
  139. end;
  140.  
  141. procedure TSmoothMoveThread.DoOnValue;
  142. begin
  143.   if Assigned(FOnValue) then
  144.     FOnValue(Self);
  145. end;
  146.  
  147. procedure TSmoothMoveThread.Execute;
  148. begin
  149.   while not Terminated do begin
  150.     try
  151.       Synchronize(DoOnValue);
  152.     finally
  153.       Sleep(FDelay);
  154.     end;
  155.   end;
  156. end;
  157.  
  158. procedure TSmoothMoveThread.SetDelay(const Value: Integer);
  159. begin
  160.   if Value < 1 then
  161.     FDelay:= 1
  162.   else
  163.     FDelay := Value;
  164. end;
  165.  
  166. { TSmoothMove }
  167.  
  168. constructor TSmoothMove.Create(AOwner: TComponent);
  169. begin
  170.   inherited;
  171.   FThread:= TSmoothMoveThread.Create;
  172.   FThread.OnValue:= TimerExec;
  173.   FThread.Delay:= SM_DEF_DELAY;
  174.   FStep:= SM_DEF_STEP;
  175.   FValue:= SM_DEF_VALUE;
  176.   FPosition:= SM_DEF_VALUE;
  177.   FEffect:= SM_DEF_EFFECT;
  178.   FEnabled:= SM_DEF_ENABLED;
  179.   FInvalidated:= True;
  180. end;
  181.  
  182. destructor TSmoothMove.Destroy;
  183. begin
  184.   FThread.Terminate;
  185.   FThread.WaitFor;
  186.   FThread.Free;
  187.   inherited;
  188. end;
  189.  
  190. procedure TSmoothMove.DoOnValue;
  191. begin
  192.   if Assigned(FOnValue) then
  193.     FOnValue(Self, FPosition);
  194. end;
  195.  
  196. function TSmoothMove.GetDelay: Integer;
  197. begin
  198.   Result:= FThread.Delay;
  199. end;
  200.  
  201. function TSmoothMove.GetEnabled: Boolean;
  202. begin
  203.   Result:= FEnabled;
  204. end;
  205.  
  206. procedure TSmoothMove.Reset;
  207. begin
  208.   FPosition:= FValue;
  209.   FInvalidated:= False;
  210.   DoOnValue;
  211. end;
  212.  
  213. procedure TSmoothMove.SetDelay(const Value: Integer);
  214. begin
  215.   FThread.Delay:= Value;
  216.   FInvalidated:= True;
  217. end;
  218.  
  219. procedure TSmoothMove.SetEffect(const Value: TSmoothMoveEffect);
  220. begin
  221.   FEffect := Value;
  222. end;
  223.  
  224. procedure TSmoothMove.SetEnabled(const Value: Boolean);
  225. begin
  226.   FEnabled:= Value;
  227.   FInvalidated:= True;
  228. end;
  229.  
  230. procedure TSmoothMove.SetStep(const Value: Double);
  231. begin
  232.   FStep := Value;
  233.   FInvalidated:= True;
  234. end;
  235.  
  236. procedure TSmoothMove.SetValue(const Value: Double);
  237. begin
  238.   FValue := Value;
  239.   FInvalidated:= True;
  240. end;
  241.  
  242. procedure TSmoothMove.TimerExec(Sender: TObject);
  243. var
  244.   TempStep: Double;
  245.   Dist: Double;
  246. begin
  247.   if not FEnabled then Exit;
  248.  
  249.   if FInvalidated then begin
  250.  
  251.     case FEffect of
  252.       seNone: begin
  253.         //No animation, just change value
  254.         FPosition:= FValue;
  255.         FInvalidated:= False;
  256.       end;
  257.       seNormal: begin
  258.         //Evenly increase/decrease value
  259.         if (FPosition >= FValue - FStep) and (FPosition <= FValue + FStep) then begin
  260.           FPosition:= FValue;
  261.           FInvalidated:= False;
  262.         end;
  263.         if FPosition > Value then begin
  264.           FPosition:= FPosition - FStep;
  265.         end else
  266.         if FPosition < Value then begin
  267.           FPosition:= FPosition + FStep;
  268.         end;
  269.       end;
  270.       seSmooth: begin
  271.         //Slow down and snap into place
  272.  
  273.         //TODO: Modify calculation to be more efficient and smooth
  274.  
  275.         if FPosition > FValue then
  276.           Dist:= FPosition - FValue
  277.         else
  278.           Dist:= FValue - FPosition;
  279.  
  280.         if Dist < (FStep * 2) then begin
  281.           TempStep:= FStep / 6;
  282.         end else
  283.         if Dist < (FStep * 4) then begin
  284.           TempStep:= FStep / 4;
  285.         end else
  286.         if Dist < (FStep * 6) then begin
  287.           TempStep:= FStep / 2;
  288.         end else begin
  289.           TempStep:= FStep;
  290.         end;
  291.  
  292.         if (FPosition >= FValue - TempStep) and (FPosition <= FValue + TempStep) then begin
  293.           FPosition:= FValue;
  294.           FInvalidated:= False;
  295.         end;
  296.         if FPosition > Value then begin
  297.           FPosition:= FPosition - TempStep;
  298.         end else
  299.         if FPosition < Value then begin
  300.           FPosition:= FPosition + TempStep;
  301.         end;
  302.  
  303.       end;
  304.     end;
  305.  
  306.     DoOnValue;
  307.   end;
  308. end;
  309.  
  310. end.
Advertisement
Add Comment
Please, Sign In to add comment