{********************************************}
{ TeeChart Tools Editor                      }
{ Copyright (c) 2000-2020 by Steema Software }
{********************************************}
unit TeeEditTools;
{$I TeeDefs.inc}

interface

uses {$IFNDEF LINUX}
     Windows, Messages,
     {$ENDIF}
     SysUtils, Classes,

     Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, Buttons, Menus,

     TeCanvas, TeEngine, Chart, TeePenDlg, TeeProcs;

type
  TFormTeeTools = class(TForm)
    LBTools: TListBox;
    PanelToolEditor: TPanel;
    PTop: TPanel;
    BAdd: TButton;
    BDelete: TButton;
    CBActive: TCheckBox;
    PBottom: TPanel;
    Splitter1: TSplitter;
    Panel2: TPanel;
    BMoveUp: TSpeedButton;
    BMoveDown: TSpeedButton;
    CBShowInEditor: TCheckBox;
    BClone: TSpeedButton;
    PopupMenu1: TPopupMenu;
    procedure LBToolsClick(Sender: TObject);
    procedure BDeleteClick(Sender: TObject);
    procedure CBActiveClick(Sender: TObject);
    procedure BAddClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure BMoveUpClick(Sender: TObject);
    procedure BMoveDownClick(Sender: TObject);
    procedure LBToolsDrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure CBShowInEditorClick(Sender: TObject);
    procedure BCloneClick(Sender: TObject);
    procedure PBottomClick(Sender: TObject);
  private
    { Private declarations }

    {$IFDEF TEEOCX}
    class function TeeAXGetUniqueName(const ATools:TChartTools; Const AStartName:String):String;
    {$ENDIF}

    Function CurrentTool:TTeeCustomTool;
    procedure DeleteForm;
    procedure EnableButtons;
    procedure FillAndSet;
    procedure FillTools;
    procedure SetPanelBottom;
    procedure SwapTool(A,B:Integer);

    {$IFNDEF LCL}
    procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
    {$ENDIF}
  protected

    OnAdded   : TNotifyEvent;
    OnDeleted : TNotifyEvent;

    function CloneTool(const Tool:TTeeCustomTool):TTeeCustomTool; virtual;
    function GetNewTool:TTeeCustomTool; virtual;
  public
    { Public declarations }
    Tools : TChartTools;

    class function AddNewTool(const ATools:TChartTools; AClass:TTeeCustomToolClass;
                              const ADefaultName:String):TTeeCustomTool;
    Procedure Reload;
  end;

implementation

{$IFNDEF LCL}
{$R *.DFM}
{$ELSE}
{$R *.lfm}
{$ENDIF}

Uses
  TeeConst, TeeToolsGallery, TeeEdiGene;

procedure TFormTeeTools.FillTools;
var t : Integer;
begin
  PBottom.Caption:='';

  With LBTools do
  begin
    Clear;

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

  CBActive.Enabled:=LBTools.Items.Count>0;

  if CBShowInEditor.Visible then
     CBShowInEditor.Enabled:=CBActive.Enabled;

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

procedure TFormTeeTools.DeleteForm;
begin
  if PanelToolEditor.ControlCount>0 then
     PanelToolEditor.Controls[0].Free;
end;

type
  TToolAccess=class(TTeeCustomTool);

procedure TFormTeeTools.LBToolsClick(Sender: TObject);
var tmpClass : TClass;
    tmp      : TForm;
    tmpSt    : String;
begin
  if (PanelToolEditor.ControlCount=0) or
     (PanelToolEditor.Controls[0].Tag<>ObjectToTag(CurrentTool)) then
  if CurrentTool<>nil then
  begin

    if PanelToolEditor.ControlCount>0 then
    begin
      if not TForm(PanelToolEditor.Controls[0]).CloseQuery then
         LBTools.ItemIndex:=Tools.IndexOf(TTeeCustomTool(PanelToolEditor.Controls[0].Tag));
    end;

    CBActive.Checked:=CurrentTool.Active;
    DeleteForm;

    tmpSt:=TToolAccess(CurrentTool).GetEditorClass;

    tmpClass:=TeeGetClass(tmpSt);

    if Assigned(tmpClass) then
    begin
      tmp:=TFormClass(tmpClass).Create(Self);

      TeeTranslateControl(tmp);

      tmp.Align:=alClient;
      AddFormTo(tmp,PanelToolEditor,CurrentTool);
    end;

    CBShowInEditor.Visible:=csDesigning in CurrentTool.ComponentState;

    if CBShowInEditor.Visible then
    begin
      CBShowInEditor.Checked:=CurrentTool.ShowInEditor;
      CBActive.Top:=3;
    end;

    EnableButtons;

    SetPanelBottom;
  end;
end;

procedure TFormTeeTools.BDeleteClick(Sender: TObject);
var tmp : Integer;
begin
  if (CurrentTool<>nil) and TeeYesNoDelete(CurrentTool.Description,Self) then
  begin
    tmp:=LBTools.ItemIndex;

    if Assigned(OnDeleted) then
       OnDeleted(CurrentTool);

    CurrentTool.Free;
    DeleteForm;
    FillTools;

    With LBTools do
    if tmp>1 then
       ItemIndex:=tmp-1
    else
    if Items.Count>0 then ItemIndex:=Items.Count-1;

    BDelete.Enabled:=LBTools.ItemIndex<>-1;
    BClone.Enabled:=BDelete.Enabled;

    if BDelete.Enabled then
       LBToolsClick(Self);
  end;
end;

procedure TFormTeeTools.CBActiveClick(Sender: TObject);
begin
  if CurrentTool<>nil then
     CurrentTool.Active:=CBActive.Checked;
end;

{$IFDEF TEEOCX}
class function TFormTeeTools.TeeAXGetUniqueName(const ATools:TChartTools; Const AStartName:String):String;
var t   : Integer;
    tmp : Integer;
Begin
  tmp:=0;

  for t:=0 to ATools.Count-1 do
  Begin
    if ATools.Items[t].Name=AStartName+TeeStr(tmp) then
       Inc(tmp)
    else
       break;
  end;

  result:=AStartName+TeeStr(tmp);
end;
{$ENDIF}

type
  TCustomAxisPanelAccess=class(TCustomAxisPanel);

function TFormTeeTools.GetNewTool:TTeeCustomTool;
var tmpGally : TTeeToolsGallery;
begin
  result:=nil;

  tmpGally:=TTeeToolsGallery.Create(Owner);
  try
    PositionToCenter(tmpGally);

    if tmpGally.ShowModal=mrOk then
       result:=AddNewTool(Tools,tmpGally.SelectedTool,TeeMsg_DefaultToolName);
  finally
    tmpGally.Free;
  end;
end;

class function TFormTeeTools.AddNewTool(const ATools:TChartTools; AClass:TTeeCustomToolClass;
                                    const ADefaultName:String):TTeeCustomTool;
var AOwner : TComponent;
    t      : Integer;
begin
  if Assigned(ATools.Owner) then
     AOwner:=TCustomAxisPanelAccess(ATools.Owner).GetDesignOwner
  else
     AOwner:=nil;

  // Runtime, Animations Owner is ParentChart
  for t:=0 to ATools.Count-1 do
  if ATools[t].Owner=ATools.Owner then
  begin
    AOwner:=ATools.Owner;
    break;
  end;

  result:=AClass.Create(AOwner);

  with result do
  begin
    ParentChart:=ATools.Owner;

    {$IFNDEF TEEOCX}
    Name:=TeeGetUniqueName(AOwner,ADefaultName);
    {$ELSE}
    //due to Owner=nil in ocx version
    Name:=TeeAXGetUniqueName(ParentChart.Tools,ADefaultName);
    {$ENDIF}
  end;
end;

procedure TFormTeeTools.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;

    {$IFDEF TEEOCX}
    if GetParentForm(Self)<>nil then
    {$ENDIF}
       LBTools.SetFocus;

    LBToolsClick(Self);
  end;
end;

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

procedure TFormTeeTools.FillAndSet;
begin
  FillTools;

  With LBTools do
  if Items.Count>0 then
  begin
    ItemIndex:=0;
    LBToolsClick(Self);
  end
  else EnableButtons;
end;

procedure TFormTeeTools.FormShow(Sender: TObject);
begin
  if not Assigned(Tools) then
     Tools:=TChartTools(Tag);

  if (not Assigned(Tools)) or
     (not Assigned(Tools.Owner)) or
     (not (csDesigning in Tools.Owner.ComponentState)) then
          CBActive.Top:=BAdd.Top+((BAdd.Height-CBActive.Height) div 2)
  else
  begin
    CBShowInEditor.Visible:=(csDesigning in Tools.Owner.ComponentState);
    CBShowInEditor.Enabled:=False;
  end;

  if Assigned(Tools) then
  begin
    if Assigned(Tools.Owner) then
       PBottom.Visible:=csDesigning in Tools.Owner.ComponentState;

    FillAndSet;
  end;

  PBottom.Cursor:=crHandPoint;

  TeeTranslateControl(Self);
end;

procedure TFormTeeTools.FormCreate(Sender: TObject);
begin
  TeeLoadArrowBitmaps(BMoveUp.Glyph,BMoveDown.Glyph);
end;

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

  LBTools.Invalidate;

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

  EnableButtons;
end;

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

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

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

Procedure TFormTeeTools.Reload;
begin
  if Assigned(Tools) and Assigned(Tools.Owner) then
     if Tools.Count<>LBTools.Items.Count then
        FillAndSet;

  if LBTools.ItemIndex<>-1 then
     LBToolsClick(Self);
end;

procedure TFormTeeTools.LBToolsDrawItem(Control: TWinControl;
  Index: Integer; Rect: TRect; State: TOwnerDrawState);
begin
  TeeDrawTool(LBTools,Index,Rect,State,TTeeCustomTool(LBTools.Items.Objects[Index]));
end;

{$IFNDEF LCL}
procedure TFormTeeTools.CMShowingChanged(var Message: TMessage);
begin
  inherited;
  if Assigned(Parent) then
     Parent.UpdateControlState;
end;
{$ENDIF}

procedure TFormTeeTools.CBShowInEditorClick(Sender: TObject);
begin
  if CurrentTool<>nil then
     CurrentTool.ShowInEditor:=CBShowInEditor.Checked;
end;

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

procedure TFormTeeTools.BCloneClick(Sender: TObject);
var tmpNew : TTeeCustomTool;
begin
  tmpNew:=CloneTool(CurrentTool);

  LBTools.ItemIndex:=LBTools.Items.AddObject(tmpNew.Description,tmpNew);
  LBToolsClick(Self);
end;

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

procedure TFormTeeTools.PBottomClick(Sender: TObject);
var tmp : String;
begin
  if CurrentTool<>nil then
  begin
    tmp:=CurrentTool.Name;

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

procedure EditTool(AOwner:TComponent; const ATool:TTeeCustomTool);
var tmpClass : TClass;
    tmpForm : TForm;
begin
  tmpClass:=TeeGetClass(TToolAccess(ATool).GetEditorClass);

  if Assigned(tmpClass) then
  begin
    tmpForm:=TFormClass(tmpClass).Create(AOwner);
    try
      tmpForm.Align:=alNone;
      PositionToCenter(tmpForm);

      tmpForm.Tag:=ObjectToTag(ATool);

      TeeTranslateControl(tmpForm);
      tmpForm.ShowModal;
    finally
      tmpForm.Free;
    end;
  end;
end;

initialization
  TeeEditToolProc:=EditTool;
finalization
  TeeEditToolProc:=nil;
end.
