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

interface

uses
  System.Classes, FMX.Types,
  {$IFNDEF UPTOXE3}
  FMX.StdCtrls,
  {$ENDIF}
  FMX.Controls;

type
  {$IFDEF D16}
  [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 {$IFDEF D26}or pidOSX64{$ENDIF})]
  {$ENDIF}
  TRadioGroup = class(TGroupBox)
  private
    FItemIndex: Integer;
    FOnChange: TNotifyEvent;
    FAutoSize: Boolean;

    procedure CheckSelected;
    function GetCount: Integer;
    function GetItem(Index: Integer): TRadioButton;
    procedure ItemChanged(Sender: TObject);
    procedure SetAutoSize(const Value: Boolean);
    procedure SetItemIndex(const Value: Integer);
  protected
    procedure Changed; virtual;

    {$IFDEF D17}
    procedure DoAddObject({$IFDEF D18}const {$ENDIF}AObject: TFmxObject); override;
    procedure DoRealign; override;
    {$ENDIF}

    procedure Loaded; override;
  public
    constructor Create(AOwner: TComponent); override;

    function Add(const AText:String):TRadioButton;

    {$IFNDEF D17}
    procedure AddObject(AObject: TFmxObject); override;
    {$ENDIF}

    function IndexOfItem(AItem: TObject): Integer;

    {$IFNDEF D17}
    procedure Realign; override;
    {$ENDIF}

    function Selected:TRadioButton;

    property Count: Integer read GetCount;
    property Items[Index: Integer]: TRadioButton read GetItem;
  published
    property AutoSize:Boolean read FAutoSize write SetAutoSize default False;
    property CanFocus default True;
    property ItemIndex: Integer read FItemIndex write SetItemIndex default -1;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

implementation

uses
  System.Math;

{ TRadioGroup }

function TRadioGroup.Add(const AText: String): TRadioButton;
begin
  result:=TRadioButton.Create(Owner);
  result.Text:=AText;
  AddObject(result);
end;

{$IFDEF D17}
procedure TRadioGroup.DoAddObject({$IFDEF D18}const {$ENDIF}AObject: TFmxObject);
{$ELSE}
procedure TRadioGroup.AddObject(AObject: TFmxObject);
{$ENDIF}
begin
  inherited;
  if AObject is TRadioButton then
    TRadioButton(AObject).OnChange := ItemChanged;
end;

constructor TRadioGroup.Create(AOwner: TComponent);
begin
  inherited;
  CanFocus := True;
  FItemIndex := -1;

  {$IFDEF D18}
  Padding.Top := 14;
  Padding.Left := 6;
  {$ELSE}
  Margins.Top := 14;
  Margins.Left := 6;
  {$ENDIF}
end;

function TRadioGroup.GetCount: Integer;
var
  t: Integer;
begin
  result := 0;

  for t := 0 to ChildrenCount - 1 do
    if Children[t] is TRadioButton then
      Inc(result);
end;

function TRadioGroup.GetItem(Index: Integer): TRadioButton;
var
  c, t: Integer;
begin
  result := nil;

  if Index>-1 then
  begin
    c := 0;

    for t := 0 to ChildrenCount - 1 do
      if Children[t] is TRadioButton then
        if c = Index then
          Exit(TRadioButton(Children[t]))
        else
          Inc(c);
  end;
end;

function TRadioGroup.IndexOfItem(AItem: TObject): Integer;
var
  i, t: Integer;
begin
  i := -1;

  for t := 0 to ChildrenCount - 1 do
    if Children[t] is TRadioButton then
    begin
      Inc(i);

      if Children[t] = AItem then
        Exit(i);
    end;

  result := -1;
end;

procedure TRadioGroup.ItemChanged(Sender: TObject);
begin
  if not (csLoading in ComponentState) then
  begin
    if (Sender as TRadioButton).IsChecked then
       ItemIndex := IndexOfItem(Sender)

//    else
//    if IndexOfItem(Sender)=ItemIndex then
//       FItemIndex:=-1;  // <-- do not notify Change
  end;
end;

procedure TRadioGroup.CheckSelected;
var c : Integer;
    t : Integer;
begin
  c := 0;

  for t := 0 to ChildrenCount - 1 do
    if Children[t] is TRadioButton then
    begin
      {$IFDEF D19}
      if c=ItemIndex then
      begin
        TRadioButton(Children[t]).IsChecked := True;
        break;
      end;
      {$ELSE}
      TRadioButton(Children[t]).IsChecked := (c = ItemIndex);
      {$ENDIF}

      Inc(c);
    end;
end;

procedure TRadioGroup.Loaded;

  {$IFDEF D19}
  procedure SetGroupName;
  var t : Integer;
  begin
    for t := 0 to ChildrenCount - 1 do
      if Children[t] is TRadioButton then
         TRadioButton(Children[t]).GroupName:=Name;
  end;
  {$ENDIF}

begin
  inherited;

  {$IFDEF D19}
  SetGroupName;
  {$ENDIF}

  CheckSelected;
end;

procedure TRadioGroup.Changed;
begin
  if (not (csLoading in ComponentState)) and Assigned(FOnChange) then
    FOnChange(Self);
end;

{$IFDEF D17}
procedure TRadioGroup.DoRealign;
{$ELSE}
procedure TRadioGroup.Realign;
{$ENDIF}
var
  t: Integer;
  pos: Single;
  b: TRadioButton;
begin
  inherited;

  if csLoading in ComponentState then
    Exit;

  pos := Padding.Top;

  for t := 0 to ChildrenCount - 1 do
    if Children[t] is TRadioButton then
    begin
      b := TRadioButton(Children[t]);
      b.Position.X := Padding.Left;
      b.Position.Y := pos;

      pos := pos + b.Height + b.Padding.Bottom;
    end;

  if FAutoSize then
  begin
    if Count>0 then
    begin
      b:=Items[Count-1];
      pos:=b.Position.Y+b.Height+b.Padding.Bottom+Max(4,Padding.Bottom);
    end
    else
      pos:=8;

    Height:=Max(pos,Padding.Top+Padding.Bottom);
  end;
end;

function TRadioGroup.Selected: TRadioButton;
begin
  result:=Items[ItemIndex];
end;

procedure TRadioGroup.SetAutoSize(const Value: Boolean);
begin
  if FAutoSize<>Value then
  begin
    FAutoSize:=Value;

    if FAutoSize then
       ReAlign;
  end;
end;

procedure TRadioGroup.SetItemIndex(const Value: Integer);
begin
  if FItemIndex <> Value then
  begin
    FItemIndex := Value;
    CheckSelected;
    Changed;
  end;
end;

end.
