{********************************************}
{   TeeChart Pie Series Tool                 }
{ Copyright (c) 2001-2020 by Steema Software }
{        All Rights Reserved                 }
{********************************************}
unit TeePieTool;
{$I TeeDefs.inc}

interface

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

  {$IFDEF FMX}
  System.UITypes, FMX.Types,
  FMXTee.Canvas, FMXTee.Engine, FMXTee.Chart, FMXTee.Series, FMXTee.Tools,
  FMXTee.Animate
  {$ELSE}

  {$IFDEF D16}
  System.UITypes,
  {$ENDIF}

  {$IFDEF D17}
  System.UIConsts,
  {$ENDIF}

  Controls, Graphics,

  TeeTools, TeCanvas, TeEngine, Chart, Series, TeeAnimate
  {$ENDIF}
  ;

type
  TPieToolStyle=(ptFocus,ptExplode);

  TPieTool=class(TTeeCustomToolSeries)
  private
    FExplode : TNumberAnimation;
    FStyle   : TPieToolStyle;

    ISeries : TPieSeries;
    ISlice  : Integer;

    procedure ExplodeSetValue(Sender:TTeeAnimation; const Value:Double);
    function GetExplode: TNumberAnimation;
  protected
    Procedure ChartMouseEvent( AEvent: TChartMouseEvent;
                               Button:TMouseButton;
                               Shift: TShiftState; X, Y: Integer); override;
    Procedure FocusSlice(ValueIndex:Integer; Focused:Boolean; ASeries:TPieSeries=nil);
    class Function GetEditorClass:String; override;
  public
    Constructor Create(AOwner:TComponent); override;

    class Function Description:String; override;
    class Function LongDescription:String; override;

    property ExplodeAnimation:TNumberAnimation read GetExplode;
    property Slice:Integer read ISlice;
  published
    property Active;
    property Pen;
    property Series;
    property Style:TPieToolStyle read FStyle write FStyle default ptFocus;
  end;

implementation

Uses
  {$IFDEF FMX}
  {$IFDEF D17}
  System.UIConsts,
  {$ENDIF}
  FMXTee.Constants, FMXTee.Procs, FMXTee.ProConstants
  {$ELSE}
  TeeConst, TeeProcs, TeeProCo
  {$ENDIF}
  ;

{$IFDEF FMX}
const
  clWhite=claWhite;
  clBlack=claBlack;
{$ENDIF}

type
  TTeePenAccess=class(TTeePen);

{ TPieTool }
Constructor TPieTool.Create(AOwner: TComponent);
begin
  inherited;

  FStyle:=ptFocus;
  ISlice:=-1;

  Pen.Width:=4;
  TTeePenAccess(Pen).DefaultWidth:=4;

  Pen.Style:=psSolid;
end;

type
  TPieSeriesAccess=class(TPieSeries);

Procedure TPieTool.FocusSlice(ValueIndex:Integer; Focused:Boolean; ASeries:TPieSeries=nil);
var tmpColor : TColor;
begin
  if not Assigned(ASeries) then
     ASeries:=Series as TPieSeries;

  if Style=ptExplode then
  begin
    if ExplodeAnimation.Animate.Playing then
       ExplodeAnimation.Animate.Stop;

    ExplodeAnimation.StartValue:=ASeries.ExplodedSlice[ValueIndex];

    if Focused then
       ExplodeAnimation.EndValue:=50
    else
       ExplodeAnimation.EndValue:=0;

    ExplodeAnimation.Tag:=ValueIndex;
    ExplodeAnimation.Animate.Play;
  end
  else
  begin
    if not Focused then
       ParentChart.Repaint
    else
    begin
      with ASeries.ParentChart.Canvas do
      begin
        {$IFDEF FMX}
        // BeginScene must be called before setting Brush.Style=bsClear
        ReferenceCanvas.BeginScene;
        ReferenceCanvas.SetMatrix(ParentChart.AbsoluteMatrix);
        {$ENDIF}

        Brush.Style:=bsClear;

        tmpColor:=Self.Pen.Color;

        if ASeries.ValueColor[ValueIndex]=Self.Pen.Color then
           if Self.Pen.Color=clBlack then tmpColor:=clWhite
                                     else tmpColor:=clBlack;

        AssignVisiblePenColor(Self.Pen,tmpColor);
      end;

      TPieSeriesAccess(ASeries).DrawPie(ValueIndex);

      {$IFDEF FMX}
      ASeries.ParentChart.Canvas.ReferenceCanvas.EndScene;
      {$ENDIF}
    end;
  end;
end;

procedure TPieTool.ChartMouseEvent(AEvent: TChartMouseEvent;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

  function ClickedPie(out ASlice:Integer):TPieSeries;

    function DoClicked(ASeries:TPieSeries):Boolean;
    begin
      if ASeries.Visible then
      begin
        ASlice:=ASeries.CalcClickedPie(X,Y);

        if ASlice=TeeNoPointClicked then
           ASlice:=ASeries.CalcClickedPie(X,Y,False);

        result:=ASlice<>TeeNoPointClicked;
      end
      else
        result:=False;
    end;

  var tmp : TChartSeries;
      t   : Integer;
  begin
    result:=nil;

    if Assigned(Series) and (Series is TPieSeries) then
    begin
      if DoClicked(TPieSeries(Series)) then
         result:=TPieSeries(Series);
    end
    else
    begin
      for t:=0 to ParentChart.SeriesCount-1 do
      begin
        tmp:=ParentChart[t];

        if tmp is TPieSeries then
           if DoClicked(TPieSeries(tmp)) then
           begin
             result:=TPieSeries(tmp);
             break;
           end;
      end;
    end;
  end;

var tmpSeries : TPieSeries;
    tmpSlice  : Integer;
begin
  if AEvent=cmeMove then
  begin
    tmpSeries:=ClickedPie(tmpSlice);

    if Assigned(ISeries) then
       if (ISeries<>tmpSeries) or (ISlice<>tmpSlice) then
       begin
         FocusSlice(ISlice,False,ISeries);
         tmpSeries:=ClickedPie(tmpSlice);
       end;

    if (ISeries<>tmpSeries) or (ISlice<>tmpSlice) then
    begin
      ISeries:=tmpSeries;
      ISlice:=tmpSlice;

      if Assigned(ISeries) and (ISlice<>TeeNoPointClicked) then
         FocusSlice(ISlice,True,ISeries);
    end;
  end;
end;

class function TPieTool.Description: String;
begin
  result:=TeeMsg_PieTool;
end;

class function TPieTool.GetEditorClass: String;
begin
  result:='TPieToolEditor';
end;

class function TPieTool.LongDescription: String;
begin
  result:=TeeMsg_PieToolDesc;
end;

procedure TPieTool.ExplodeSetValue(Sender:TTeeAnimation; const Value:Double);
begin
  if Assigned(ISeries) then
     ISeries.ExplodedSlice[Sender.Tag]:=Round(Value);
end;

function TPieTool.GetExplode: TNumberAnimation;
begin
  if not Assigned(FExplode) then
  begin
    FExplode:=TNumberAnimation.Create(Self);
    FExplode.Duration:=300;
    FExplode.KeepEndValue:=True;
    FExplode.OnSetValue:=ExplodeSetValue;
    FExplode.Animate:=TTeeAnimate.Create(Self);
  end;

  result:=FExplode;
end;

initialization
  RegisterTeeTools([TPieTool]);
finalization
  UnRegisterTeeTools([TPieTool]);
end.
