unit FMXTee.Editor.Functions.Gallery;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Layouts, FMX.ListBox,
  FMX.TabControl, FMXTee.Engine, FMXTee.Procs, FMXTee.Chart,
  FMXTee.Editor.EditorPanel, FMX.Edit, FMX.Objects, FMXTee.Chart.Functions;

type
  TFunctionsGallery = class(TForm)
    Panel1: TPanel;
    LBFuncs: TListBox;
    Splitter1: TSplitter;
    Chart1: TChart;
    CBGroup: TComboBox;
    ListBoxItem1: TListBoxItem;
    ChartEditor1: TChartEditor;
    Button1: TButton;
    TBData: TTrackBar;
    Text1: TText;
    CBPeriod: TComboTrackBar;
    Text2: TText;
    PanelBottom: TPanel;
    PanelButtons: TPanel;
    Button2: TButton;
    Button3: TButton;
    Text3: TText;
    procedure FormCreate(Sender: TObject);
    procedure LBFuncsChange(Sender: TObject);
    procedure CBGroupChange(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure TBDataChange(Sender: TObject);
    procedure CBPeriodTyping(Sender: TObject);
    procedure CBPeriodChange(Sender: TObject);
    procedure CBPeriodChangeTracking(Sender: TObject);
  private
    { Private declarations }
    procedure AddDemo(AClass:TTeeFunctionClass);
    procedure AddFunctions(const AGroup:String);
    procedure AddGroups;
    function CurrentFunction:TTeeFunction;
    procedure YCalculate(Sender:TCustomTeeFunction; const x:Double; var y:Double);
  public
    { Public declarations }
  end;

implementation

{$R *.fmx}

uses
  Math, FMXTee.Series, FMXTee.Functions.Stats, FMXTee.Series.OHLC,
  FMXTee.Series.Candle, FMXTee.Series.Spline;

type
  TFunctionAccess=class(TTeeFunction);

procedure TFunctionsGallery.AddDemo(AClass: TTeeFunctionClass);

  function FinancialIndicator:Boolean;
  begin
    result:=(AClass=TACFunction) or (AClass=TADXFunction) or
            (AClass=TAlligatorFunction) or (AClass=TATRFunction) or
            (AClass=TAOFunction) or (AClass=TBollingerFunction) or
            (AClass=TCLVFunction) or (AClass=TCCIFunction) or
            (AClass=TCompressFunction) or (AClass=TGatorFunction) or
            (AClass=TMoneyFlowFunction) or (AClass=TOBVFunction) or
            (AClass=TRSIFunction) or (AClass=TRVIFunction) or
            (AClass=TSARFunction);
  end;

  function SplitVertical:Boolean;
  begin
    result:=(AClass=TACFunction) or (AClass=TADXFunction) or
            (AClass=TATRFunction) or (AClass=TAOFunction) or
            (AClass=TCLVFunction) or (AClass=TCCIFunction) or
            (AClass=TGatorFunction) or (AClass=TMACDFunction) or
            (AClass=TMoneyFlowFunction) or (AClass=TOBVFunction) or
            (AClass=TMomentumFunction) or (AClass=TMomentumDivFunction) or
            (AClass=TPercentChangeFunction) or (AClass=TRVIFunction) or
            (AClass=TPerformanceFunction) or (AClass=TRSIFunction) or
            (AClass=TSlopeFunction);
  end;

  function SourceSeries:TChartSeriesClass;
  begin
    if FinancialIndicator then
       result:=TCandleSeries
    else
       result:=TFastLineSeries
  end;

  function DestSeries:TChartSeries;
  begin
    if AClass=TCrossPointsFunction then
       result:=TPointSeries.Create(Self)
    else
    if AClass=TCompressFunction then
       result:=TCandleSeries.Create(Self)
    else
    if AClass=TACFunction then
       result:=TVolumeSeries.Create(Self)
    else
       result:=TFastLineSeries.Create(Self);

    if AClass=TCompressFunction then
    begin
      result.VertAxis:=aRightAxis;
      Chart1.Axes.Left.EndPosition:=50;
      Chart1.Axes.Right.StartPosition:=50;
    end
    else
    if SplitVertical then
    begin
      result.VertAxis:=aRightAxis;
      Chart1.Axes.Left.EndPosition:=70;
      Chart1.Axes.Right.StartPosition:=70;
    end
    else
    begin
      Chart1.Axes.Left.EndPosition:=100;
      Chart1.Axes.Right.StartPosition:=0;
    end;
  end;

var f : TTeeFunction;
    data : Integer;
begin
  Chart1.FreeAllSeries;

  f:=AClass.Create(Self);

  if (AClass=TMovingAverageFunction) or
     (AClass=TSmoothedMovAvgFunction) or
     (AClass=TRSIFunction) then
        f.Period:=10;

  TBData.Enabled:=(AClass<>TSmoothingFunction);

  CBPeriod.Enabled:=TFunctionAccess(f).CanUsePeriod;

  if CBPeriod.Visible then
     CBPeriod.Value:=f.Period;

  if AClass=TSmoothingFunction then
     data:=15
  else
     data:=Round(TBData.Value);

  if AClass=TCustomTeeFunction then
  begin
    Chart1.Legend.Hide;

    Chart1.Title.Caption:='y = Sqr(Sin(x) + Cos(x))';
    Chart1.AddSeries(DestSeries);
    Chart1[0].FunctionType:=f;
    TCustomTeeFunction(f).NumPoints:=data;
    TCustomTeeFunction(f).OnCalculate:=YCalculate;
    f.ReCalculate;
  end
  else
  begin
    Chart1.Legend.Show;

    Chart1.AddSeries(SourceSeries).FillSampleValues(data);
    Chart1[0].Title:='Data';

    if AClass=TCrossPointsFunction then
    begin
      Chart1.AddSeries(SourceSeries).FillSampleValues(data);
      Chart1[1].Title:='Data 2';
      Chart1[0].Title:='Data 1';
    end
    else
    if (AClass=TMoneyFlowFunction) or (AClass=TOBVFunction) then
       Chart1.AddSeries(TVolumeSeries).FillSampleValues(data);

    Chart1.AddSeries(DestSeries);
    Chart1.SeriesList.Last.Title:='Function';

    if AClass=TCrossPointsFunction then
    begin
      Chart1[2].FunctionType:=f;
      Chart1[2].DataSources.Add(Chart1[0]);
      Chart1[2].DataSources.Add(Chart1[1]);
    end
    else
    if AClass=TMoneyFlowFunction then
    begin
      TMoneyFlowFunction(f).Volume:=Chart1[1];
      Chart1[2].FunctionType:=f;
      Chart1[2].DataSource:=Chart1[0];
    end
    else
    if AClass=TOBVFunction then
    begin
      TOBVFunction(f).Volume:=Chart1[1];
      Chart1[2].FunctionType:=f;
      Chart1[2].DataSource:=Chart1[0];
    end
    else
    begin
      Chart1[1].FunctionType:=f;
      Chart1[1].DataSource:=Chart1[0];
    end;
  end;
end;

procedure TFunctionsGallery.AddFunctions(const AGroup:String);

  procedure AddItem(AClass:TTeeFunctionClass; const ADesc:String);
  var i : TListBoxItem;
  begin
    i:=TListBoxItem.Create(Self);
    i.Text:=ADesc;
    i.Data:=TObject(AClass);
    LBFuncs.AddObject(i);
  end;

var t : Integer;
    s : TStringList;
begin
  s:=TStringList.Create;
  try
    for t := 0 to TeeSeriesTypes.Count-1 do
    if Assigned(TeeSeriesTypes[t].FunctionClass) then
       if (AGroup='') or (AGroup=TeeSeriesTypes[t].GalleryPage^) then
          s.AddObject(TeeSeriesTypes[t].Caption, TObject(t));

    s.Sort;

    LBFuncs.Clear;

    for t := 0 to s.Count-1 do
        AddItem(TeeSeriesTypes[Integer(s.Objects[t])].FunctionClass, s[t]);
  finally
    s.Free;
  end;
end;

procedure TFunctionsGallery.AddGroups;
var t : Integer;
    s : String;
    i : TListBoxItem;
begin
  for t := 0 to TeeSeriesTypes.Count-1 do
  if Assigned(TeeSeriesTypes[t].FunctionClass) then
  begin
    s:=TeeSeriesTypes[t].GalleryPage^;

    if CBGroup.Items.IndexOf(s)=-1 then
    begin
      i:=TListBoxItem.Create(Self);
      i.Text:=s;
      i.Parent:=CBGroup;
    end;
  end;
end;

procedure TFunctionsGallery.Button1Click(Sender: TObject);
begin
  ChartEditor1.Execute;
end;

procedure TFunctionsGallery.CBGroupChange(Sender: TObject);
begin
  if CBGroup.ItemIndex=0 then
     AddFunctions('')
  else
     AddFunctions(CBGroup.Items[CBGroup.ItemIndex]);

  if LBFuncs.Count>0 then
     LBFuncs.ItemIndex:=0;
end;

procedure TFunctionsGallery.CBPeriodChange(Sender: TObject);
begin
  CBPeriodTyping(Self);
end;

procedure TFunctionsGallery.CBPeriodChangeTracking(Sender: TObject);
begin
  CBPeriodTyping(Self);
end;

function TFunctionsGallery.CurrentFunction:TTeeFunction;
var t : Integer;
begin
  result:=nil;

  for t := 0 to Chart1.SeriesCount-1 do
  if Assigned(Chart1[t].FunctionType) then
  begin
    result:=Chart1[t].FunctionType;
    break;
  end;
end;

procedure TFunctionsGallery.CBPeriodTyping(Sender: TObject);
var tmp : TTeeFunction;
begin
  tmp:=CurrentFunction;

  if Assigned(tmp) then
     tmp.Period:=CBPeriod.Value;
end;

procedure TFunctionsGallery.FormCreate(Sender: TObject);
begin
  AddGroups;
  CBGroup.ItemIndex:=0;
  CBGroupChange(Self);
end;

procedure TFunctionsGallery.LBFuncsChange(Sender: TObject);
begin
  if LBFuncs.ItemIndex<>-1 then
  begin
    Chart1.Title.Caption:=LBFuncs.ListItems[LBFuncs.ItemIndex].Text;
    AddDemo(TTeeFunctionClass(LBFuncs.ListItems[LBFuncs.ItemIndex].Data));

    CBPeriod.Value:=CurrentFunction.Period;
  end;
end;

procedure TFunctionsGallery.TBDataChange(Sender: TObject);
var t : Integer;
begin
  if CurrentFunction is TCustomTeeFunction then
  begin
    (CurrentFunction as TCustomTeeFunction).NumPoints:=Round(TBData.Value);
    CurrentFunction.ReCalculate;
  end
  else
  for t := 0 to Chart1.SeriesCount-2 do
      Chart1[t].FillSampleValues(Round(TBData.Value));
end;

procedure TFunctionsGallery.YCalculate(Sender: TCustomTeeFunction;
  const x: Double; var y: Double);
var Angle : Double;
begin
  Angle:=DegToRad(x);
  y:=Sqr(Sin(Angle) + Cos(Angle));
end;

end.
