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

interface

uses
  SysUtils, Types, Classes, Variants, FMX.Types, FMX.Controls, FMX.Forms,
  {$IFNDEF UPTOXE3}
  FMX.StdCtrls,
  {$ENDIF}
  FMX.ListBox, FMX.Dialogs, FMXTee.Engine, FMXTee.Chart,
  FMX.Layouts, FMX.Menus, FMX.Objects, FMX.Memo, FMX.TreeView;

type
  TToolsEditor = class(TForm)
    Splitter1: TSplitter;
    LBTools: TListBox;
    PanelToolEditor: TPanel;
    PTop: TPanel;
    BAdd: TButton;
    BDelete: TButton;
    CBActive: TCheckBox;
    Panel2: TPanel;
    BMoveUp: TButton;
    BMoveDown: TButton;
    CBShowInEditor: TCheckBox;
    PBottom: TPanel;
    PopupMenu1: TPopupMenu;
    BottomText: TText;
    BClone: TButton;
    Layout1: TLayout;
    StyleBook1: TStyleBook;
    procedure FormCreate(Sender: TObject);
    procedure BCloneClick(Sender: TObject);
    procedure BAddClick(Sender: TObject);
    procedure BDeleteClick(Sender: TObject);
    procedure BMoveUpClick(Sender: TObject);
    procedure BMoveDownClick(Sender: TObject);
    procedure PBottomClick(Sender: TObject);
    procedure LBToolsChange(Sender: TObject);
    procedure CBActiveChange(Sender: TObject);
    procedure CBShowInEditorChange(Sender: TObject);
  private
   { Private declarations }
    Chart : TCustomChart;

    FLastForm : TCommonCustomForm;

    procedure AddTool(const ATool:TTeeCustomTool);
    procedure AddToolEditor;
    function CloneTool(const Tool:TTeeCustomTool):TTeeCustomTool;
    Function CurrentTool:TTeeCustomTool;
    procedure DeleteForm;
    function DoAddNewTool(const AClass: TTeeCustomToolClass;
      const ADefaultName: String): TTeeCustomTool;
    procedure EnableButtons;
    procedure FillTools;
    function GetNewTool: TTeeCustomTool;
    procedure RefreshChart(const AChart:TCustomChart);
    procedure RefreshTool(const ATool:TTeeCustomTool);
    procedure SetPanelBottom;
    procedure SwapTool(A,B:Integer);
    function Tool:TTeeCustomTool;
    procedure TryAddEditorNode(const ATool:TTeeCustomTool);

  protected
    OnAdded   : TNotifyEvent;
    OnDeleted : TNotifyEvent;
  public
   { Public declarations }

    EditorNode : TTreeViewItem;

    class function CreateEditor(const AOwner:TComponent; const AChart:TCustomChart):TToolsEditor;
    class procedure Edit(const AOwner:TComponent; const ATool:TTeeCustomTool);
    procedure EditTool(const Value: TTeeCustomTool);
  end;

implementation

{$R *.fmx}

uses
  FMXTee.Tools.Gallery, FMXTee.Procs, FMXTee.Constants, FMXTee.Editor.Stroke,
  FMXTee.Chart.ListBox;

procedure TToolsEditor.AddTool(const ATool:TTeeCustomTool);
var tmp : TListBoxItem;
begin
  tmp:=TListBoxItem.Create(Self);
  tmp.Text:=ATool.Description;
  tmp.Data:=ATool;
  LBTools.AddObject(tmp);

  TToolsGallery.ApplyListToolItem(tmp,ATool.ClassName);
end;

procedure TToolsEditor.FillTools;
var t : Integer;
begin
  LBTools.Clear;

  for t := 0 to Chart.Tools.Count-1 do
  if (csDesigning in Chart.Tools[t].ComponentState) or
     Chart.Tools[t].ShowInEditor then
        AddTool(Chart.Tools[t]);
end;

procedure TToolsEditor.FormCreate(Sender: TObject);
begin
  CBActive.Enabled:=False;
end;

procedure TToolsEditor.LBToolsChange(Sender: TObject);
begin
  RefreshTool(Tool);
end;

function TToolsEditor.CloneTool(const Tool:TTeeCustomTool):TTeeCustomTool;
begin
  result:=CloneChartTool(Tool,Tool.Owner);
  result.ParentChart:=Tool.ParentChart;
end;

procedure TToolsEditor.BCloneClick(Sender: TObject);
var tmpTool : TTeeCustomTool;
begin
  tmpTool:=CloneTool(CurrentTool);
  AddTool(tmpTool);

  TryAddEditorNode(tmpTool);

  LBTools.ItemIndex:=LBTools.Count-1;
  EnableButtons;
end;

function TToolsEditor.GetNewTool:TTeeCustomTool;
var tmp : TTeeCustomToolClass;
begin
  tmp:=TToolsGallery.Choose(Self);

  if Assigned(tmp) then
     result:=DoAddNewTool(tmp,TeeMsg_DefaultToolName)
  else
     result:=nil;
end;

procedure TToolsEditor.DeleteForm;
begin
  FreeAndNil(FLastForm);

  {
  while PanelToolEditor.ChildrenCount>0 do
        PanelToolEditor.Children[0].DisposeOf;
  }
end;

function TToolsEditor.DoAddNewTool(const AClass:TTeeCustomToolClass;
                                   const ADefaultName:String):TTeeCustomTool;
begin
  result:=AClass.Create(Chart.Owner);

  with result do
  begin
    ParentChart:=Self.Chart;
    Name:=TeeGetUniqueName(Owner,ADefaultName);
  end;
end;

type
  TToolAccess=class(TTeeCustomTool);
  TFormClass=class of TForm;

class procedure TToolsEditor.Edit(const AOwner: TComponent; const ATool: TTeeCustomTool);
var tmpClass : TFormClass;
begin
  tmpClass:=TFormClass(GetClass(TToolAccess(ATool).GetEditorClass));

  if Assigned(tmpClass) then
     with tmpClass.Create(AOwner) do
     try
       TagObject:=ATool;
       ShowModal;
     finally
       Free;
     end;
end;

procedure TToolsEditor.EnableButtons;
begin
  With LBTools do
  begin
    BMoveUp.Enabled  :=ItemIndex>0;
    BMoveDown.Enabled:=ItemIndex<Items.Count-1;
    BDelete.Enabled  :=ItemIndex<>-1;
  end;

  BClone.Enabled   :=BDelete.Enabled;
  CBActive.Enabled :=BDelete.Enabled;
  CBShowInEditor.Enabled:=BDelete.Enabled;
end;

procedure TToolsEditor.EditTool(const Value: TTeeCustomTool);
begin
  PTop.Visible:=False;
  LBTools.Visible:=False;
  Splitter1.Visible:=False;
  LBTools.ItemIndex:=LBTools.Items.IndexOfObject(Value);
end;

procedure TToolsEditor.TryAddEditorNode(const ATool:TTeeCustomTool);
var tmpNode : TTreeViewItem;
begin
  if Assigned(EditorNode) then
  begin
    tmpNode:=TTreeViewItem.Create(EditorNode.Owner);
    tmpNode.Text:=ATool.Description;
    tmpNode.TextSettings.WordWrap:=False; // Fix
    tmpNode.TagObject:=ATool;
    tmpNode.Parent:=EditorNode;
  end;
end;

procedure TToolsEditor.BAddClick(Sender: TObject);
var tmpTool : TTeeCustomTool;
begin
  tmpTool:=GetNewTool;

  if Assigned(tmpTool) then
  begin
    if Assigned(OnAdded) then
       OnAdded(tmpTool);

    FillTools;

    LBTools.ItemIndex:=LBTools.Items.Count-1;

    LBTools.SetFocus;

    LBToolsChange(Self);

    TryAddEditorNode(tmpTool);
  end;
end;

procedure TToolsEditor.BDeleteClick(Sender: TObject);
var Old : Integer;
begin
  Old:=LBTools.ItemIndex;

  if Assigned(EditorNode) then
     EditorNode.ItemByIndex(Old).DisposeOf;

  Tool.DisposeOf;
  LBTools.Selected.DisposeOf;

  if Old>=LBTools.Count then
     Old:=LBTools.Count-1;

  LBTools.ItemIndex:=Old;
  LBToolsChange(Self);
end;

procedure TToolsEditor.CBActiveChange(Sender: TObject);
begin
  Tool.Active:=CBActive.IsChecked;
end;

procedure TToolsEditor.BMoveUpClick(Sender: TObject);
begin
  With LBTools do SwapTool(ItemIndex,ItemIndex-1);
end;

procedure TToolsEditor.BMoveDownClick(Sender: TObject);
begin
  With LBTools do SwapTool(ItemIndex,ItemIndex+1);
end;

procedure TToolsEditor.CBShowInEditorChange(Sender: TObject);
begin
  Tool.ShowInEditor:=CBShowInEditor.IsChecked;
end;

procedure TToolsEditor.RefreshChart(const AChart:TCustomChart);
begin
  Chart:=AChart;

  CBShowInEditor.Visible:=(csDesigning in Chart.ComponentState);
  CBShowInEditor.Enabled:=False;

  if not CBShowInEditor.Visible then
     CBActive.Position.Y:=12;

  FillTools;

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

class function TToolsEditor.CreateEditor(const AOwner: TComponent; const AChart: TCustomChart):TToolsEditor;
begin
  result:=TToolsEditor.Create(AOwner);
  result.RefreshChart(AChart);
end;

function TToolsEditor.CurrentTool: TTeeCustomTool;
begin
  if LBTools.ItemIndex=-1 then
     result:=nil
  else
     result:=TTeeCustomTool(LBTools.Items.Objects[LBTools.ItemIndex]);
end;

procedure TToolsEditor.PBottomClick(Sender: TObject);
var tmp : {$IFDEF FMI}WideString{$ELSE}String{$ENDIF};
begin
  if CurrentTool<>nil then
  begin
    tmp:=CurrentTool.Name;

    if TeeInputQuery(TeeMsg_ChangeToolName,TeeMsg_NewToolName,tmp) then
    begin
      CurrentTool.Name:=tmp;
      SetPanelBottom;
    end;
  end;
end;

procedure TToolsEditor.SetPanelBottom;
begin
  if PBottom.Visible and (CurrentTool<>nil) then
     BottomText.Text:=CurrentTool.Name+' ('+CurrentTool.ClassName+')' // Do not localize
  else
     BottomText.Text:='';
end;

procedure TToolsEditor.AddToolEditor;
var tmpClass : TClass;
    tmp      : TForm;
begin
  if CurrentTool<>nil then
  begin
    CBActive.IsChecked:=CurrentTool.Active;
    DeleteForm;

    tmpClass:=GetClass(TToolAccess(CurrentTool).GetEditorClass);
    if Assigned(tmpClass) then
    begin
      tmp:=TFormClass(tmpClass).Create(Self);
      //TeeTranslateControl(tmp);
      //tmp.Align:=TAlignLayout.alClient;
      tmp.TagObject:=CurrentTool;
      EmbeddForm(tmp,PanelToolEditor);

      // Workaround XE4:
      tmp.OnActivate(Self);
    end
    else
      tmp:=nil;

    FLastForm:=tmp;

    CBShowInEditor.Visible:=csDesigning in CurrentTool.ComponentState;

    if CBShowInEditor.Visible then
    begin
      CBShowInEditor.IsChecked:=CurrentTool.ShowInEditor;
      CBActive.Position.Y:=3;
    end;
  end
  else
    DeleteForm
end;

procedure TToolsEditor.RefreshTool(const ATool: TTeeCustomTool);
begin
  if csDestroying in ComponentState then
     Exit;

  AddToolEditor;
  EnableButtons;

  if BDelete.Enabled then
  begin
    CBActive.Enabled:=True;
    CBActive.IsChecked:=ATool.Active;
    CBShowInEditor.IsChecked:=ATool.ShowInEditor;
  end;

  SetPanelBottom;
end;

procedure TToolsEditor.SwapTool(A, B: Integer);
var tmpIndex : Integer;
begin
  LBTools.Items.Exchange(A,B);

  Chart.Tools.Exchange(A,B);
  tmpIndex:=Chart.Tools[A].ComponentIndex;
  Chart.Tools[A].ComponentIndex:=Chart.Tools[B].ComponentIndex;
  Chart.Tools[B].ComponentIndex:=tmpIndex;
  Chart.Invalidate;

  EnableButtons;
end;

function TToolsEditor.Tool: TTeeCustomTool;
begin
  if (LBTools.ItemIndex=-1) or (not Assigned(LBTools.Selected)) then
     result:=nil
  else
     result:=LBTools.Selected.Data as TTeeCustomTool;
end;

end.
