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

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.TabControl, FMX.ListBox,
  {$IFNDEF UPTOXE3}
  FMX.StdCtrls, FMX.Controls3D, FMX.Viewport3D,
  {$ENDIF}
  {$IFDEF D19}
  FMX.Graphics,
  {$ENDIF}
  FMX.Grid, FMX.Layouts, FMXTee.Chart.Grid, FMXTee.Engine, FMXTee.Procs,
  FMXTee.Chart, FMX.Types3D, FMXTee.Chart3D, FMX.Objects;

type
  TChartThemeSelector = class(TForm)
    Panel1: TPanel;
    CheckBox1: TCheckBox;
    PanelButtons: TPanel;
    BOk: TButton;
    BCancel: TButton;
    TabControl1: TTabControl;
    TabItem1: TTabItem;
    TabControlPreview: TTabControl;
    Splitter1: TSplitter;
    TabPreview: TTabItem;
    TabPalette: TTabItem;
    PreviewChart2D: TChart;
    LBThemes: TListBox;
    Viewport3D1: TViewport3D;
    Chart3DChart1: TChart;
    PreviewChart3D: TChart3D;
    LBPalette: TListBox;
    ChartGrid1: TChartGrid;
    Splitter2: TSplitter;
    TabFonts: TTabItem;
    LBFonts: TListBox;
    Label1: TLabel;
    Button1: TButton;
    Button2: TButton;
    TabColors: TTabItem;
    LBColors: TListBox;
    Label2: TLabel;
    TBOffset: TTrackBar;
    PaintColors: TPaintBox;
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure TabControlPreviewChange(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure CheckBox1Change(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure BOkClick(Sender: TObject);
    procedure LBThemesChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure LBPaletteChange(Sender: TObject);
    procedure LBFontsChange(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure LBColorsChange(Sender: TObject);
    procedure TBOffsetChange(Sender: TObject);
    procedure PaintColorsPaint(Sender: TObject; Canvas: TCanvas);
  private
    { Private declarations }
    Chart : TCustomChart;
    PreviewChart : TCustomChart;

    PaletteSeries : TChartSeries;

    ICurrentColors : TColorArray;

    IChangingFonts,
    IChangingColors : Boolean;

    procedure ApplyScheme(const AColors:TColorArray);
    procedure InitPreviewChart;
    procedure RefreshColorGrid;
    Function SelectedTheme:TChartThemeClass;
  public
    { Public declarations }
    AutoApply : Boolean;

    class function Choose(AOwner:TComponent; AChart:TCustomChart):Boolean;
  end;

implementation

{$R *.fmx}

uses
  Math,
  FMXTee.Themes, FMXTee.Constants, FMXTee.ProConstants, FMXTee.Editor.Chart,
  FMXTee.Editor.Font, FMXTee.Editor.Stroke;

procedure TChartThemeSelector.BOkClick(Sender: TObject);
begin
  Chart.View3D:=CheckBox1.IsChecked;

  if SelectedTheme<>nil then
  begin
    if LBPalette.ItemIndex=0 then
       ApplyChartTheme(SelectedTheme,Chart)
    else
       ApplyChartTheme(SelectedTheme,Chart,LBPalette.ItemIndex-1);
  end
  else
    Chart.ColorPaletteIndex:=LBPalette.ItemIndex-1;

  BOK.Enabled:=False;
end;

Function TChartThemeSelector.SelectedTheme:TChartThemeClass;
begin
  if LBThemes.ItemIndex<=0 then
     result:=nil
  else
     result:=ChartThemes[LBThemes.ItemIndex-1];
end;

type
  TSeriesAccess=class(TChartSeries);

procedure TChartThemeSelector.InitPreviewChart;
var t : Integer;
    Old : Boolean;
begin
  PreviewChart.FreeAllSeries;

  if Assigned(Chart) then
  begin
    PreviewChart.Assign(Chart);

    if Chart.Parent is TCustomChart3D then
    begin
      PreviewChart3D.RotationAngle:=TCustomChart3D(Chart.Parent).RotationAngle;

      with TCustomChart3D(Chart.Parent) do
           Self.PreviewChart3D.SetSize(Width,Height,Depth);
    end;

    for t:=0 to Chart.SeriesCount-1 do
    begin
      Old:=TSeriesAccess(Chart[t]).ManualData;
      TSeriesAccess(Chart[t]).ManualData:=True;
      try
        {$IFNDEF TEEOCX} //pending fix ax
        CloneChartSeries(Chart[t],PreviewChart,PreviewChart);
        {$ENDIF}
      finally
        TSeriesAccess(Chart[t]).ManualData:=Old;
      end;
    end;

    CheckBox1.IsChecked:=Chart.View3D;
  end;
end;

procedure TChartThemeSelector.RefreshColorGrid;
var t : Integer;
begin
  if Assigned(PaletteSeries) then
  begin
    PaletteSeries.Clear;
    for t:=0 to Length(PreviewChart.ColorPalette)-1 do
        PaletteSeries.Add(t,'',PreviewChart.ColorPalette[t]);

    ChartGrid1.RecalcDimensions;
    //ChartGrid1.Invalidate;
  end;
end;

procedure TChartThemeSelector.Button1Click(Sender: TObject);
begin
  TThemesList.ApplyFontSizeDelta(Chart,1);
end;

procedure TChartThemeSelector.Button2Click(Sender: TObject);
begin
  TThemesList.ApplyFontSizeDelta(Chart,-1);
end;

procedure TChartThemeSelector.CheckBox1Change(Sender: TObject);
begin
  PreviewChart.View3D:=CheckBox1.IsChecked;
  BOk.Enabled:=True;
end;

class function TChartThemeSelector.Choose(AOwner: TComponent;
  AChart: TCustomChart): Boolean;
begin
  with TChartThemeSelector.Create(AOwner) do
  try
    Chart:=AChart;
    BOk.ModalResult:=mrOk;
    BCancel.Visible:=True;
    PanelButtons.Width:=192;

    result:=ShowModal=mrOk;
  finally
    Free;
  end;
end;

Procedure AddChartThemes(Items:TStrings);
var t : Integer;
    tmp : TChartTheme;
begin
  for t:=0 to ChartThemes.Count-1 do
  begin
    tmp:=ChartThemes[t].Create(nil);
    try
      Items.Add(tmp.Description);
    finally
      tmp.Free;
    end;
  end;
end;

procedure TChartThemeSelector.FormActivate(Sender: TObject);

  procedure CreateLight;
  var Light1 : TLight;
  begin
    Light1:=TLight.Create(Self);
    Light1.Color:=TAlphaColorRec.White;
    Light1.LightType:=TLightType.{$IFDEF D20}Directional{$ELSE}ltDirectional{$ENDIF};
    Light1.SpotCutOff:=180;
    Light1.Position.X:=-5.664;
    Light1.Position.Y:=-5.317;
    Light1.RotationAngle.Y:=53.04;
    Light1.RotationAngle.Z:=38.64;

    Light1.Parent:=ViewPort3D1;
  end;

begin
  if LBThemes.Count>0 then
     Exit;

  if not Assigned(Chart) then
     Chart:=TCustomChart(TagObject);

  if Chart.Parent is TCustomChart3D then
  begin
    PreviewChart2D.Visible:=False;

    CreateLight;
    Viewport3D1.Visible:=True;

    PreviewChart:=PreviewChart3D.Chart;
  end;

  // Fill listbox with registered Themes...
  LBThemes.Clear;
  LBThemes.Items.Add(TeeMsg_Current);

  AddChartThemes(LBThemes.Items);
  LBThemes.ItemIndex:=0;

  TabControlPreview.ActiveTab:=TabPreview;

  InitPreviewChart;

  BOk.Enabled:=False;

  TeeTranslateControl(Self);
end;

procedure TChartThemeSelector.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if BOk.Enabled then
  case YesNoCancel(TeeMsg_SureToApply) of

    mrYes: begin
             BOkClick(Self);
             CanClose:=not BOk.Enabled;
           end;

     mrNo: begin
             BOk.Enabled:=False;
             CanClose:=True;
           end;

 mrCancel: CanClose:=False;
  end;
end;

procedure TChartThemeSelector.FormCreate(Sender: TObject);
begin
  PreviewChart:=PreviewChart2D;
  PanelButtons.Width:=100;
end;

procedure TChartThemeSelector.FormDestroy(Sender: TObject);
begin
  PaletteSeries.Free;
end;

procedure TChartThemeSelector.ApplyScheme(const AColors:TColorArray);
begin
  TThemesList.ApplyColors(Chart,AColors,Round(TBOffset.Value));
end;

procedure TChartThemeSelector.LBColorsChange(Sender: TObject);
begin
  if not IChangingColors then
  begin
    if LBColors.ItemIndex=0 then
       ApplyScheme(ICurrentColors)
    else
       ApplyScheme(TeeColorSchemes[LBColors.ItemIndex-1]);

    PaintColors.Repaint;

    InitPreviewChart;
  end;
end;

procedure TChartThemeSelector.LBFontsChange(Sender: TObject);
begin
  if (LBFonts.ItemIndex<>-1) and Assigned(Chart) then
  begin
    TThemesList.ApplyFont(Chart,LBFonts.Items[LBFonts.ItemIndex]);
    InitPreviewChart;
  end;
end;

procedure TChartThemeSelector.LBPaletteChange(Sender: TObject);
begin
  if LBPalette.ItemIndex=0 then
     LBThemesChange(Self)
  else
     PreviewChart.ColorPaletteIndex:=LBPalette.ItemIndex-1;

  {
  if CBScale.IsChecked then
     ScaledChart.Invalidate;
  }

  RefreshColorGrid;

  BOK.Enabled:=True;

  if (LBPalette.ItemIndex>0) and AutoApply then
     Chart.ColorPaletteIndex:=LBPalette.ItemIndex-1;
end;

procedure TChartThemeSelector.LBThemesChange(Sender: TObject);
begin
  if LBThemes.ItemIndex>0 then
  begin
    if LBPalette.ItemIndex=0 then
       ApplyChartTheme(SelectedTheme,PreviewChart)
    else
       ApplyChartTheme(SelectedTheme,PreviewChart,LBPalette.ItemIndex-1);

    BOK.Enabled:=True;
  end
  else
  begin
    InitPreviewChart;
    BOK.Enabled:=False;
  end;

  RefreshColorGrid;

  if AutoApply then
     BOkClick(Self);
end;

procedure TChartThemeSelector.PaintColorsPaint(Sender: TObject;
  Canvas: TCanvas);
var t,
    w,
    h,
    x : Integer;
    tmp : TColorArray;
begin
  if LBColors.ItemIndex=-1 then
     Exit;

  if Canvas.BeginScene then
  try
    if LBColors.ItemIndex=0 then
       tmp:=ICurrentColors
    else
       tmp:=TeeColorSchemes[LBColors.ItemIndex-1];

    w:=Round((PaintColors.Width-4)/Length(tmp))-4;
    h:=Round(Math.Min(w,PaintColors.Height-2));

    Canvas.Stroke.Kind:=TBrushKind.{$IFDEF D20}Solid{$ELSE}bkSolid{$ENDIF};
    Canvas.Stroke.Color:=TAlphaColors.Black;

    Canvas.Fill.Kind:=TBrushKind.{$IFDEF D20}Solid{$ELSE}bkSolid{$ENDIF};

    for t:=Low(tmp) to High(tmp) do
    begin
      Canvas.Fill.Color:=tmp[t];

      x:=2+(t*(w+2));

      Canvas.FillRect(RectF(x,2,x+w,2+h),0,0,AllCorners,1);
      Canvas.DrawRect(RectF(x,2,x+w,2+h),0,0,AllCorners,1);
    end;
  finally
    Canvas.EndScene;
  end;
end;

procedure TChartThemeSelector.TabControlPreviewChange(Sender: TObject);

  procedure InitColorGrid;
  begin
    PaletteSeries:=TChartSeries.Create(nil);
    PaletteSeries.MandatoryValueList.Name:=TeeMsg_Index;

    ChartGrid1.Series:=PaletteSeries;
    ChartGrid1.ShowFields:=False;
    ChartGrid1.ReadOnly:=True;
    ChartGrid1.AllowAppend:=False;
    ChartGrid1.ColumnByIndex(2).Width:=90;
  end;

  procedure FillFonts;
  var f : TStringList;
  begin
    f:=TFontEditor.Fonts;
    try
      LBFonts.Items:=f;
    finally
      f.Free;
    end;
 end;

  procedure FillColors;
  var t : Integer;
  begin
    LBColors.Items.Clear;

    LBColors.Items.Add('Current');

    for t:=Low(TeeColorSchemes) to High(TeeColorSchemes) do
        LBColors.Items.Add('Scheme '+IntToStr(t));
  end;

  function FindCurrentColors:Integer;

    function EqualColors(const AColors:TColorArray):Boolean;
    var tmpLow,
        t : Integer;
    begin
      result:=Length(ICurrentColors)<=Length(AColors);

      if result then
      begin
        tmpLow:=Low(AColors);

        for t:=0 to High(ICurrentColors) do
            if ICurrentColors[t]<>AColors[tmpLow+t] then
            begin
              result:=False;
              break;
            end;
      end;
    end;

  var t : Integer;
  begin
    result:=0;

    SetLength(ICurrentColors,5);

    ICurrentColors[0]:=Chart.Legend.Color;
    ICurrentColors[1]:=Chart.Legend.Pen.Color;
    ICurrentColors[2]:=Chart.Legend.Font.Color;

    ICurrentColors[3]:=Chart.Walls.Back.Color;
    ICurrentColors[4]:=Chart.Walls.Bottom.Color;

    for t:=Low(TeeColorSchemes) to High(TeeColorSchemes) do
        if EqualColors(TeeColorSchemes[t]) then
        begin
          result:=t+1;

          ICurrentColors:=TeeColorSchemes[t];

          break;
        end;
  end;

begin
  if TabControlPreview.ActiveTab=TabPalette then
  begin
    if LBPalette.Items.Count=0 then
    begin
      TColorPalettes.AddTo(LBPalette.Items,True);

      if Assigned(Chart) then
         if Chart.ColorPaletteIndex=0 then
            LBPalette.ItemIndex:=0
         else
            LBPalette.ItemIndex:=Chart.ColorPaletteIndex+1
      else
        LBPalette.ItemIndex:=0;
    end;

    if ChartGrid1.Series=nil then
       InitColorGrid;

    RefreshColorGrid;
  end
  else
  if TabControlPreview.ActiveTab=TabFonts then
  begin
    IChangingFonts:=True;
    try
      if LBFonts.Count=0 then
         FillFonts;

      if Assigned(Chart) then
         LBFonts.ItemIndex:=LBFonts.Items.IndexOf(Chart.Legend.Font.Name);
    finally
      IChangingFonts:=False;
    end;
  end
  else
  if TabControlPreview.ActiveTab=TabColors then
  begin
    IChangingColors:=True;
    try
      if LBColors.Items.Count=0 then
         FillColors;

      LBColors.ItemIndex:=FindCurrentColors;
    finally
      IChangingColors:=False;
    end;
  end
end;

procedure TChartThemeSelector.TBOffsetChange(Sender: TObject);
begin
  LBColorsChange(Self);
end;

initialization
  TChartEditForm.ThemesEditor:=TChartThemeSelector;
finalization
  TChartEditForm.ThemesEditor:=nil;
end.
