unit FMXTee.Editor.Animations;
{$I TeeDefs.inc}

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
  {$IFNDEF UPTOXE3}
  FMX.StdCtrls,
  {$ENDIF}
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,
  FMXTee.Engine, FMXTee.Chart, FMXTee.Animations.Tools, FMX.TabControl,
  FMX.Layouts, FMX.ListBox, FMX.Menus, FMXTee.Animate, FMXTee.Editor.Animation;

type
  TChartAnimationsEditor = class(TForm)
    LayoutAnims: TLayout;
    Panel1: TPanel;
    LBAnims: TListBox;
    Splitter1: TSplitter;
    PanelEditor: TLayout;
    Panel2: TPanel;
    Layout3: TLayout;
    Layout4: TLayout;
    TabControl1: TTabControl;
    Splitter2: TSplitter;
    TabOptions: TTabItem;
    TabAnimation: TTabItem;
    Panel3: TPanel;
    LBItems: TListBox;
    SBAddItem: TButton;
    BDeleteItem: TButton;
    BAdd: TButton;
    BDelete: TButton;
    BRename: TButton;
    TBFramesPerSecond: TTrackBar;
    LFramesPerSecond: TLabel;
    CBLoop: TCheckBox;
    CBSpeed: TComboBox;
    SBPlay: TButton;
    SBPause: TButton;
    SBStop: TButton;
    PopupMenu1: TPopupMenu;
    procedure BAddClick(Sender: TObject);
    procedure BDeleteClick(Sender: TObject);
    procedure BRenameClick(Sender: TObject);
    procedure LBAnimsChange(Sender: TObject);
    procedure SBPlayClick(Sender: TObject);
    procedure SBPauseClick(Sender: TObject);
    procedure SBStopClick(Sender: TObject);
    procedure SBAddItemClick(Sender: TObject);
    procedure BDeleteItemClick(Sender: TObject);
    procedure TBFramesPerSecondTracking(Sender: TObject);
    procedure CBLoopChange(Sender: TObject);
    procedure CBSpeedChange(Sender: TObject);
    procedure LBItemsChange(Sender: TObject);
  private
    { Private declarations }
    IOldAnimation : TTeeAnimationTool;
    IAnimEditor : TAnimationEditor;

    procedure ChangedAnimation(Sender: TObject);
    procedure CheckPlayButtons;
    procedure ClearOnChangeEvent;
    procedure FillAnimations;
    function NewAnimation:TTeeAnimationTool;
    procedure PopupSelected(Sender:TObject);
    function SelectedAnimation:TTeeAnimationTool;
    function SelectedItem:TTeeAnimation;
  protected
    OnAdded   : TNotifyEvent;
    OnDeleted : TNotifyEvent;
  public
    { Public declarations }
    Animations : TChartAnimations;

    procedure RefreshAnimations(const Value:TChartAnimations);
    Procedure Reload;
    procedure SelectAnimation(const Value:TTeeCustomAnimation);
    procedure SelectIfAny;

    class function CreateEditor(const AOwner:TComponent; const Anims:TChartAnimations):TChartAnimationsEditor;
    class procedure Edit(const AOwner:TComponent; const Animation:TTeeAnimationTool);
  end;

implementation

{$R *.fmx}

uses
  FMXTee.Editor.Stroke, FMXTee.Constants, FMXTee.Canvas,
  FMXTee.Procs;

{ TChartAnimationsEditor }

function TChartAnimationsEditor.NewAnimation:TTeeAnimationTool;
//var tmpGally : TTeeAnimationsGallery;
begin
  result:=nil;

  (*
  tmpGally:=TTeeAnimationsGallery.Create(Owner);
  try
    PositionToCenter(tmpGally);

    if tmpGally.ShowModal=mrOk then
       result:=tmpGally.AddNewAnimation(Animations);
  finally
    tmpGally.Free;
  end;
  *)
end;

procedure TChartAnimationsEditor.PopupSelected(Sender:TObject);
var tmp : TTeeAnimation;
    tmpClass : TTeeAnimationClass;
begin
  tmpClass:=TTeeAnimationClass(GetClass(TeeAnimationClasses[TMenuItem(Sender).Tag]));

  tmp:=tmpClass.Create(SelectedAnimation.Owner);
  tmp.Animate:=SelectedAnimation.Animate;

  if tmp is TCustomAnimationChart then
     TCustomAnimationChart(tmp).Chart:=SelectedAnimation.ParentChart
  else
     tmp.TagObject:=SelectedAnimation.ParentChart;

  LBItems.Items.AddObject(tmp.EditorName,tmp);
  LBItems.ItemIndex:=LBItems.Items.Count-1;
  LBItemsChange(Self);
end;

procedure TChartAnimationsEditor.BAddClick(Sender: TObject);
var tmpAnim : TTeeAnimationTool;
begin
  tmpAnim:=NewAnimation;

  if Assigned(tmpAnim) then
  begin
    LBAnims.Items.AddObject(tmpAnim.Description,tmpAnim);
    LBAnims.ItemIndex:=LBAnims.Items.Count-1;
    LBAnimsChange(Self);
  end;
end;

procedure TChartAnimationsEditor.SBAddItemClick(Sender: TObject);
var tmp : TMenuItem;
    t   : Integer;
    P   : TPointF;
    tmpClass : TTeeAnimationClass;
begin
  if PopupMenu1.ChildrenCount=0 then
  begin
    for t:=0 to TeeAnimationClasses.Count-1 do
    begin
      tmpClass:=TTeeAnimationClass(GetClass(TeeAnimationClasses[t]));

      if tmpClass.IsValidOwner(Animations.Owner) then
      begin
        tmp:=TMenuItem.Create(Self);
        tmp.Text:=TTeeAnimationClass(GetClass(TeeAnimationClasses[t])).Description;
        tmp.Tag:=t;
        tmp.OnClick:=PopupSelected;
        tmp.Parent:=PopupMenu1; // PopupMenu1.Items.Add(tmp);
      end;
    end;
  end;

  P.X:=SBAddItem.Position.X+SBAddItem.Width;
  P.Y:=SBAddItem.Position.Y+SBAddItem.Height;

//  P:=SBAddItem.ClientToScreen(P);
  PopupMenu1.Popup(P.X,P.Y);
end;

procedure TChartAnimationsEditor.SBPauseClick(Sender: TObject);
begin
  if SelectedAnimation.Paused then
     SelectedAnimation.Continue
  else
     SelectedAnimation.Pause;

  CheckPlayButtons;
end;

procedure TChartAnimationsEditor.SBPlayClick(Sender: TObject);
begin
  SelectedAnimation.Play;
  CheckPlayButtons;
end;

procedure TChartAnimationsEditor.SBStopClick(Sender: TObject);
begin
  SelectedAnimation.Stop;
  CheckPlayButtons;
end;

procedure TChartAnimationsEditor.BDeleteItemClick(Sender: TObject);
var tmp : Integer;
begin
  tmp:=LBItems.ItemIndex;

  if YesNo(Format(TeeMsg_SureToDelete,[LBItems.Items[tmp]])) then
  begin
    SelectedAnimation.Animations[tmp].Free;

    LBItems.Items.Delete(tmp);

    if tmp>LBItems.Items.Count-1 then
       LBItems.ItemIndex:=LBItems.Items.Count-1
    else
       LBItems.ItemIndex:=tmp;

    LBItemsChange(Self);
  end;
end;

procedure TChartAnimationsEditor.BDeleteClick(Sender: TObject);
var tmp : Integer;
begin
  tmp:=LBAnims.ItemIndex;

  if YesNo(Format(TeeMsg_SureToDelete,[LBAnims.Items[tmp]])) then
  begin
    SelectedAnimation.Free;

    LBAnims.Items.Delete(tmp);

    if tmp>LBAnims.Items.Count-1 then
       LBAnims.ItemIndex:=LBAnims.Items.Count-1
    else
       LBAnims.ItemIndex:=tmp;

    LBAnimsChange(Self);
  end;

  BDelete.Enabled:=LBAnims.ItemIndex<>-1;
  BRename.Enabled:=BDelete.Enabled;
end;

procedure TChartAnimationsEditor.BRenameClick(Sender: TObject);
var tmp : {$IFDEF FMI}WideString{$ELSE}String{$ENDIF};
begin
  tmp:=SelectedAnimation.Name;

  if InputQuery(TeeMsg_ChangeAnimationName,TeeMsg_NewAnimationName,tmp) then
  if tmp<>'' then
  begin
    SelectedAnimation.Name:=tmp;
    LBAnims.Items[LBAnims.ItemIndex]:=tmp;
  end;
end;

procedure TChartAnimationsEditor.CBLoopChange(Sender: TObject);
begin
  SelectedAnimation.Animate.Loop:=CBLoop.IsChecked;
end;

procedure TChartAnimationsEditor.CBSpeedChange(Sender: TObject);
var s : String;
begin
  s:=CBSpeed.Items[CBSpeed.ItemIndex];
  Delete(s,Length(s),1);
  SelectedAnimation.Animate.SpeedFactor:=StrToFloat(s);
end;

procedure TChartAnimationsEditor.RefreshAnimations(const Value:TChartAnimations);
begin
  if Assigned(Value) then
  begin
    Animations:=Value;
    FillAnimations;
    SelectIfAny;
  end;
end;

procedure TChartAnimationsEditor.Reload;
begin
  if Assigned(Animations) and Assigned(Animations.Owner) then
     if Animations.Count<>LBAnims.Items.Count then
     begin
       FillAnimations;
       SelectIfAny;
     end;

  if LBAnims.ItemIndex<>-1 then
     LBAnimsChange(Self);
end;

procedure TChartAnimationsEditor.SelectAnimation(const Value: TTeeCustomAnimation);
begin
  LBAnims.ItemIndex:=LBAnims.Items.IndexOfObject(Value);
  LBAnimsChange(Self);
end;

procedure TChartAnimationsEditor.SelectIfAny;
begin
  if Animations.Count>0 then
  begin
    LBAnims.ItemIndex:=0;
    LBAnimsChange(Self);
  end
  else
  begin
    PanelEditor.Visible:=True;
    PanelEditor.Visible:=False;
  end;
end;

class function TChartAnimationsEditor.CreateEditor(const AOwner: TComponent;
  const Anims: TChartAnimations): TChartAnimationsEditor;
begin
  result:=TChartAnimationsEditor.Create(AOwner);
  result.RefreshAnimations(Anims);
end;

class procedure TChartAnimationsEditor.Edit(const AOwner: TComponent;
  const Animation: TTeeAnimationTool);
var tmp : TChartAnimations;
begin
  tmp:=(Animation.ParentChart as TCustomChart).Animations;

  with TChartAnimationsEditor.CreateEditor(AOwner,tmp) do
  try
    LayoutAnims.Visible:=False;
    SelectAnimation(Animation);
    ShowModal;
  finally
    Free;
  end;
end;

procedure TChartAnimationsEditor.LBAnimsChange(Sender: TObject);
var t : Integer;
    tmpFPS : Integer;
begin
  ClearOnChangeEvent;

  PanelEditor.Visible:=False;
  PanelEditor.Visible:=LBAnims.ItemIndex<>-1;
  PanelEditor.Enabled:=PanelEditor.Visible;

  if IOldAnimation<>SelectedAnimation then
  begin
    if SelectedAnimation<>nil then
    begin
      LBItems.Clear;

      for t:=0 to SelectedAnimation.Animations.Count-1 do
          LBItems.Items.AddObject(SelectedAnimation.Animations[t].EditorName,SelectedAnimation.Animations[t]);

      if LBItems.Items.Count>0 then
         LBItems.ItemIndex:=0;

      LBItemsChange(Self);

      //Timer1.Enabled:=True;

      CheckPlayButtons;

      tmpFPS:=SelectedAnimation.Animate.Speed;

      while tmpFPS>TBFramesPerSecond.Max do
         TBFramesPerSecond.Max:=2*TBFramesPerSecond.Max;

      if TBFramesPerSecond.Max>120 then
         TBFramesPerSecond.Frequency:=Round(TBFramesPerSecond.Max) div 12;

      TBFramesPerSecond.Value:=tmpFPS;
      LFramesPerSecond.Text:=IntToStr(tmpFPS);

      CBLoop.IsChecked:=SelectedAnimation.Animate.Loop;

      CBSpeed.ItemIndex:=CBSpeed.Items.IndexOf(FloatToStr(SelectedAnimation.Animate.SpeedFactor)+'x');
    end;

    BDelete.Enabled:=PanelEditor.Enabled;
    BRename.Enabled:=BDelete.Enabled;

    IOldAnimation:=SelectedAnimation;
  end;
end;

type
  TFormClass=class of TCommonCustomForm;

procedure TChartAnimationsEditor.LBItemsChange(Sender: TObject);

  procedure AddEditor(const Animation:TTeeAnimation);
  var tmpFormClass : TFormClass;
      tmpForm      : TCommonCustomForm;
  begin
    tmpFormClass:=TFormClass(TeeGetClass(Animation.EditorClass));

    if Assigned(tmpFormClass) then
    begin
      tmpForm:=tmpFormClass.Create(Self);
      //tmpForm.Align:=alClient;
      TeeTranslateControl(tmpForm);
      tmpForm.TagObject:=Animation;
      EmbeddForm(tmpForm,TabOptions);
    end
    //else
     // InspectAnimation;
  end;

var tmpItem : TTeeAnimation;
begin
  ClearOnChangeEvent;

  TabControl1.Enabled:=LBItems.ItemIndex<>-1;

  RemoveControls(TabOptions);

  if LBItems.ItemIndex<>-1 then
  begin
    tmpItem:=SelectedItem;

    if tmpItem is TCustomAnimationChart then
    begin
      if TCustomAnimationChart(tmpItem).Chart=nil then
         TCustomAnimationChart(tmpItem).Chart:=SelectedAnimation.ParentChart
    end
    else
    if not Assigned(tmpItem.TagObject) then
       tmpItem.TagObject:=SelectedAnimation.ParentChart;

    if not Assigned(IAnimEditor) then
    begin
      IAnimEditor:=TAnimationEditor.Create(Self);
      //IAnimEditor.Align:=alClient;
      IAnimEditor.RefreshAnimation(tmpItem);
      EmbeddForm(IAnimEditor,TabAnimation);
    end
    else
      IAnimEditor.RefreshAnimation(tmpItem);

    AddEditor(tmpItem);

    if tmpItem is TPropertyAnimation then
       TPropertyAnimation(tmpItem).OnChange:=ChangedAnimation;
  end;

  BDeleteItem.Enabled:=LBItems.ItemIndex<>-1;
end;

procedure TChartAnimationsEditor.TBFramesPerSecondTracking(Sender: TObject);
begin
  SelectedAnimation.Animate.Speed:=Round(TBFramesPerSecond.Value);
  LFramesPerSecond.Text:=IntToStr(SelectedAnimation.Animate.Speed);
end;

procedure TChartAnimationsEditor.ChangedAnimation(Sender: TObject);
begin
  LBItems.Items[LBItems.ItemIndex]:=SelectedItem.EditorName;
end;

procedure TChartAnimationsEditor.CheckPlayButtons;
begin
  with SelectedAnimation do
  begin
    SBPlay.Enabled:=not Animate.Playing;
    SBPause.Enabled:=not Paused;
    SBStop.Enabled:=(not SBPlay.Enabled) or (not SBPause.Enabled);
    //SBFrame.Enabled:=Paused;
  end;
end;

procedure TChartAnimationsEditor.ClearOnChangeEvent;
var t : Integer;
    tmp : TTeeAnimation;
begin
  for t:=0 to LBItems.Items.Count-1 do
  begin
    tmp:=TTeeAnimation(LBItems.Items.Objects[t]);

    if tmp is TPropertyAnimation then
       TPropertyAnimation(tmp).OnChange:=nil;
  end;
end;

procedure TChartAnimationsEditor.FillAnimations;
var t : Integer;
    tmpS : String;
    tmp : TTeeCustomAnimation;
begin
  LBAnims.Clear;

  for t:=0 to Animations.Count-1 do
  begin
    tmp:=Animations[t];

    tmpS:=tmp.Name;
    if tmpS='' then
    begin
      tmpS:=tmp.Description;

      if tmpS='' then
         tmpS:=tmp.ClassName;
    end;

    LBAnims.Items.AddObject(tmpS,tmp);
  end;
end;

function TChartAnimationsEditor.SelectedAnimation: TTeeAnimationTool;
begin
  if LBAnims.ItemIndex=-1 then
     result:=nil
  else
     result:=TTeeAnimationTool(LBAnims.Items.Objects[LBAnims.ItemIndex]);
end;

function TChartAnimationsEditor.SelectedItem:TTeeAnimation;
begin
  if LBItems.ItemIndex=-1 then
     result:=nil
  else
     result:=TTeeAnimation(LBItems.Items.Objects[LBItems.ItemIndex]);
end;

end.
