{**********************************************}
{   TOrgSeries Organizational Charts           }
{   Copyright (c) 2011-2020 by Steema Software }
{**********************************************}
unit TeeOrgSeriesEditor;
{$I TeeDefs.inc}

interface

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

  StdCtrls, Controls, Buttons, ExtCtrls, ComCtrls, Forms, Graphics,

  TeCanvas, TeEngine, Chart, TeeTools, TeeConst, TeePenDlg, TeeComma, TeeProcs,
  TeeCustomShapeEditor, TeeStringsEditor, TeeMargins, TeeOrgSeries;

type
  TOrgSeriesEditor = class(TForm,ITeeEventListener)
    PageControl2: TPageControl;
    TabOptions: TTabSheet;
    TabNodes: TTabSheet;
    GroupBox1: TGroupBox;
    ScrollBar1: TScrollBar;
    ScrollBar2: TScrollBar;
    Panel3: TPanel;
    PageNodes: TPageControl;
    TabText: TTabSheet;
    Label3: TLabel;
    Label1: TLabel;
    Label9: TLabel;
    Memo1: TMemo;
    ComboAlign: TComboFlat;
    CBCursor: TComboFlat;
    Button1: TButton;
    Splitter1: TSplitter;
    SBAdd: TSpeedButton;
    SBDelete: TSpeedButton;
    TabSheet3: TTabSheet;
    CBAutoSize: TCheckBox;
    Label14: TLabel;
    Label15: TLabel;
    ECustWidth: TEdit;
    ECustHeight: TEdit;
    UDWidth: TUpDown;
    UDHeight: TUpDown;
    CBClip: TCheckBox;
    CBVisible: TCheckBox;
    Label2: TLabel;
    CBLineStyle: TComboFlat;
    Label4: TLabel;
    Label5: TLabel;
    TabMargins: TTabSheet;
    SpeedButton3: TSpeedButton;
    CBDefaultFormat: TCheckBox;
    TreeNodes: TTreeView;
    TabFormat: TTabSheet;
    TabLines: TTabSheet;
    procedure FormCreate(Sender: TObject);
    procedure ScrollBar1Change(Sender: TObject);
    procedure ScrollBar2Change(Sender: TObject);
    procedure Memo1Change(Sender: TObject);
    procedure ComboAlignChange(Sender: TObject);
    procedure CBCursorChange(Sender: TObject);
    procedure PageNodesChange(Sender: TObject);
    procedure SBAddClick(Sender: TObject);
    procedure LBNodesClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure SBDeleteClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ECustWidthChange(Sender: TObject);
    procedure ECustHeightChange(Sender: TObject);
    procedure CBAutoSizeClick(Sender: TObject);
    procedure CBClipClick(Sender: TObject);
    procedure CBVisibleClick(Sender: TObject);
    procedure CBLineStyleChange(Sender: TObject);
    procedure PageControl2Change(Sender: TObject);
    procedure SpeedButton3Click(Sender: TObject);
    procedure CBDefaultFormatClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    NodeEditor  : TFormTeeShape;
    MarginsForm : TMarginsEditor;

    IFormatEditor : TFormTeeShape;

    procedure AddListNodes(const Series:TCustomOrgSeries; Current:Integer);
    function CurrentItem:TOrgItem;
    procedure SetupEditor(const ASeries:TCustomOrgSeries);
    procedure ShowHideFormatTabs(DoShow:Boolean);
  protected
    Series      : TCustomOrgSeries;
    IChanging   : Boolean;

    function CurrentIndex:Integer;
    procedure TeeEvent(Event: TTeeEvent);
  protected
    procedure RefreshNode(Index:Integer);
    procedure SetItemProperties(Index:Integer); virtual;
  public
    { Public declarations }
  end;

implementation

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

uses
  TeeLegendScrollBar, TeeProCo, TeeMouseCursor;

type
  TPanelScrollBar=class(TTeeScrollBar)
  private
  protected
    function CurrentCount:Integer; override;
    function DeltaMain: Integer; override;
    function GetPosition:Integer; override;
    procedure SetParentChart(const Value: TCustomAxisPanel); override;
    procedure SetPosition(Value:Integer); override;
    function ShouldDraw(var R:TRect):Boolean; override;
    function TotalCount:Integer; override;
  public
//    Destructor Destroy; override;
    class Function Description:String; override;
    class Function LongDescription:String; override;
  end;

{
var h, v : TPanelScrollBar;

  v:=TPanelScrollBar.Create(Self);
  v.ParentChart:=Chart1;
  v.Horizontal:=False;

  h:=TPanelScrollBar.Create(Self);
  h.ParentChart:=Chart1;
  h.Horizontal:=True;
}

{ TPanelScrollBar }
function TPanelScrollBar.CurrentCount: Integer;
begin
  if Horizontal then
     result:=ParentChart.ChartWidth
  else
     result:=ParentChart.ChartHeight;
end;

function TPanelScrollBar.DeltaMain: Integer;
begin
  result:=0;
end;

class function TPanelScrollBar.Description: String;
begin
  result:='ScrollBar';
end;

{
Destructor TPanelScrollBar.Destroy;
begin
  inherited;
end;
}

function TPanelScrollBar.GetPosition: Integer;
begin
  if Horizontal then
     result:=ParentChart.View3DOptions.HorizOffset
  else
     result:=ParentChart.View3DOptions.VertOffset;
end;

class function TPanelScrollBar.LongDescription: String;
begin
  result:='ScrollBar';
end;

procedure TPanelScrollBar.SetParentChart(const Value: TCustomAxisPanel);
begin
  inherited;
end;

procedure TPanelScrollBar.SetPosition(Value: Integer);
begin
  if Horizontal then
     ParentChart.View3DOptions.HorizOffset:=Value
  else
     ParentChart.View3DOptions.VertOffset:=Value;

  inherited;
end;

function TPanelScrollBar.ShouldDraw(var R: TRect): Boolean;
begin
  R:=ParentChart.ChartBounds;

  if Horizontal then
  begin
    Dec(R.Bottom, Size);
    Dec(R.Right, Size);
  end
  else
  begin
    Dec(R.Bottom, Size-1);
  end;

  result:=True;
end;

function TPanelScrollBar.TotalCount: Integer;
begin
  result:=CurrentCount+10;
end;

procedure TOrgSeriesEditor.FormCreate(Sender: TObject);
begin
  PageNodes.ActivePage:=TabText;
end;

procedure TOrgSeriesEditor.ScrollBar1Change(Sender: TObject);
begin
  Series.Spacing.Horizontal:=ScrollBar1.Position;
end;

procedure TOrgSeriesEditor.ScrollBar2Change(Sender: TObject);
begin
  Series.Spacing.Vertical:=ScrollBar2.Position;
end;

procedure TOrgSeriesEditor.Memo1Change(Sender: TObject);
begin
  if not IChanging then
  begin
    CurrentItem.Text:=Memo1.Lines.Text;
    Series.ManualData:=True;
  end;
end;

procedure TOrgSeriesEditor.ComboAlignChange(Sender: TObject);
begin
  if not IChanging then
  begin
    CBDefaultFormat.Checked:=False;
    CurrentItem.Format.TextAlignment:=TAlignment(ComboAlign.ItemIndex);
    Series.ManualData:=True;
  end;
end;

procedure TOrgSeriesEditor.CBCursorChange(Sender: TObject);
begin
  if not IChanging then
  begin
    CBDefaultFormat.Checked:=False;

    with CurrentItem.Format do
         Cursor:=TeeSetCursor(Cursor,CBCursor.CurrentItem);
  end;
end;

procedure TOrgSeriesEditor.PageNodesChange(Sender: TObject);
begin
  if Assigned(NodeEditor) then
     NodeEditor.PC1Change(PageNodes);
end;

procedure TOrgSeriesEditor.SBAddClick(Sender: TObject);
var tmp : Integer;
begin
  if TreeNodes.Selected=nil then
     tmp:=-1
  else
     tmp:=CurrentItem.Index;

  AddListNodes(Series,Series.Add('#'+IntToStr(Series.Count),tmp));
  Series.ManualData:=True;
end;

type
  TOrgItemAccess=class(TOrgItem);

procedure TOrgSeriesEditor.SetItemProperties(Index:Integer);
begin
  CBDefaultFormat.Checked:=not TOrgItemAccess(CurrentItem).HasFormat;

  with TOrgItemAccess(CurrentItem) do
  begin
    CBDefaultFormatClick(Self);

    Memo1.Lines.Text:=Text;
    UDWidth.Position:=Width;
    UDHeight.Position:=Height;

    with ActiveFormat do
    begin
      CBVisible.Checked:=Visible;
      CBAutoSize.Checked:=AutoSize;
      CBClip.Checked:=ClipText;
      ComboAlign.ItemIndex:=Ord(TextAlignment);
      TeeFillCursors(CBCursor,Cursor);
    end;
  end;
end;

procedure TOrgSeriesEditor.LBNodesClick(Sender: TObject);
//var t : Integer;
begin
  { Highlight selected node:
  with Series do
  for t:=0 to Count-1 do
      Items[t].Format.Gradient.Visible:= t = CurrentIndex;
  }

  IChanging:=True;
  try
    SetItemProperties(CurrentIndex);
  finally
    IChanging:=False;
  end;

  SBAdd.Enabled:=True;
  SBDelete.Enabled:=True;

  if not PageNodes.Visible then
     PageNodes.Show;
end;

procedure TOrgSeriesEditor.Button1Click(Sender: TObject);
begin
  TeeEditStrings(Self,Memo1.Lines)
end;

procedure TOrgSeriesEditor.SBDeleteClick(Sender: TObject);
var tmp : Integer;
begin
  tmp:=CurrentIndex;
  Series.Delete(tmp);
  Series.ManualData:=True;
  AddListNodes(Series,tmp-1);
end;

function TOrgSeriesEditor.CurrentIndex:Integer;
begin
  result:=Integer(TreeNodes.Selected.Data);
end;

function TOrgSeriesEditor.CurrentItem:TOrgItem;
begin
  result:=Series.Items[CurrentIndex];
end;

procedure TOrgSeriesEditor.RefreshNode(Index:Integer);
var t : Integer;
begin
  for t:=0 to TreeNodes.Items.Count-1 do
  if Integer(TreeNodes.Items[t].Data)=Index then
  begin
    TreeNodes.Selected:=TreeNodes.Items[t];
    LBNodesClick(Self);
    Break;
  end;
end;

type
  TTeePanelAccess=class(TCustomTeePanel);

procedure TOrgSeriesEditor.SetupEditor(const ASeries:TCustomOrgSeries);
begin
  Series:=ASeries;

  if Assigned(Series) then
  begin
    ScrollBar1.Position:=Series.Spacing.Horizontal;
    ScrollBar2.Position:=Series.Spacing.Vertical;

    if Series is TOrgSeries then
       CBLineStyle.ItemIndex:=Ord(TOrgSeries(Series).LineStyle);

    AddListNodes(Series,0);

    if Assigned(Series.ParentChart) then
       TTeePanelAccess(Series.ParentChart).AddListener(Self);
  end;
end;

procedure TOrgSeriesEditor.AddListNodes(const Series:TCustomOrgSeries; Current:Integer);

  procedure AddNodes(const Node:TTreeNode=nil; Parent:Integer=-1);

    function FirstLine(const s:String):String;
    var i : Integer;
    begin
      i:=Pos(TeeLineSeparator,s);
      if i=0 then
         result:=s
      else
         result:=Copy(s,1,i-1);
    end;

  var t : Integer;
  begin
    with Series do
    for t:=0 to Min(Count,Items.Count)-1 do
    if NotMandatoryValueList.Value[t]=Parent then
       AddNodes(TreeNodes.Items.AddChildObject(Node,FirstLine(XLabel[t]),Pointer(t)),t);
  end;

begin
  TreeNodes.Items.Clear;
  AddNodes;

  TreeNodes.Enabled:=TreeNodes.Items.Count>0;
  PageNodes.Enabled:=TreeNodes.Enabled;

  if Series.Count=0 then
     PageNodes.Hide
  else
  if (Current<>-1) and (TreeNodes.Items.Count>0) then
  begin
    TreeNodes.Items[0].Expanded:=True;
    RefreshNode(Current);
  end;

  SBDelete.Enabled:=Series.Count>0;
end;

procedure TOrgSeriesEditor.FormShow(Sender: TObject);
begin
  Series:=TOrgSeries(Tag);
  SetupEditor(Series);
end;

procedure TOrgSeriesEditor.ECustWidthChange(Sender: TObject);
begin
  if (not IChanging) and (CurrentItem.Width<>UDWidth.Position) then
  begin
    CurrentItem.Width:=UDWidth.Position;
    CBAutoSize.Checked:=False;
  end;
end;

procedure TOrgSeriesEditor.ECustHeightChange(Sender: TObject);
begin
  if (not IChanging) and (CurrentItem.Height<>UDHeight.Position) then
  begin
    CurrentItem.Height:=UDHeight.Position;
    CBAutoSize.Checked:=False;
  end;
end;

procedure TOrgSeriesEditor.CBAutoSizeClick(Sender: TObject);
begin
  if not IChanging then
  begin
    CBDefaultFormat.Checked:=False;
    CurrentItem.Format.AutoSize:=CBAutoSize.Checked;
  end;
end;

procedure TOrgSeriesEditor.CBClipClick(Sender: TObject);
begin
  if not IChanging then
  begin
    CBDefaultFormat.Checked:=False;
    CurrentItem.Format.ClipText:=CBClip.Checked;
  end;
end;

procedure TOrgSeriesEditor.CBVisibleClick(Sender: TObject);
begin
  if not IChanging then
  begin
    CBDefaultFormat.Checked:=False;

    CurrentItem.Format.Visible:=CBVisible.Checked;
    Series.ManualData:=True;
  end;
end;

procedure TOrgSeriesEditor.CBLineStyleChange(Sender: TObject);
begin
  TOrgSeries(Series).LineStyle:=TOrgLineStyle(CBLineStyle.ItemIndex);
end;

procedure TOrgSeriesEditor.PageControl2Change(Sender: TObject);
begin
  if Assigned(Series) and (Series.Count<>TreeNodes.Items.Count) then
     AddListNodes(Series,0);

  if PageControl2.ActivePage=TabFormat then
  begin
    if not Assigned(IFormatEditor) then
    begin
      IFormatEditor:=TFormTeeShape.CreateForm(Self,Series.Format);
      IFormatEditor.Align:=alClient;
      AddFormTo(IFormatEditor,TabFormat);
    end;
  end
  else
  if (PageControl2.ActivePage=TabLines) and (TabLines.ControlCount=0) then
     TPenDialog.InsertForm(Series.Pen,TabLines);
end;

procedure TOrgSeriesEditor.SpeedButton3Click(Sender: TObject);
begin
  CBDefaultFormat.Checked:=False;

  with CurrentItem.Format do
       Cursor:=TMouseCursorEdit.Choose(Series,Cursor);
end;

procedure TOrgSeriesEditor.ShowHideFormatTabs(DoShow:Boolean);
var t : Integer;
begin
  if not Assigned(NodeEditor) then
  begin
    NodeEditor:=InsertTeeObjectForm(PageNodes,nil);

    MarginsForm:=TMarginsEditor.Create(Self);
    AddFormTo(MarginsForm,TabMargins);
  end;

  for t:=2 to PageNodes.PageCount-1 do
      PageNodes.Pages[t].TabVisible:=DoShow;
end;

procedure TOrgSeriesEditor.CBDefaultFormatClick(Sender: TObject);
begin
  if not IChanging then
     Series.ManualData:=True;

  if CBDefaultFormat.Checked then
  begin
    CurrentItem.RemoveFormat;
    ShowHideFormatTabs(False);
  end
  else
  begin
    ShowHideFormatTabs(True);

    NodeEditor.RefreshControls(CurrentItem.Format);
    MarginsForm.RefreshControls(CurrentItem.Format.Margins);
  end;
end;

procedure TOrgSeriesEditor.TeeEvent(Event: TTeeEvent);
begin
  if (Event is TTeeSeriesEvent) and
     (TTeeSeriesEvent(Event).Event=seDataChanged) then
  begin
    if Assigned(Series) then
       AddListNodes(Series,0);
  end;
end;

procedure TOrgSeriesEditor.FormDestroy(Sender: TObject);
begin
  if Assigned(Series) and Assigned(Series.ParentChart) then
     TTeePanelAccess(Series.ParentChart).Listeners.Remove(Self);
end;

initialization
  RegisterClass(TOrgSeriesEditor);
end.

