{********************************************}
{   TeeChart Pro Charting Library            }
{   Frame Tool (Decorating Frames)           }
{                                            }
{ Copyright (c) 2006-2020 by Steema Software }
{ All Rights Reserved                        }
{********************************************}
unit TeeFrameTool;
{$I TeeDefs.inc}

interface

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

  {$IFDEF FMX}
  System.UITypes, FMX.Types,
  {$ELSE}

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

  Graphics, Controls,
  {$ENDIF}

  {$IFDEF D6}
  Types,
  {$ENDIF}

  {$IFDEF FMX}
  FMXTee.Procs, FMXTee.Engine, FMXTee.Chart, FMXTee.Canvas
  {$ELSE}
  TeeProcs, TeeFilters, TeEngine, Chart, TeCanvas
  {$ENDIF}
  ;

type
  TFrameTool=class(TTeeCustomTool)
  private
    FFrame     : TTeePicture;
    FPaspartou : Integer;
    FResize    : Boolean;
    FSize      : Integer;
    FStyle     : Integer;

    IResized : Boolean;
    {$IFNDEF FMX}
    IRotate  : TRotateFilter;
    {$ENDIF}

    procedure DoResizeChart;
    procedure DrawFrame;
    function IsFrameStored: Boolean;
    procedure PaspartouChanged(Sender:TObject);
    procedure SetFrame(const Value: TTeePicture);
    procedure SetResize(const Value: Boolean);
    procedure SetSize(const Value: Integer);
    procedure SetStyle(const Value: Integer);
    procedure SetPaspartou(const Value: Integer);
  protected
    procedure ChartEvent(AEvent: TChartToolEvent); override;
    class function GetEditorClass: String; override;
    procedure SetActive(Value:Boolean); override;
    procedure SetParentChart(const Value: TCustomAxisPanel); 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;
  published
    property Active;
    property Brush;
    property Frame:TTeePicture read FFrame write SetFrame stored IsFrameStored;
    property Paspartou:Integer read FPaspartou write SetPaspartou;
    property Pen;
    property ResizeChart:Boolean read FResize write SetResize default True;
    property Size:Integer read FSize write SetSize default 16;
    property Style:Integer read FStyle write SetStyle default 1;
  end;

implementation

{$R TeeFrameTool.res}

uses
  {$IFDEF FMX}
  FMXTee.ProConstants
  {$ELSE}
  ImageBar, TeeProCo
  {$ENDIF}
  ;

{ TFrameTool }

Constructor TFrameTool.Create(AOwner: TComponent);
begin
  inherited;
  FSize:=16;
  FResize:=True;
  FFrame:=TTeePicture.Create;

  {$IFNDEF FMX}
  IRotate:=TRotateFilter.Create(nil);
  {$ENDIF}

  FPaspartou:=16;

  Brush.BackColor:={$IFDEF FMX}claWhite{$ELSE}clWhite{$ENDIF};
  Brush.Style:=bsClear;
  Brush.OnChange:=PaspartouChanged;

  Style:=1;
end;

Destructor TFrameTool.Destroy;
begin
  {$IFNDEF FMX}
  IRotate.Free;
  {$ENDIF}

  FFrame.Free;
  inherited;
end;

procedure TFrameTool.PaspartouChanged(Sender:TObject);
begin
  DoResizeChart;
  Repaint;
end;

procedure TFrameTool.Assign(Source: TPersistent);
begin
  if Source is TFrameTool then
  with TFrameTool(Source) do
  begin
    Self.FFrame.Assign(FFrame);
    Self.FPaspartou:=FPaspartou;
    Self.FResize:=FResize;
    Self.FSize:=FSize;
    Self.FStyle:=FStyle;
  end;

  inherited;
end;

procedure TFrameTool.DrawFrame;
var h : Integer;
    w : Integer;

  procedure ApplyShadow(const AShadow:TTeeShadow);
  begin
    if AShadow.Visible then
    begin
      Dec(w,2*AShadow.HorizSize);
      Dec(h,2*AShadow.VertSize);
    end;
  end;

var P       : TFourPoints;
    tmp     : TBitmap;
    tmpSize : Integer;
begin
  w:=ParentChart.Width;
  h:=ParentChart.Height;

  ApplyShadow(ParentChart.Shadow);
  ApplyShadow(ParentChart.Emboss);

  if Brush.Style<>bsClear then
  begin
    tmpSize:=Size+Paspartou;

    with ParentChart.Canvas do
    begin
      AssignBrush(Self.Brush);
      Pen.Style:=psClear;
      Rectangle(Size,Size,w-Size,tmpSize);
      Rectangle(Size,h-Size,w-Size,h-tmpSize);
      Rectangle(Size,Size,tmpSize,h-Size);
      Rectangle(w-Size,Size,w-tmpSize,h-Size);

      if Self.Pen.Visible then
      begin
        AssignVisiblePen(Self.Pen);
        Brush.Style:=bsClear;
        Rectangle(tmpSize-1,tmpSize-1,w-tmpSize,h-tmpSize);
      end;
    end;
  end;

  tmp:=TBitmap.Create;
  try
    TeeSetBitmapSize(tmp,Size,h);

    tmp.Assign(FFrame.Filtered as TBitmap);

    with ParentChart.Canvas do
    begin
      // Left
      P[0].X:=0;
      P[0].Y:=0;
      P[1].X:=Size;
      P[1].Y:=Size;
      P[2].X:=Size;
      P[2].Y:=h-Size;
      P[3].X:=0;
      P[3].Y:=h;

      ClipPolygon(P,4);
      StretchDraw(TeeRect(Size,h),tmp);
      UnClipRectangle;

      // Right
      TReverseFilter.ApplyTo(tmp);

      P[0].X:=w;
      P[1].X:=P[0].X-Size;
      P[2].X:=P[1].X;
      P[3].X:=P[0].X;
      P[3].Y:=h;

      ClipPolygon(P,4);
      StretchDraw(TeeRect(P[1].X,0,P[0].X,h),tmp);
      UnClipRectangle;

      (*
      AV at D6 TeeGetLines (Bitmap.Scanline)
      {$IFNDEF D7}
      tmp.Dormant;
      {$ENDIF}
      *)

      // Top
      IRotate.Angle:=270;
      IRotate.Apply(tmp);

      P[0].X:=0;
      P[0].Y:=0;
      P[1].X:=w;
      P[1].Y:=0;
      P[2].X:=w-Size;
      P[2].Y:=Size;
      P[3].X:=Size;
      P[3].Y:=Size;

      ClipPolygon(P,4);
      StretchDraw(TeeRect(w,Size),tmp);
      UnClipRectangle;

      // Bottom
      IRotate.Angle:=180;
      IRotate.Apply(tmp);

      P[0].Y:=h;
      P[1].X:=w;
      P[1].Y:=h;
      P[2].X:=w-Size;
      P[2].Y:=h-Size;
      P[3].X:=Size;
      P[3].Y:=h-Size;

      ClipPolygon(P,4);
      StretchDraw(TeeRect(0,h-Size,w,h),tmp);
      UnClipRectangle;
    end;

  finally
    tmp.Free;
  end;
end;

procedure TFrameTool.ChartEvent(AEvent: TChartToolEvent);
begin
  inherited;

  if AEvent=cteAfterDraw then
     DrawFrame;
end;

class function TFrameTool.Description: String;
begin
  result:=TeeMsg_FrameTool;
end;

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

class function TFrameTool.LongDescription: String;
begin
  result:=TeeMsg_FrameToolDesc;
end;

procedure TFrameTool.SetSize(const Value: Integer);
begin
  SetIntegerProperty(FSize,Value);
  DoResizeChart;
end;

procedure TFrameTool.SetStyle(const Value: Integer);
begin
  SetIntegerProperty(FStyle,Value);

  if Style<>0 then
     LoadBitmapFromResourceName(FFrame.Bitmap,'TeeFrame'+IntToStr(Style)); // Do not localize
end;

procedure TFrameTool.SetFrame(const Value: TTeePicture);
begin
  if Assigned(Value) then Frame.Assign(Value)
                     else FreeAndNil(FFrame);
end;

function TFrameTool.IsFrameStored: Boolean;
begin
  result:=Style=0;
end;

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

  if Assigned(Value) then
  begin
    DoResizeChart;
    Repaint;
  end;
end;

procedure TFrameTool.DoResizeChart;
var tmp : Integer;
begin
  if Assigned(ParentChart) then
  if Active and FResize then
  begin
    tmp:=Size;

    if Brush.Style<>bsClear then
       Inc(tmp,Paspartou);

    with ParentChart as TCustomChart do
    begin
      MarginUnits:=muPixels;
      MarginBottom:=tmp;
      MarginTop:=tmp;
      MarginRight:=tmp;
      MarginLeft:=tmp;
    end;

    IResized:=True;
  end
  else
  if IResized then
  begin
    with ParentChart as TCustomChart do
    begin
      MarginUnits:=muPercent;
      MarginBottom:=TeeDefVerticalMargin;
      MarginTop:=TeeDefVerticalMargin;
      MarginRight:=TeeDefHorizMargin;
      MarginLeft:=TeeDefHorizMargin;
    end;

    IResized:=False;
  end;
end;

procedure TFrameTool.SetResize(const Value: Boolean);
begin
  SetBooleanProperty(FResize,Value);
  DoResizeChart;
end;

procedure TFrameTool.SetPaspartou(const Value: Integer);
begin
  SetIntegerProperty(FPaspartou,Value);
  DoResizeChart;
end;

procedure TFrameTool.SetActive(Value: Boolean);
begin
  inherited;
  DoResizeChart;
end;

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