{**********************************************}
{   TeeChart Legend Palette tool               }
{   Copyright (c) 2006-2020 by Steema Software }
{**********************************************}
unit TeeLegendPalette;
{$I TeeDefs.inc}

interface

// This tool displays a legend made with colors from a 3D series palette.

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

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

  {$IFDEF FMX}
  FMX.Types,
  {$ELSE}
  Controls, Graphics,
  {$ENDIF}

  {$IFDEF D6}
  Types,
  {$ENDIF}

  {$IFDEF FMX}
  FMXTee.Canvas, FMXTee.Procs, FMXTee.Engine, FMXTee.Chart, FMXTee.Tools,
  FMXTee.Series.Surface
  {$ELSE}
  TeCanvas, TeeProcs, TeEngine, Chart, TeeTools, TeeSurfa
  {$ENDIF}
  ;

const
  DefaultPanelColor={$IFDEF FMX}claWhite{$ELSE}clWhite{$ENDIF};

type
  TLegendPointer=class(TSeriesPointer)
  private
    FValue : Double;
    procedure SetValue(const AValue:Double);
  published
    property Value:Double read FValue write SetValue;
  end;

  TLegendPaletteAxis=(laDefault,laOther,laBoth);

  TLegendPaletteTool=class(TTeeCustomToolSeries)
  private
    FChart    : TCustomChart;
    FHeight   : Integer;
    FLeft     : Integer;
    FPointer  : TLegendPointer;
    FPositionUnits: TTeeUnits;
    FSmooth   : Boolean;
    FTop      : Integer;
    FVertical : Boolean;
    FWidth    : Integer;

    function GetAxis: TLegendPaletteAxis;
    function GetBorder: TChartHiddenPen;
    function GetColor: TColor;
    function GetEmboss: TTeeEmboss;
    function GetGradient: TChartGradient;
    function GetInverted: Boolean;
    function GetShadow: TTeeShadow;
    function GetTitle:TChartTitle;
    function GetTransp: Boolean;
    procedure SetAxis(const Value: TLegendPaletteAxis);
    procedure SetBorder(const Value: TChartHiddenPen);
    procedure SetColor(const Value: TColor);
    procedure SetEmboss(const Value: TTeeEmboss);
    procedure SetGradient(const Value: TChartGradient);
    procedure SetHeight(const Value: Integer);
    procedure SetInverted(const Value: Boolean);
    procedure SetLeft(const Value: Integer);
    procedure SetPositionUnits(const Value: TTeeUnits);
    procedure SetShadow(const Value: TTeeShadow);
    procedure SetSmooth(const Value: Boolean);
    procedure SetTitle(const Value: TChartTitle);
    procedure SetTop(const Value: Integer);
    procedure SetTransp(const Value: Boolean);
    procedure SetVertical(const Value: Boolean);
    procedure SetWidth(const Value: Integer);
    function GetPointer: TLegendPointer;
    function GetFoot: TChartTitle;
    function GetSubFoot: TChartTitle;
    function GetSubTitle: TChartTitle;
    procedure SetFoot(const Value: TChartTitle);
    procedure SetSubFoot(const Value: TChartTitle);
    procedure SetSubTitle(const Value: TChartTitle);
  protected
    procedure ChartEvent(AEvent:TChartToolEvent); override;
    Procedure ChartMouseEvent( AEvent: TChartMouseEvent;
                               Button:TMouseButton;
                               Shift: TShiftState; X, Y: Integer); override;
    class function GetEditorClass: String; override;
    procedure SetParentChart(const Value: TCustomAxisPanel); override;
    procedure SetSeries(const Value: TChartSeries); override;
  public
    Constructor Create(AOwner:TComponent); override;
    Destructor Destroy; override;

    procedure Assign(Source:TPersistent); override;

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

    property Chart:TCustomChart read FChart;
    property Pointer:TLegendPointer read GetPointer;
  published
    property Active;
    property Axis:TLegendPaletteAxis read GetAxis write SetAxis default laBoth;
    property Border:TChartHiddenPen read GetBorder write SetBorder;
    property Color:TColor read GetColor write SetColor default DefaultPanelColor;
    property Emboss:TTeeEmboss read GetEmboss write SetEmboss;
    property Foot:TChartTitle read GetFoot write SetFoot;
    property Gradient:TChartGradient read GetGradient write SetGradient;
    property Height:Integer read FHeight write SetHeight default 200;
    property Inverted:Boolean read GetInverted write SetInverted default False;
    property Left:Integer read FLeft write SetLeft default 10;
    property Pen;
    property PositionUnits:TTeeUnits read FPositionUnits write SetPositionUnits
                                                         default muPixels;
    property Series;
    property Shadow:TTeeShadow read GetShadow write SetShadow;
    property Smooth:Boolean read FSmooth write SetSmooth default False;
    property SubFoot:TChartTitle read GetSubFoot write SetSubFoot;
    property SubTitle:TChartTitle read GetSubTitle write SetSubTitle;
    property Title:TChartTitle read GetTitle write SetTitle;
    property Top:Integer read FTop write SetTop default 10;
    property Transparent:Boolean read GetTransp write SetTransp default False;
    property Vertical:Boolean read FVertical write SetVertical default True;
    property Width:Integer read FWidth write SetWidth default 100;
  end;

implementation

uses
  // Referencing TeePolarGrid here is not ideal.
  // This usage should be removed, adding an interface ISupportsPalette or similar
  // to TPolarGridSeries.
  // Then discovering this interface at TLegendPaletteTool.ChartEvent.

  {$IFDEF FMX}
  FMXTee.Series.PolarGrid, FMXTee.ProConstants, System.TypInfo
  {$ELSE}
  TeePolarGrid, TeeProCo, TypInfo, Printers
  {$ENDIF}
  ;

type
  TPaletteSeries=class(TChartSeries)
  private
    ITool     : TLegendPaletteTool;
  protected
    procedure DrawAllValues; override;
    procedure DrawValue(ValueIndex:Integer); override;
  end;

  TPaletteChart=class(TChart)
  private
    IParent : TCustomAxisPanel;
  public
    procedure Invalidate; override;
  end;

{ TPaletteChart }

procedure TPaletteChart.Invalidate;
begin
  if Assigned(IParent) then
     IParent.Invalidate;
end;

{ TLegendPaletteTool }

Constructor TLegendPaletteTool.Create(AOwner: TComponent);

  procedure PrepareAxis(const Axis:TChartAxis);
  begin
    Axis.Axis.Width:=1;
    Axis.Axis.EndStyle:=esSquare;
    Axis.Grid.Hide;
  end;

const
  DefaultMargin=8;

var tmp : TPaletteSeries;
begin
  inherited;

  FChart:=TPaletteChart.Create(nil);
  with FChart do
  begin
    BufferedDisplay:=False;
    Zoom.Allow:=False;
    AllowPanning:=pmNone;
    View3D:=False;
    ClipPoints:=False;
    Color:=DefaultPanelColor;
    BevelOuter:=bvNone;

    MarginLeft:=DefaultMargin;
    MarginRight:=DefaultMargin;
    MarginTop:=DefaultMargin;
    MarginBottom:=DefaultMargin;

    PrepareAxis(Axes.Left);
    PrepareAxis(Axes.Top);
    PrepareAxis(Axes.Right);
    PrepareAxis(Axes.Bottom);

    with Axes do
    begin
      Bottom.Visible:=False;
      Top.Visible:=False;
    end;

    Legend.Hide;

    tmp:=TPaletteSeries.Create(Self);
    tmp.CalcVisiblePoints:=False;
    tmp.ITool:=Self;
    tmp.VertAxis:=aBothVertAxis;
    tmp.HorizAxis:=aBothHorizAxis;
    AddSeries(tmp);
  end;

  FPositionUnits:=muPixels;
  FTop:=10;
  FLeft:=10;
  FWidth:=100;
  FHeight:=200;

  FVertical:=True;
end;

Destructor TLegendPaletteTool.Destroy;
begin
  FPointer.Free;
  FreeAndNil(FChart);
  inherited;
end;

procedure TLegendPaletteTool.Assign(Source: TPersistent);
begin
  if Source is TLegendPaletteTool then
  with TLegendPaletteTool(Source) do
  begin
    Self.FLeft:=FLeft;
    Self.FTop:=FTop;
    Self.FWidth:=FWidth;
    Self.FHeight:=FHeight;
    Self.FChart.Assign(FChart); // <--- panel, title, foot, etc
    Self.Pointer.Assign(Pointer);
    Self.FSmooth:=FSmooth;
    Self.Inverted:=Inverted;
    Self.Vertical:=FVertical;
  end;

  inherited;
end;

type
  TCustom3DAccess=class(TCustom3DPaletteSeries);
  TLevelAccess=class(TContourLevel);
  TTPrintPanel=class(TCustomTeePanel);

procedure TLegendPaletteTool.ChartEvent(AEvent: TChartToolEvent);

  procedure AddPoint(const X,Y:TChartValue; const AColor:TColor);
  begin
    with FChart[0] do
    if Self.Vertical then
       AddXY(X,Y,'',AColor)
    else
       AddXY(Y,X,'',AColor);
  end;

var tmp      : TCustom3DPaletteSeries;
    t        : Integer;
    tmpValue : TChartValue;
    tmpColor : TColor;
    tmpR     : TRect;
    RelLeft, RelTop, RelRight, RelBottom : Double;  //relative panel pos
    tmpPrintRect : TRect;
    tmpPRWidth,tmpPRHeight : Integer;
begin
  inherited;

  if AEvent=cteAfterDraw then
  begin
    FChart[0].BeginUpdate;

    FChart[0].Clear;

    if Assigned(Series) then
    begin
      if Series is TCustom3DPaletteSeries then
      begin
        tmp:=TCustom3DPaletteSeries(Series);

        // Special case. Pending to avoid checking for TContourSeries.
        if Series is TContourSeries then
          for t:=0 to TContourSeries(tmp).Levels.Count-1 do
          begin
            tmpValue:=TContourSeries(tmp).Levels[t].UpToValue;
            tmpColor:=TLevelAccess(TContourSeries(tmp).Levels[t]).InternalColor;
            AddPoint(t,tmpValue,tmpColor);
          end
        else
        for t:=0 to Length(tmp.Palette)-1 do
        begin
          tmpValue:=tmp.Palette[t].UpToValue;

          if tmp.UsePalette then
             tmpColor:=tmp.Palette[t].Color
          else
             tmpColor:=TCustom3DAccess(tmp).GetValueColorValue(tmpValue);

          AddPoint(t,tmpValue,tmpColor);
        end;
      end
      else
      if Series is TPolarGridSeries then
         for t:=0 to Length(TPolarGridSeries(Series).Palette.Palette)-1 do
         begin
           tmpValue:=TPolarGridSeries(Series).Palette.Palette[t].UpToValue;
           tmpColor:=TPolarGridSeries(Series).GetCellColor(tmpValue);
           AddPoint(t,tmpValue,tmpColor);
         end;
    end;

    ParentChart.Canvas.UnClipRectangle;
    FChart[0].Pen.Assign(Pen);

    if FPositionUnits=muPercent then
    begin
      tmpR.Left:=Round(FLeft*ParentChart.Width*0.01);
      tmpR.Top:=Round(FTop*ParentChart.Height*0.01);
      RelLeft := FLeft/100;
      RelTop := FTop/100;
      RelRight := RelLeft+((FWidth/ParentChart.Width));
      RelBottom := RelTop+((FHeight/ParentChart.Height));
    end
    else
    begin
      tmpR := TeeRect(FLeft,FTop,FLeft+FWidth,FTop+FHeight);

      RelLeft := FLeft/ParentChart.Width;
      RelTop := FTop/ParentChart.Height;
      RelRight := (FLeft+FWidth)/ParentChart.Width;
      RelBottom := (FTop+FHeight)/ParentChart.Height;
    end;

    tmpR.Right:=tmpR.Left+FWidth;
    tmpR.Bottom:=tmpR.Top+FHeight;

    FChart[0].EndUpdate;
    if ParentChart.Printing and TTPrintPanel(ParentChart).IsPrinterCanvas then
    Begin
      if TTPrintPanel(ParentChart).ICustomPrinterRect.Right-TTPrintPanel(ParentChart).ICustomPrinterRect.Left>0 then
      Begin
        tmpPrintRect:=TTPrintPanel(ParentChart).ICustomPrinterRect;
        TTPrintPanel(ParentChart).ICustomPrinterRect := TeeRect(0,0,0,0);
      End
      else
        tmpPrintRect:=ParentChart.ChartPrintRect;

      tmpPRWidth := Round(tmpPrintRect.Right-tmpPrintRect.Left);
      tmpPRHeight := Round(tmpPrintRect.Bottom-tmpPrintRect.Top);

      tmpR.Left := Round(tmpPrintRect.Left + (RelLeft * (tmpPRWidth)));
      tmpR.Top := Round(tmpPrintRect.Top + (RelTop * (tmpPRHeight)));
      tmpR.Right := Round(tmpPrintRect.Left + (RelRight * (tmpPRWidth)));
      tmpR.Bottom := Round(tmpPrintRect.Top + (RelBottom * (tmpPRHeight)));
    end;

    FChart.Draw(ParentChart.Canvas.ReferenceCanvas,tmpR);

    // Draw indicator, if visible:
    if Assigned(FPointer) and FPointer.Visible then
    begin
      FPointer.PrepareCanvas(FChart.Canvas, FPointer.Color);

      if FVertical then
         FPointer.Draw(FChart.ChartXCenter, FChart.Axes.Left.CalcPosValue(FPointer.Value))
      else
         FPointer.Draw(FChart.Axes.Bottom.CalcPosValue(FPointer.Value), FChart.ChartYCenter);
    end;
  end;
end;

class function TLegendPaletteTool.Description: String;
begin
  result:=TeeMsg_LegendPalette;
end;

class function TLegendPaletteTool.LongDescription: String;
begin
  result:=TeeMsg_LegendPaletteDesc;
end;

class function TLegendPaletteTool.GetEditorClass: String;
begin
  result:='TLegendPaletteEditor'; // Do not localize
end;

function TLegendPaletteTool.GetTitle:TChartTitle;
begin
  result:=FChart.Title;
end;

procedure TLegendPaletteTool.SetTitle(const Value: TChartTitle);
begin
  FChart.Title:=Value;
end;

type
  TChartAccess=class(TCustomChart);

procedure TLegendPaletteTool.ChartMouseEvent(AEvent: TChartMouseEvent;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var tmpR : TRect;
begin
  inherited;

  case AEvent of
    cmeMove: TChartAccess(FChart).MouseMove(Shift,X,Y);
    cmeDown: TChartAccess(FChart).MouseDown(Button,Shift,X,Y);
    cmeUp  : TChartAccess(FChart).MouseUp(Button,Shift,X,Y);
  end;

  tmpR:=TeeRect(Left,Top,Left+Width,Top+Height);

  if {$IFDEF FMX}PointInRect{$ELSE}PtInRect{$ENDIF}(tmpR,TeePoint(X,Y)) then
     ParentChart.CancelMouse:=True;
end;

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

  if Assigned(FChart) then
     TPaletteChart(FChart).IParent:=ParentChart;
end;

procedure TLegendPaletteTool.SetSmooth(const Value: Boolean);
begin
  SetBooleanProperty(FSmooth,Value);
end;

procedure TLegendPaletteTool.SetVertical(const Value: Boolean);
var tmp : Integer;
begin
  if FVertical<>Value then
  begin
    FVertical:=Value;

    tmp:=Width;
    Width:=Height;
    Height:=tmp;

    with FChart.Axes do
    begin
      Bottom.Visible:=not Vertical;
      Top.Visible:=not Vertical;
      Left.Visible:=Vertical;
      Right.Visible:=Vertical;
    end;
  end;
end;

function TLegendPaletteTool.GetInverted: Boolean;
begin
  result:=FChart.Axes.Left.Inverted;
end;

procedure TLegendPaletteTool.SetInverted(const Value: Boolean);
begin
  with FChart.Axes do
  begin
    Left.Inverted:=Value;
    Right.Inverted:=Value;
    Top.Inverted:=Value;
    Bottom.Inverted:=Value;
  end;
end;

procedure TLegendPaletteTool.SetPositionUnits(const Value: TTeeUnits);
begin
  if FPositionUnits<>Value then
  begin
    FPositionUnits:=Value;
    Repaint;
  end;
end;

procedure TLegendPaletteTool.SetHeight(const Value: Integer);
begin
  SetIntegerProperty(FHeight,Value);
end;

procedure TLegendPaletteTool.SetLeft(const Value: Integer);
begin
  SetIntegerProperty(FLeft,Value);
end;

procedure TLegendPaletteTool.SetTop(const Value: Integer);
begin
  SetIntegerProperty(FTop,Value);
end;

procedure TLegendPaletteTool.SetWidth(const Value: Integer);
begin
  SetIntegerProperty(FWidth,Value);
end;

procedure TLegendPaletteTool.SetSeries(const Value: TChartSeries);
begin
  inherited;
  Repaint;
end;

function TLegendPaletteTool.GetTransp: Boolean;
begin
  result:=Chart.Color=clNone
end;

procedure TLegendPaletteTool.SetTransp(const Value: Boolean);
begin
  if GetTransp<>Value then
     if Value then
        Chart.Color:=clNone
     else
        Chart.Color:=DefaultPanelColor;
end;

function TLegendPaletteTool.GetBorder: TChartHiddenPen;
begin
  result:=Chart.Border;
end;

procedure TLegendPaletteTool.SetBorder(const Value: TChartHiddenPen);
begin
  Chart.Border:=Value;
end;

function TLegendPaletteTool.GetAxis: TLegendPaletteAxis;
begin
  case Chart[0].VertAxis of
    aLeftAxis  : result:=laDefault;
    aRightAxis : result:=laOther;
  else
    result:=laBoth;
  end;
end;

procedure TLegendPaletteTool.SetAxis(const Value: TLegendPaletteAxis);
begin
  with Chart[0] do
  case Value of
    laDefault : begin
                  VertAxis:=aLeftAxis;
                  HorizAxis:=aBottomAxis;
                end;
      laOther : begin
                  VertAxis:=aRightAxis;
                  HorizAxis:=aTopAxis;
                end;
  else
    begin
      VertAxis:=aBothVertAxis;
      HorizAxis:=aBothHorizAxis;
    end;
  end;

  Repaint;
end;

function TLegendPaletteTool.GetColor: TColor;
begin
  result:=FChart.Color;
end;

procedure TLegendPaletteTool.SetColor(const Value: TColor);
begin
  FChart.Color:=Value;
end;

function TLegendPaletteTool.GetGradient: TChartGradient;
begin
  result:=FChart.Gradient;
end;

procedure TLegendPaletteTool.SetGradient(const Value: TChartGradient);
begin
  FChart.Gradient:=Value;
end;

function TLegendPaletteTool.GetShadow: TTeeShadow;
begin
  result:=FChart.Shadow;
end;

procedure TLegendPaletteTool.SetShadow(const Value: TTeeShadow);
begin
  FChart.Shadow:=Value;
end;

function TLegendPaletteTool.GetEmboss: TTeeEmboss;
begin
  result:=FChart.Emboss;
end;

procedure TLegendPaletteTool.SetEmboss(const Value: TTeeEmboss);
begin
  FChart.Emboss:=Value;
end;

function TLegendPaletteTool.GetPointer: TLegendPointer;
begin
  if not Assigned(FPointer) then
  begin
    FPointer:=TLegendPointer.Create(nil);
    FPointer.Size:=8;
    FPointer.Style:=psDonut;
    FPointer.ParentChart:=FChart;
  end;

  result:=FPointer;
end;

function TLegendPaletteTool.GetFoot: TChartTitle;
begin
  result:=FChart.Foot;
end;

function TLegendPaletteTool.GetSubFoot: TChartTitle;
begin
  result:=FChart.SubFoot;
end;

function TLegendPaletteTool.GetSubTitle: TChartTitle;
begin
  result:=FChart.SubTitle;
end;

procedure TLegendPaletteTool.SetFoot(const Value: TChartTitle);
begin
  FChart.Foot:=Value;
end;

procedure TLegendPaletteTool.SetSubFoot(const Value: TChartTitle);
begin
  FChart.SubFoot:=Value;
end;

procedure TLegendPaletteTool.SetSubTitle(const Value: TChartTitle);
begin
  FChart.SubTitle:=Value;
end;

{ TPaletteSeries }

procedure TPaletteSeries.DrawAllValues;
var tmpBlend  : TTeeBlend;
    tmpTransp : Boolean;
begin
  tmpTransp:=(Transparency>0) and ParentChart.Canvas.SupportsAlpha;

  if tmpTransp then
     tmpBlend:=ParentChart.Canvas.BeginBlending(TeeZeroRect,Transparency)
  else
     tmpBlend:=nil;

  inherited;

  if tmpTransp then
     ParentChart.Canvas.EndBlending(tmpBlend);
end;

procedure TPaletteSeries.DrawValue(ValueIndex: Integer);

  function GradientDirection:TGradientDirection;
  begin
    if ITool.Vertical then
       if ITool.Inverted then
          result:=gdBottomTop
       else
          result:=gdTopBottom
    else
       if ITool.Inverted then
          result:=gdLeftRight
       else
          result:=gdRightLeft;
  end;

var R : TRect;
begin
  if ITool.Vertical then
  begin
    R.Left:=GetHorizAxis.IStartPos;

    if VertAxis<>aRightAxis then
       R.Left:=R.Left+ParentChart.Axes.Left.Axis.Width;

    R.Right:=GetHorizAxis.IEndPos;
    R.Top:=CalcYPos(ValueIndex);

    if ValueIndex=Count-1 then
       if GetVertAxis.Inverted then R.Bottom:=R.Bottom-1
                               else R.Top:=R.Top+1;

    if ValueIndex>0 then
       R.Bottom:=CalcYPos(ValueIndex-1)
    else
    if GetVertAxis.Inverted then
       R.Bottom:=GetVertAxis.IStartPos
    else
       R.Bottom:=GetVertAxis.IEndPos;

    if ValueIndex=1 then
       if GetVertAxis.Inverted then
          R.Bottom:=R.Bottom+1;
  end
  else
  begin
    R.Top:=GetVertAxis.IStartPos;

    if HorizAxis<>aBottomAxis then
       R.Top:=R.Top+ParentChart.Axes.Bottom.Axis.Width;

    R.Bottom:=GetVertAxis.IEndPos;
    R.Left:=CalcXPos(ValueIndex);

    if ValueIndex>0 then
       R.Right:=CalcXPos(ValueIndex-1)
    else
    if GetHorizAxis.Inverted then
       R.Right:=GetHorizAxis.IEndPos
    else
       R.Right:=GetHorizAxis.IStartPos;
  end;

  R:=OrientRectangle(R);

  with ParentChart.Canvas do
  begin
    Pen.Style:=psClear;
    Brush.Color:=ValueColor[ValueIndex];

    Brush.Gradient.Visible:=ITool.Smooth;

    if ITool.Smooth then
    begin
      Brush.Gradient.Direction:=GradientDirection;
      Brush.Gradient.EndColor:=ValueColor[ValueIndex];

      if ValueIndex>0 then
         Brush.Gradient.StartColor:=ValueColor[ValueIndex-1]
      else
         Brush.Gradient.StartColor:=Brush.Gradient.EndColor;
    end;

    FillRect(R);

    if Self.Pen.Visible then
    begin
      AssignVisiblePen(Self.Pen);

      if ITool.Vertical then
      begin
        DoHorizLine(R.Left,R.Right,R.Top);

        if ValueIndex=1 then
           DoHorizLine(R.Left,R.Right,R.Bottom);

        if VertAxis=aLeftAxis then
           DoVertLine(R.Right,R.Top,R.Bottom)
        else
        if VertAxis=aRightAxis then
           DoVertLine(R.Left,R.Top,R.Bottom);
      end
      else
      begin
        DoVertLine(R.Right,R.Top,R.Bottom);

        if ValueIndex=1 then
           DoVertLine(R.Left,R.Top,R.Bottom);

        if HorizAxis=aTopAxis then
           DoHorizLine(R.Left,R.Right,R.Top)
        else
        if HorizAxis=aBottomAxis then
           DoHorizLine(R.Left,R.Right,R.Bottom);
      end;
    end;
  end;
end;

{ TLegendPointer }

procedure TLegendPointer.SetValue(const AValue: Double);
begin
  if FValue<>AValue then
  begin
    FValue:=AValue;
    ParentChart.Invalidate;
  end;
end;

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