{*********************************************}
{  TeeChart Charting Library for FireMonkey   }
{  Copyright (c) 2012-2020 by Steema Software }
{  All Rights Reserved                        }
{*********************************************}
unit FMXTee.Editor.Animation;
{$I TeeDefs.inc}

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
  FMX.StdCtrls, FMX.Layouts, FMXTee.Chart.GalleryPanel, FMX.ListBox, FMX.Edit,
  {$IFDEF D21}
  FMX.ComboTrackBar,
  {$ENDIF}
  FMX.TabControl, FMXTee.Animate;

type
  TAnimationEditor = class(TForm)
    TabControl1: TTabControl;
    TabOptions: TTabItem;
    TabTiming: TTabItem;
    Label1: TLabel;
    EDuration: TComboTrackBar;
    Label2: TLabel;
    Label3: TLabel;
    EStartTime: TComboTrackBar;
    Label4: TLabel;
    CBEnabled: TCheckBox;
    CBLoop: TCheckBox;
    Label5: TLabel;
    ETitle: TEdit;
    Panel1: TPanel;
    Label6: TLabel;
    CBTiming: TComboBox;
    Gallery: TChartGalleryPanel;
    CBTwoWay: TCheckBox;
    CBInverted: TCheckBox;
    CBEasing: TComboBox;
    Label7: TLabel;
    procedure CBTimingChange(Sender: TObject);
    procedure GalleryChangeChart(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure TabControl1Change(Sender: TObject);
    procedure EDurationChangeTracking(Sender: TObject);
    procedure EStartTimeChangeTracking(Sender: TObject);
    procedure CBEnabledChange(Sender: TObject);
    procedure CBLoopChange(Sender: TObject);
    procedure CBTwoWayChange(Sender: TObject);
    procedure CBInvertedChange(Sender: TObject);
    procedure CBEasingChange(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    Animation : TTeeAnimation;
    FOnChanged : TNotifyEvent;

    IPointerAnim : TTeeAnimation;

    procedure CreateTimingGallery;
    procedure DoChanged;
    procedure PointerAnimFrame(Sender: TTeeAnimation; const Fraction:Single);
  public
    { Public declarations }
    procedure RefreshAnimation(const AAnimation:TTeeAnimation);
    property OnChanged:TNotifyEvent read FOnChanged write FOnChanged;
  end;

implementation

{$R *.fmx}

uses
  FMXTee.Engine, FMXTee.Procs, FMXTee.Series;

procedure TAnimationEditor.CBEasingChange(Sender: TObject);
begin
  Animation.TimingStyle:=TAnimationTimingStyle(CBEasing.ItemIndex);

  IPointerAnim.TimingStyle:=Animation.TimingStyle;

  CreateTimingGallery;
end;

procedure TAnimationEditor.CBEnabledChange(Sender: TObject);
begin
  Animation.Enabled:=CBEnabled.IsChecked;
end;

procedure TAnimationEditor.CBInvertedChange(Sender: TObject);
begin
  Animation.Inverted:=CBInverted.IsChecked;
end;

procedure TAnimationEditor.CBLoopChange(Sender: TObject);
begin
  Animation.Loop:=CBLoop.IsChecked;
end;

procedure TAnimationEditor.CBTimingChange(Sender: TObject);
begin
  if Gallery.Charts.Count>0 then
  begin
    if Assigned(Gallery.SelectedChart) then
       Gallery.SelectedChart.Series[1].Visible:=False;

    Gallery.SelectedChart:=Gallery.Charts[CBTiming.ItemIndex];
  end
  else
     Animation.Timing:=TAnimationTiming(CBTiming.ItemIndex);
end;

procedure TAnimationEditor.CBTwoWayChange(Sender: TObject);
begin
  Animation.TwoWay:=CBTwoWay.IsChecked;
end;

procedure TAnimationEditor.EDurationChangeTracking(Sender: TObject);
begin
  if Assigned(Animation) then
  begin
    Animation.Duration:=StrToIntDef(EDuration.Text,Animation.Duration);
    DoChanged;
  end;
end;

procedure TAnimationEditor.FormCreate(Sender: TObject);
begin
  TabControl1.ActiveTab:=TabOptions;

  EDuration.Max:=1000000;
  EStartTime.Max:=1000000;
end;

procedure TAnimationEditor.FormDestroy(Sender: TObject);
begin
  IPointerAnim.Free;
end;

procedure TAnimationEditor.GalleryChangeChart(Sender: TObject);
begin
  if CBTiming.ItemIndex<>-1 then
     Gallery.Charts[CBTiming.ItemIndex].Series[1].Visible:=False;

  CBTiming.ItemIndex:=Gallery.Charts.IndexOf(Gallery.SelectedChart);
  Animation.Timing:=TAnimationTiming(CBTiming.ItemIndex);

  Gallery.SelectedChart[1].Visible:=True;

  if not IPointerAnim.Animate.Playing then
     IPointerAnim.Animate.Play;
end;

procedure TAnimationEditor.EStartTimeChangeTracking(Sender: TObject);
begin
  Animation.StartTime:=StrToIntDef(EStartTime.Text,Animation.StartTime);
  DoChanged;
end;

procedure TAnimationEditor.DoChanged;
begin
  if Assigned(FOnChanged) then
     FOnChanged(Animation);
end;

type
  TAnimationAccess=class(TTeeAnimation);

procedure TAnimationEditor.RefreshAnimation(const AAnimation: TTeeAnimation);
begin
  Animation:=AAnimation;

  if Assigned(Animation) then
  with Animation do
  begin
    EDuration.Text:=IntToStr(Duration);

    if Assigned(Parent) and TAnimationAccess(Parent).IsSequence then
       EStartTime.Enabled:=False;

    EStartTime.Text:=IntToStr(StartTime);
    CBTiming.ItemIndex:=Ord(Timing);

    CBEnabled.IsChecked:=Enabled;
    CBLoop.IsChecked:=Loop;
    CBTwoWay.IsChecked:=TwoWay;
    CBInverted.IsChecked:=Inverted;
  end;
end;

procedure TAnimationEditor.CreateTimingGallery;
var
  tmpAnim : TTeeAnimation;

  procedure CreateChart(const ATitle:String; ATiming:TAnimationTiming);
  var tmp : TGalleryChart;
      t   : Integer;
  begin
    tmp:=TGalleryChart.Create(Self);
    tmp.View3D:=False;
    tmp.Axes.Hide;
    tmp.Walls.Back.Show;

    tmp.AddSeries(TFastLineSeries);
    TFastLineSeries(tmp[0]).DrawStyle:=flAll;

    tmpAnim.Timing:=ATiming;

    for t:=0 to 100 do
        tmp[0].Add(tmpAnim.TimingFunction(t*0.01));

    tmp.Title.Caption:=ATitle;

    tmp.AddSeries(TPointSeries);
    tmp[1].AddXY(49,tmp[0].MandatoryValueList[49]);
    TPointSeries(tmp[1]).Pointer.Style:=psCircle;
    tmp[1].Visible:=False;

    tmp.Parent:=Gallery;
    Gallery.FinishAdd(tmp);
    Gallery.Charts.Add(tmp);
  end;

var t : Integer;
begin
  tmpAnim:=TTeeAnimation.Create(nil);
  try
    tmpAnim.TimingStyle:=TAnimationTimingStyle(CBEasing.ItemIndex);

    Gallery.FreeAllCharts;

    for t:=0 to CBTiming.Items.Count-1 do
        CreateChart(CBTiming.Items[t],TAnimationTiming(t));

    if not Assigned(IPointerAnim) then
    begin
      IPointerAnim:=TTeeAnimation.Create(nil);
      IPointerAnim.Animate.Loop:=True;
      IPointerAnim.StartTime:=500;
      IPointerAnim.OnFrame:=PointerAnimFrame;
    end;

  finally
    tmpAnim.Free;
  end;

  Gallery.ResizeCharts;

  Gallery.SelectedChart:=Gallery.Charts[CBTiming.ItemIndex];
end;

procedure TAnimationEditor.TabControl1Change(Sender: TObject);
begin
  if TabControl1.ActiveTab=TabTiming then
  begin
    if Gallery.Charts.Count=0 then
        CreateTimingGallery
    else
    if Assigned(IPointerAnim) then
       IPointerAnim.Animate.Continue;
  end
  else
  if Assigned(IPointerAnim) then
     IPointerAnim.Animate.Pause;
end;

procedure TAnimationEditor.PointerAnimFrame(Sender: TTeeAnimation; const Fraction:Single);
var tmpX : Integer;
    tmpChart : TCustomAxisPanel;
begin
  tmpChart:=Gallery.SelectedChart;

  tmpX:=Round(Fraction*100);

  if tmpChart[1].XValue[0]<>tmpX then
  begin
    tmpChart[1].XValue[0]:=tmpX;
    tmpChart[1].YValue[0]:=tmpChart[0].YValues[tmpX];
  end;
end;

initialization
  RegisterClass(TAnimationEditor);
end.
