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

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls,
  {$IFNDEF UPTOXE3}
  FMX.StdCtrls,
  {$ENDIF}
  {$IFDEF D21}
  FMX.SpinBox, FMX.ComboEdit,
  {$ENDIF}
  FMX.Forms, FMX.ListBox, FMX.Edit, FMX.Dialogs;

type
  TFormatEditor = class(TForm)
    PanelOK: TPanel;
    Button1: TButton;
    Button2: TButton;
    GroupBox1: TGroupBox;
    CBCustom: TComboEdit;
    CBDate: TComboEdit;
    RBDate: TRadioButton;
    RBCustom: TRadioButton;
    RBGeo: TRadioButton;
    CBGeo: TComboEdit;
    Panel2: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    RBInteger: TRadioButton;
    CBPercent: TCheckBox;
    CBThousands: TCheckBox;
    CBCurrency: TCheckBox;
    CBFixedDecimals: TCheckBox;
    UpDown1: TSpinBox;
    UpDown2: TSpinBox;
    procedure FormCreate(Sender: TObject);
    procedure CBCustomChange(Sender: TObject);
    procedure CBDateChange(Sender: TObject);
    procedure RadioGroup1Click(Sender: TObject);
    procedure CBGeoChange(Sender: TObject);
    procedure RBIntegerChange(Sender: TObject);
    procedure CBThousandsChange(Sender: TObject);
    procedure CBPercentChange(Sender: TObject);
    procedure RBDateChange(Sender: TObject);
    procedure RBGeoChange(Sender: TObject);
    procedure RBCustomChange(Sender: TObject);
    procedure CBCurrencyChange(Sender: TObject);
    procedure UpDown2Change(Sender: TObject);
    procedure UpDown1Change(Sender: TObject);
    procedure CBFixedDecimalsChange(Sender: TObject);
    procedure CBGeoChangeTracking(Sender: TObject);
    procedure CBDateChangeTracking(Sender: TObject);
    procedure CBCustomChangeTracking(Sender: TObject);
  private
   { Private declarations }
    Format : String;

    tmpChanging : Boolean;

    Procedure AddDate(Const S:String);
    Procedure AddGeo(Const S:String);
    procedure RefreshFormat(const AFormat:String);
    function TheFormat: String;
  public
   { Public declarations }
    IsDate : Boolean;
    IsGeo  : Boolean;

    class procedure AddDefaultFormats(const AComboEdit:TComboEdit);
    class Function Change(const AOwner:TComponent; const AFormat:String; AllowDates:Boolean=True):String;
  end;

implementation

{$R *.fmx}

uses
  StrUtils, FMXTee.Constants, FMXTee.Procs;

procedure TFormatEditor.RadioGroup1Click(Sender: TObject);
begin
  if tmpChanging then exit;

  IsDate:=RBDate.IsChecked;
  IsGeo:=RBGeo.IsChecked;

  if RBDate.IsChecked or RBGeo.IsChecked or RBCustom.IsChecked then
     RBInteger.IsChecked:=False;

  CBDate.Enabled:=IsDate;
  CBGeo.Enabled:=RBGeo.IsChecked;
  CBCustom.Enabled:=RBCustom.IsChecked;

  if RBDate.IsChecked then
  begin
    if CBDate.Text='' then CBDate.Text:=FormatSettings.ShortDateFormat;

    CBDate.SetFocus;
  end
  else
  if RBGeo.IsChecked then
  begin
    if CBGeo.Text='' then CBGeo.Text:=CBGeo.Items[0];

    CBGeo.SetFocus;
  end
  else
  begin
    CBPercent.Enabled:=not CBCustom.Enabled;

    if CBCustom.Enabled then
    begin
      if CBCustom.Text='' then CBCustom.Text:=TheFormat;
      CBCustom.SetFocus;
    end;
  end;
end;

function TFormatEditor.TheFormat: String;
var t : Integer;
begin
  if CBCustom.Enabled then
     result:=CBCustom.Text
  else
  if RBInteger.IsChecked then
  begin
    if CBCurrency.IsChecked then result:=FormatSettings.CurrencyString
                            else result:='';

    if UpDown2.Value=0 then
       if CBThousands.IsChecked then result:=result+'#,###'
                                else result:=result+'#'
    else
    begin
      if CBThousands.IsChecked then
      begin
        if UpDown2.Value>3 then
           result:=result+DupeString('0',Round(UpDown2.Value-3))+FormatSettings.ThousandSeparator+'000'
        else
           result:=result+'#'+FormatSettings.ThousandSeparator+
                   DupeString('#',Round(3-UpDown2.Value))+DupeString('0',Round(UpDown2.Value));
      end
      else
      for t:=1 to Round(UpDown2.Value) do
          result:=result+'0';
    end;

    if UpDown1.Value>0 then
    begin
      result:=result+FormatSettings.DecimalSeparator;

      if CBFixedDecimals.IsChecked then
          result:=result+DupeString('0',Round(UpDown1.Value))
       else
          result:=result+DupeString('#',Round(UpDown1.Value));
    end;

    if CBPercent.IsChecked then
       result:=result+'%';
  end
  else
  if RBDate.IsChecked then
     result:=CBDate.Text
  else
  if RBGeo.IsChecked then
     result:=CBGeo.Text
  else
     result:='';
end;

procedure TFormatEditor.UpDown1Change(Sender: TObject);
begin
  RadioGroup1Click(Self);
end;

procedure TFormatEditor.UpDown2Change(Sender: TObject);
begin
  RadioGroup1Click(Self);
end;

procedure TFormatEditor.FormCreate(Sender: TObject);
begin
  AddDate(FormatSettings.ShortDateFormat);
  AddDate(FormatSettings.ShortTimeFormat);
end;

Procedure TFormatEditor.AddDate(Const S:String);
begin
  if CBDate.Items.IndexOf(S)=-1 then CBDate.Items.Add(S);
end;

class procedure TFormatEditor.AddDefaultFormats(const AComboEdit: TComboEdit);

  procedure Add(const AFormat:String);
  begin
    AComboEdit.Items.Add(AFormat);
  end;

begin
  Add(TeeMsg_DefValueFormat);
  Add('0');
  Add('0.0');
  Add('0.#');
  Add('#.#');
  Add('#,##0.00;(#,##0.00)');
  Add('00e-0');
  Add('#.0 "x10" E+0');
  Add('#.# x10E-#');
end;

Procedure TFormatEditor.AddGeo(Const S:String);
begin
  if CBGeo.Items.IndexOf(S)=-1 then CBGeo.Items.Add(S);
end;

procedure TFormatEditor.CBCurrencyChange(Sender: TObject);
begin
  RadioGroup1Click(Self);
end;

procedure TFormatEditor.CBCustomChange(Sender: TObject);
begin
  Format:=CBCustom.Text;
end;

procedure TFormatEditor.CBCustomChangeTracking(Sender: TObject);
begin
  CBCustomChange(Self);
end;

procedure TFormatEditor.CBDateChange(Sender: TObject);
begin
  Format:=CBDate.Text;
end;

procedure TFormatEditor.CBDateChangeTracking(Sender: TObject);
begin
  CBDateChange(Self);
end;

procedure TFormatEditor.CBFixedDecimalsChange(Sender: TObject);
begin
  RadioGroup1Click(Self);
end;

procedure TFormatEditor.CBGeoChange(Sender: TObject);
begin
  Format:=CBGeo.Text;
end;

procedure TFormatEditor.CBGeoChangeTracking(Sender: TObject);
begin
  CBGeoChange(Self);
end;

procedure TFormatEditor.RBCustomChange(Sender: TObject);
begin
  if RBCustom.IsChecked then
  begin
    RBInteger.IsChecked:=False;
    RBDate.IsChecked:=False;
    RBGeo.IsChecked:=False;
  end;

  RadioGroup1Click(Self);
end;

procedure TFormatEditor.RBDateChange(Sender: TObject);
begin
  if RBDate.IsChecked then
  begin
    RBInteger.IsChecked:=False;
    RBGeo.IsChecked:=False;
    RBCustom.IsChecked:=False;
  end;

  RadioGroup1Click(Self);
end;

procedure TFormatEditor.RBGeoChange(Sender: TObject);
begin
  if RBGeo.IsChecked then
  begin
    RBInteger.IsChecked:=False;
    RBDate.IsChecked:=False;
    RBCustom.IsChecked:=False;
  end;

  RadioGroup1Click(Self);
end;

procedure TFormatEditor.RBIntegerChange(Sender: TObject);
begin
  if RBInteger.IsChecked then
  begin
    RBDate.IsChecked:=False;
    RBGeo.IsChecked:=False;
    RBCustom.IsChecked:=False;
  end;

  RadioGroup1Click(Self);
end;

procedure TFormatEditor.RefreshFormat(const AFormat: String);

  procedure SetIntegerRB;
  begin
    tmpChanging:=True;
    try
      RBInteger.IsChecked:=True;
    finally
      tmpChanging:=False;
    end;
  end;

var i : Integer;
    t : Integer;
    tmp : Integer;
    IsCustom : Boolean;
    OldFormat : String;
begin
  OldFormat:=AFormat;
  Format:=AFormat;

  CBCustom.Items.Clear;
  CBCustom.Items.Add('#.#');
  CBCustom.Items.Add(string('0.0%'));

  CBGeo.Items.Clear;
  CBGeo.Items.Add(string('ddd° mm'' ss".zzz'));
  CBGeo.Items.Add('ddd mm'' ss".zzz');
  CBGeo.Items.Add('ddd deg mm'' ss".zzz');
  CBGeo.Items.Add('ddd mm'' ss".zzz');
  CBGeo.Items.Add('ddd mm ss.zzz');
  CBGeo.Items.Add('ddd mm ss');
  CBGeo.Items.Add('ddd mm');
  CBGeo.Items.Add(string('ddd°'));
  CBGeo.Items.Add('ddd');


  if IsDate or (CBDate.Items.IndexOf(Format)<>-1) then
  begin
    CBDate.Enabled:=True;
    AddDate(Format);
    CBDate.Text:=Format;
    CBDate.SetFocus;

    tmpChanging:=True;
    try
      RBDate.IsChecked:=True;
    finally
      tmpChanging:=False;
    end;
  end
  else
  if IsGeo or (CBGeo.Items.IndexOf(Format)<>-1) then
  begin
    CBGeo.Enabled:=True;
    AddGeo(Format);
    CBGeo.Text:=Format;
    CBGeo.SetFocus;

    tmpChanging:=True;
    try
      RBGeo.IsChecked:=True;
    finally
      tmpChanging:=False;
    end;
  end
  else
  begin
    i:=Pos('%',Format);

    CBPercent.IsChecked:=i>0;
    CBPercentChange(Self);

    if i>0 then
       Delete(Format,i,1);

    i:=Pos(FormatSettings.CurrencyString,Format);

    CBCurrency.IsChecked:=i>0;
    if i>0 then
       Delete(Format,i,Length(FormatSettings.CurrencyString));

    i:=Pos(FormatSettings.ThousandSeparator,Format);

    CBThousands.IsChecked:=i>0;
    if i>0 then
       Delete(Format,i,Length(FormatSettings.ThousandSeparator));

    i:=Pos(FormatSettings.DecimalSeparator,Format);
    if i>0 then
    begin
      SetIntegerRB;

      tmp:=0;
      while (Copy(Format,i+tmp+1,1)='#') or (Copy(Format,i+tmp+1,1)='0') do
         Inc(tmp);

      UpDown1.Value:=tmp;

      CBFixedDecimals.IsChecked:=(tmp>0) and (Copy(Format,i+1,1)='0');

      Delete(Format,i,tmp+Length(FormatSettings.ThousandSeparator));
    end;

    IsCustom:=False;

    for t:=1 to Length(Format) do
    if (Format[t]<>'#') and (Format[t]<>'0') then
    begin
      IsCustom:=True;
      Format:=OldFormat;
      break;
    end;

    tmp:=0;
    if not IsCustom then
    begin
      SetIntegerRB;

      for t:=1 to Length(Format) do
          if Format[t]='0' then
             Inc(tmp);

      UpDown2.Value:=tmp;
    end
    else
    begin
      tmpChanging:=True;
      try
        RBCustom.IsChecked:=True;
      finally
        tmpChanging:=False;
      end;

      CBCustom.Enabled:=True;

      if CBCustom.Items.IndexOf(Format)=0 then
         CBCustom.Items.Add(Format);

      CBCustom.Text:=Format;
      CBCustom.SetFocus;
    end;
  end;

  TeeTranslateControl(Self);
end;

procedure TFormatEditor.CBPercentChange(Sender: TObject);
begin
  CBThousands.Enabled:=not CBPercent.IsChecked;
  CBCurrency.Enabled:=not CBPercent.IsChecked;

  if CBPercent.IsChecked then
  begin
    CBThousands.IsChecked:=False;
    CBCurrency.IsChecked:=False;
  end;

  RadioGroup1Click(Self);
end;

procedure TFormatEditor.CBThousandsChange(Sender: TObject);
begin
  RadioGroup1Click(Sender);
end;

class function TFormatEditor.Change(const AOwner: TComponent; const AFormat: String;
  AllowDates: Boolean): String;
begin
  with TFormatEditor.Create(AOwner) do
  try
    RBDate.Visible:=AllowDates;
    CBDate.Visible:=AllowDates;

    AddDefaultFormats(CBCustom);

    RefreshFormat(AFormat);

    if ShowModal=mrOk then result:=TheFormat
                      else result:=AFormat;

  finally
    Free;
  end;
end;

end.
