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

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  System.Generics.Collections, 
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Layouts, FMX.ListBox,
  {$IFNDEF UPTOXE3}
  FMX.StdCtrls,
  {$ENDIF}
  FMX.TabControl, FMXTee.Engine, FMXTee.Procs, FMXTee.Chart,
  FMX.Objects, FMXTee.Chart.Functions, FMX.Edit;

type
  TFunctionsGallery = class(TForm)
    Panel1: TPanel;
    LBFuncs: TListBox;
    Splitter1: TSplitter;
    ChartFunctions: TChart;
    CBGroup: TComboBox;
    ListBoxItem1: TListBoxItem;
    TBData: TTrackBar;
    Text1: TText;
    Text2: TText;
    PanelBottom: TPanel;
    PanelButtons: TPanel;
    Button2: TButton;
    Button3: TButton;
    Text3: TText;
    TBPeriod: TTrackBar;
    LPeriod: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure LBFuncsChange(Sender: TObject);
    procedure CBGroupChange(Sender: TObject);
    procedure TBDataChange(Sender: TObject);
    procedure TBPeriodChange(Sender: TObject);
    procedure ChartFunctionsClickTitle(Sender: TCustomChart;
      ATitle: TChartTitle; Button: TMouseButton; Shift: TShiftState; X,
      Y: Integer);
  private
    { Private declarations }
    procedure AddFunctionDemo(const AType: TTeeSeriesType);
    procedure AddFunctions(const AGroup:String);
    procedure AddGroups;
    procedure AddSampleData(const AFunction:TTeeFunction; const ASeries:TChartSeries; ANum:Integer);
    function CurrentFunction:TTeeFunction;
  public
    { Public declarations }
    function SelectedFunction:TTeeSeriesType;
    function SelectedFunctionClass:TTeeFunctionClass;
  end;

implementation

{$R *.fmx}

uses
  Math, FMXTee.Series, FMXTee.Constants, FMXTee.Editor.Chart;

type
  TFunctionAccess=class(TTeeFunction);

procedure TFunctionsGallery.AddFunctionDemo(const AType: TTeeSeriesType);
var f : TTeeFunction;
    data : Integer;
    SourceSeries : TChartSeriesClass;
    tmpHasSource : Boolean;
    tmpAxes : TChartAxes;
    tmpDest : TFastLineSeries;
begin
  ChartFunctions.FreeAllSeries;

  f:=AType.FunctionClass.Create(Self);

  data:=Round(TBData.Value);

  SourceSeries:=TFunctionAccess(f).GallerySource;

  tmpHasSource:=Assigned(SourceSeries);

  if not tmpHasSource then
     SourceSeries:=TFastLineSeries;

  AddSampleData(f,ChartFunctions.AddSeries(SourceSeries),Data);

  if ChartFunctions[0] is TFastLineSeries then
     TFastLineSeries(ChartFunctions[0]).DrawStyle:=flAll;

  ChartFunctions.Legend.Show;

  tmpAxes:=ChartFunctions.Axes;

  tmpAxes.Left.EndPosition:=100;
  tmpAxes.Right.StartPosition:=0;

  // Reset chart axes properties that might have changed by previous functions:

  tmpAxes.Automatic:=True;

  tmpAxes.Right.AxisValuesFormat:=TeeMsg_DefValueFormat;
  tmpAxes.Left.Title.Caption:='';
  tmpAxes.Right.Title.Caption:='';
  tmpAxes.Bottom.Title.Caption:='';
  tmpAxes.Left.Title.Angle:=90;

  // Function Series destination:
  tmpDest:=TFastLineSeries(ChartFunctions.AddSeries(TFastLineSeries));

  tmpDest.Pen.Width:=2;
  tmpDest.DrawStyle:=flAll;

  TFunctionAccess(f).PrepareForGallery(ChartFunctions);

  if not Assigned(f.ParentSeries) then
  begin
    ChartFunctions.AddSeries(TFastLineSeries).Pen.Width:=2;
    //tmp:=ChartFunctions.SeriesCount-1;
    ChartFunctions[1].FunctionType:=f;
    ChartFunctions[1].DataSource:=ChartFunctions[0];
  end;

  f.ParentSeries.GetVertAxis.Grid.Hide;

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

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

  f.ParentSeries.Title:=AType.Caption;
end;

procedure TFunctionsGallery.AddSampleData(const AFunction:TTeeFunction; const ASeries:TChartSeries; ANum:Integer);
var tmp : Double;
    t   : Integer;
begin
  // Special case for Multiply function.
  // Add very small sample values to avoid multiplication to crash (Floating point Overflow)
  if AFunction is TMultiplyTeeFunction then
  begin
    ASeries.BeginUpdate;
    ASeries.Clear;

    tmp:=Random(1000);

    for t:=0 to ANum-1 do
    begin
      ASeries.Add(tmp*0.001);
      tmp:=tmp+Random(50)-25;
    end;

    ASeries.EndUpdate;
  end
  else
     ASeries.FillSampleValues(ANum);
end;

procedure TFunctionsGallery.AddFunctions(const AGroup:String);

  procedure AddItem(const AType:TObject; const ADesc:String);
  var i : TListBoxItem;
  begin
    i:=TListBoxItem.Create(Self);
    i.Text:=ADesc;
    i.Data:=AType;
    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, TeeSeriesTypes[t]);

    s.Sort;

    LBFuncs.Clear;

    for t := 0 to s.Count-1 do
        AddItem(s.Objects[t], 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.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.ChartFunctionsClickTitle(Sender: TCustomChart;
  ATitle: TChartTitle; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button=TMouseButton.mbRight then
     TChartEditForm.Edit(Self,ChartFunctions);
end;

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

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

procedure TFunctionsGallery.FormCreate(Sender: TObject);
begin
  AddGroups;

  CBGroup.ItemIndex:=CBGroup.Items.IndexOf(TeeMsg_GalleryStandard);
  CBGroupChange(Self);
end;

function TFunctionsGallery.SelectedFunction:TTeeSeriesType;
begin
  if LBFuncs.ItemIndex=-1 then
     result:=nil
  else
     result:=TTeeSeriesType(LBFuncs.ListItems[LBFuncs.ItemIndex].Data);
end;

function TFunctionsGallery.SelectedFunctionClass:TTeeFunctionClass;
var tmp : TTeeSeriesType;
begin
  tmp:=SelectedFunction;

  if Assigned(tmp) then
     result:=tmp.FunctionClass
  else
     result:=nil;
end;

procedure TFunctionsGallery.LBFuncsChange(Sender: TObject);
begin
  if LBFuncs.ItemIndex<>-1 then
  begin
    ChartFunctions.Title.Caption:=LBFuncs.ListItems[LBFuncs.ItemIndex].Text;
    AddFunctionDemo(SelectedFunction);

    TBPeriod.Value:=Round(CurrentFunction.Period);
    LPeriod.Text:=IntToStr(Round(TBPeriod.Value));
  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 ChartFunctions.SeriesCount-2 do
      ChartFunctions[t].FillSampleValues(Round(TBData.Value));
end;

procedure TFunctionsGallery.TBPeriodChange(Sender: TObject);
var tmp : TTeeFunction;
begin
  LPeriod.Text:=IntToStr(Round(TBPeriod.Value));

  tmp:=CurrentFunction;

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

end.
