{********************************************}
{   TDashBoard component                     }
{ Copyright (c) 1995-2020 by Steema Software }
{        All Rights Reserved                 }
{********************************************}
unit TeeDashBoard;
{$I TeeDefs.inc}

interface

Uses {$IFNDEF LINUX}
     {$IFNDEF FMX}
     Windows,
     {$ENDIF}
     {$ENDIF}

     Classes,

     {$IFDEF D16}
     Types,
     {$ENDIF}

     {$IFDEF FMX}
     FMX.Types, System.UITypes,
     {$ELSE}
     Controls, Graphics, ExtCtrls, Forms,
     {$ENDIF}

     {$IFDEF FMX}
     FMXTee.Engine, FMXTee.Chart, FMXTee.Series, FMXTee.Tools.SubChart
     {$ELSE}
     TeEngine, TeeSubChart, Chart, Series
     {$ENDIF}
     ;

type
  {$IFDEF D16}
  [ComponentPlatformsAttribute(TeeAllComponentPlatformIDs)]
  {$ENDIF}
  TDashBoard=class(TCustomChart)  // TCustomAxisPanel
  private
    ChartIndex : Integer;
    FContainer : TSubChartTool;

    procedure DrawChartCorners(const Chart : TChart);
    procedure DashBoardDragOver(Sender, Source: TObject; X, Y: Integer;
      State: TDragState; var Accept: Boolean);
    procedure DashBoardMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure ChartMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure DashBoardDragDrop(Sender, Source: TObject; X, Y: Integer);
    procedure DashBoardMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure DeletingChart(Sender:TSubChartTool; Item:TSubChart);
    procedure AddedChart(Sender:TSubChartTool; Item:TSubChart);
  protected
    IDontResetCanvas : Boolean;
    procedure Resize; override;
  public
    Constructor Create(AOwner: TComponent); override;
    Destructor Destroy; override;

    function AddChart(const AName:String=''):TChart;
    procedure ResetPositions;

    function GetCharts:TChartCollection;
    function ShowEditor:TModalResult;
  published
    { TCustomAxisPanel properties }
    property Tools;

    { TCustomTeePanelExtended properties }
    property BackImage;
    property BackImageMode;
    property Border;
    property BorderRound;
    property Emboss;
    property Gradient;
    property OnAfterDraw;

    { TCustomTeePanel properties }
    property BufferedDisplay default True;
    property MarginLeft;
    property MarginTop;
    property MarginRight;
    property MarginBottom;
    property MarginUnits;
    property Monochrome;
    property PrintProportional;
    property PrintResolution;
    property Shadow;
    property View3D;
    property View3DOptions;

    { TPanel properties }
    property Align;
    property BevelInner;
    property BevelOuter;
    property BevelWidth;

    property BorderWidth;
    property Color;
    property DragCursor;
    property DragMode;
    property Enabled;
    property ParentColor;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Visible;
    property Anchors;
    property AutoSize;
    property Constraints;
    property DragKind;
    {$IFNDEF LCL}
    property Locked;
    {$ENDIF}

    { TPanel events }
    property OnClick;
    property OnContextPopup;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property OnMouseWheel;
    property OnMouseWheelDown;
    property OnMouseWheelUp;
    property OnStartDrag;
    {$IFNDEF LCL}
    property OnCanResize;
    {$ENDIF}
    property OnConstrainedResize;
    property OnDockDrop;
    property OnDockOver;
    property OnEndDock;
    property OnGetSiteInfo;
    property OnStartDock;
    property OnUnDock;

    {$IFDEF D10}
    property OnMouseEnter;
    property OnMouseLeave;
    {$ENDIF}

    // TeeDashBoard properties
    property Charts:TChartCollection read GetCharts;
    property Container:TSubChartTool read FContainer;
  end;

implementation

uses
  SysUtils, Math,
  {$IFDEF FMX}
  FMXTee.Procs, FMXTee.Canvas, FMXTee.Store
  {$ELSE}
  TeeDashBoardEdit, TeeProcs, TeCanvas, TeeStore
  {$ENDIF}
  ;

{ TDashBoard }

Constructor TDashBoard.Create(AOwner: TComponent);
begin
  inherited;

  FContainer:=TSubChartTool.Create(Self);
  FContainer.ParentChart:=Self;
  FContainer.OnAdded:=AddedChart;
  FContainer.OnDeleting:=DeletingChart;

  Walls.Hide;
  Axes.Hide;

  with Gradient do
  begin
    Visible := True;
    EndColor := RGB(70,70,70);
    StartColor := RGB(127,127,127);
  end;

  Width:=700;
  Height:=500;

  OnDragOver:=DashBoardDragOver;
  OnMouseMove:=DashBoardMouseMove;
  OnDragDrop:=DashBoardDragDrop;
  OnMouseUp:=DashBoardMouseUp;
end;

Destructor TDashBoard.Destroy;
begin
  FContainer.Free;
  inherited;
end;

function TDashBoard.AddChart(const AName: String): TChart;
begin
  result:=FContainer.Charts.AddChart(AName);
end;

procedure TDashBoard.DeletingChart(Sender:TSubChartTool; Item:TSubChart);
begin
  ResetPositions;
end;

procedure TDashBoard.AddedChart(Sender:TSubChartTool; Item:TSubChart);
begin
  Item.Chart.View3D:=View3D;
  Item.Chart.OnDragOver:=DashBoardDragOver;

  // Temp, Tag property used, but we'd have to use other ?
  //FContainer.Charts[FContainer.Charts.Count-1].Index:=FContainer.Charts.Count-1;
  ResetPositions;
end;

procedure TDashBoard.DashBoardDragOver(Sender, Source: TObject; X, Y: Integer;
  State: TDragState; var Accept: Boolean);
var ARect: TRect;
begin
  Accept := (Source is TCustomChart);

  if Accept then
  begin
    ARect := TeeRect(TCustomChart(Source).Width, TCustomChart(Source).Height);

    Canvas.Brush.Style := bsClear;
    // TODO
    //Canvas.Rectangle (x- (ARect.Right div 2),y-(ARect.Bottom div 2),
    //  x + (ARect.Right div 2) , y +(ARect.Bottom div 2));
  end;
end;

{ TSubChartDash }

function TDashBoard.GetCharts: TChartCollection;
begin
  result:=FContainer.Charts;
end;

function TDashBoard.ShowEditor:TModalResult;
begin
  with TDashBoardEditor.Create(Self) do
  try
    SetTool(FContainer);

    Position:=poOwnerFormCenter;
    CBAllowDrag.Enabled:=False;
    CBAllowResize.Enabled:=False;

    result:=ShowModal;
  finally
    Free;
  end;
end;

procedure TDashBoard.ResetPositions;
var i, p,
    rows, cols,
    cHeight,
    nChart : Integer;
    Last : TCustomChart;
    tmp : TSubChart;
    tmpCount : Integer;
begin
  tmpCount:=FContainer.Charts.Count;

  if tmpCount>0 then
  begin
    Last:=FContainer.Charts.Last.Chart;

    Last.MarginLeft:=5;
    Last.MarginTop:=5;
    Last.MarginRight:=5;
    Last.MarginBottom:=5;
  end;

  if tmpCount=1 then
  begin
    tmp:=FContainer.Charts[0];

    tmp.Left:=0;
    tmp.Top:=0;
    tmp.Width:=FContainer.ParentChart.Width;
    tmp.Height:=FContainer.ParentChart.Height;
  end
  else
  begin
    if (tmpCount mod 2)<> 0 then
       rows:=((tmpCount-1) div 2)+1
    else
      if tmpCount>2 then
         rows:=(tmpCount div 2)
      else
         rows:=1;

    cols:=2;
    cHeight:=FContainer.ParentChart.Height div rows;
    nChart:=0;

    for i:=0 to rows -1 do
      for p:=0 to cols -1 do
      begin
        if nChart<tmpCount then
        begin
          tmp:=FContainer.Charts[nChart];

          tmp.Top:=i*cHeight;
          tmp.Height:=cHeight;

          if (rows=1) or ((tmpCount mod 2)=0) or (nChart < tmpCount-1) then
          begin
            tmp.Left:=p*(FContainer.ParentChart.Width div 2);
            tmp.Width:=FContainer.ParentChart.Width div 2;
          end
          else
          begin
            tmp.Left:=0;
            tmp.Width:=FContainer.ParentChart.Width;
            tmp.AllowResize:=True;
          end;
        end;

        Inc(nChart);
      end;
  end;
end;

procedure TDashBoard.Resize;
begin
  inherited;

  if FContainer.Charts.Count>1 then
     ResetPositions;
end;

procedure TDashBoard.DrawChartCorners(const Chart : TChart);
var R : TRect;
begin
  Chart.Canvas.Pen.Color := RGB(127,127,127);
  Chart.Canvas.Pen.Width := 3;

  R:=Chart.ChartRect;

  Canvas.Line(R.Left,R.Top,R.Left+15,R.Top);
  Canvas.Line(R.Left,R.Top,R.Left,R.Top+15);

  Canvas.Line(R.Right-15,R.Top,R.Right,R.Top);
  Canvas.Line(R.Right,R.Top,R.Right,R.Top+15);

  Canvas.Line(R.Left,R.Bottom,R.Left+15,R.Bottom);
  Canvas.Line(R.Left,R.Bottom,R.Left,R.Bottom-15);

  Canvas.Line(R.Right,R.Bottom,R.Right,R.Bottom-15);
  Canvas.Line(R.Right-15,R.Bottom,R.Right,R.Bottom);
end;

procedure TDashBoard.DashBoardMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
var i : integer;
    tmp : TSubChart;
begin
  for i :=0 to FContainer.Charts.Count-1 do
  begin
    tmp:=FContainer.Charts[i];

    if tmp.Clicked(x,y) then
    begin
      // TODO remove the modif of Gradient property and fix the repaint
      tmp.Chart.Gradient.Visible:=True;
      tmp.Chart.OnMouseDown:=ChartMouseDown;

      DrawChartCorners(tmp.Chart);
    end
    else
    begin
      tmp.Chart.Gradient.Visible:=False;
      tmp.Chart.OnMouseDown:=nil;
    end;
  end;
end;

procedure TDashBoard.ChartMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var i : Integer;
    tmp : TSubChart;
begin
 (Sender as TControl).BeginDrag(True);

 for i:=0 to FContainer.Charts.Count-1 do
 begin
   tmp:=FContainer.Charts[i];

   if tmp.Clicked(X,Y) then
   begin
     ChartIndex:=tmp.Index;
     tmp.Chart.CancelMouse:=True;
     CancelMouse:=True;
     break;
   end;
 end;
end;

procedure TDashBoard.DashBoardDragDrop(Sender, Source: TObject; X, Y: Integer);
var tmp   : TSubChart;
    i,idx : Integer;
    tmpStream : TMemoryStream;
    tmpChart : TCustomChart;
    tmpTop,
    tmpLeft,
    tmpW,
    tmpH : Integer;
begin
  idx:=0;

  if Source.ClassName <> 'TInnerChart'  then
  begin
    AddChart('MyChart'+IntToStr(Charts.Count));
    tmpW:=Charts[Charts.Count-1].Chart.Width;
    tmpH:=Charts[Charts.Count-1].Chart.Height;

    tmpTop:=Charts[Charts.Count-1].Chart.Top;
    tmpLeft:=Charts[Charts.Count-1].Chart.Left;

    tmpStream:=TMemoryStream.Create;
    try
      SaveChartToStream(TCustomChart(Source),tmpStream);

      tmpStream.Position :=0;
      tmpChart := Charts[Charts.Count-1].Chart as TCustomChart;
      LoadChartFromStream(TCustomChart(tmpChart),tmpStream);

      Charts[Charts.Count-1].Chart.Top:=tmpTop;
      Charts[Charts.Count-1].Chart.Left:=tmpLeft;
      Charts[Charts.Count-1].Chart.Width:=tmpW;
      Charts[Charts.Count-1].Chart.Height:=tmpH;
    finally
      tmpStream.Free;
    end;

//    Self.Charts[Self.Charts.Count-1].Chart.Assign(Source as TChart);
  end
  else
  begin
    if FContainer.Charts.Count>1 then
    begin
      tmp:=FContainer.Charts[ChartIndex];

      if FContainer.Charts.Count>0 then
        for i :=0 to FContainer.Charts.Count-1 do
          if FContainer.Charts[i].Clicked(X,Y) then
             idx:=i;

      Charts[idx].Index:=ChartIndex;
      tmp.Index:=idx;

      ResetPositions;
    end;
  end;
end;

procedure TDashBoard.DashBoardMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
//
end;

end.
