{**********************************************}
{   TeePreviewPanel Control                    }
{   Copyright (c) 1999-2020 by Steema Software }
{**********************************************}
unit TeePreviewPanel;
{$I TeeDefs.inc}

interface

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

     {$IFDEF D18}
     System.Generics.Collections,
     {$ENDIF}
     
     {$IFDEF D16}
     System.UITypes,
     {$ENDIF}

     {$IFDEF FMX}
     System.UIConsts, FMX.Types, System.Types,

     {$IFDEF D19}
     FMX.Graphics,
     {$ENDIF}

     {$ELSE}
     Printers, Graphics, Controls, ExtCtrls, Forms,
     {$ENDIF}

     {$IFDEF D6}
     {$IFNDEF FMX}
     Types,
     {$ENDIF}
     {$ENDIF}

     {$IFDEF FMX}
     FMXTee.Procs, FMXTee.Canvas
     {$ELSE}
     TeeProcs, TeCanvas
     {$ENDIF}
     ;

type
  TTeePreviewPanelOrientation=(ppoDefault,ppoPortrait,ppoLandscape);

  TOnChangeMarginsEvent=Procedure( Sender:TObject; DisableProportional:Boolean;
                                   Const NewMargins:TRect) of object;

  TOnGetPaperRect=Procedure(Sender:TObject; var PaperRect:TRect) of object;

  TPreviewChartPen=class(TTeePen)
  published
    property EndStyle default esFlat;
    property Style default psDot;
    property SmallDots default True;
  end;

  TeePreviewZones=( teePrev_None,
                    teePrev_Left,
                    teePrev_Top,
                    teePrev_Right,
                    teePrev_Bottom,
                    teePrev_Image,
                    teePrev_LeftTop,
                    teePrev_RightTop,
                    teePrev_LeftBottom,
                    teePrev_RightBottom );

  TTeePanelsList=class(TList{$IFDEF D18}<TCustomTeePanel>{$ENDIF})
  {$IFNDEF D18}
  private
    Function Get(Index:Integer):TCustomTeePanel;
    Procedure Put(Index:Integer; Value:TCustomTeePanel);
  public
    property Items[Index:Integer]:TCustomTeePanel read Get write Put; default;
  end
  {$ENDIF};

  {$IFDEF D16}
  [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 {$IFDEF D26}or pidOSX64{$ENDIF})]
  {$ENDIF}
  TTeePreviewPanel=class(TCustomTeePanelExtended)
  private
    FAllowResize     : Boolean;
    FAllowMove       : Boolean;
    FAsBitmap        : Boolean;
    FPanels          : TTeePanelsList;
    FDragImage       : Boolean;
    FMargins         : TPreviewChartPen;
    FOrientation     : TTeePreviewPanelOrientation;
    FOnChangeMargins : TOnChangeMarginsEvent;
    FOnGetPaperRect  : TOnGetPaperRect;
    FPaperColor      : TColor;
    FPaperShadow     : TTeeShadow;
    FShowImage       : Boolean;
    FSmoothBitmap    : Boolean;
    FTitle           : String;

    { internal }
    IDragged         : TeePreviewZones;
    OldX             : TCoordinate;
    OldY             : TCoordinate;
    OldRect          : TRect;
    IOldShowImage    : Boolean;

    Procedure CheckPrinterOrientation;
    Function GetPanel:TCustomTeePanel;
    Function GetPrintingBitmap(const APanel:TCustomTeePanel):TBitmap;
    Function GetShadowColor:TColor;  // obsolete
    Function GetShadowSize:Integer;  // obsolete
    function PrinterCount:Integer;
    Procedure SendAsBitmap(const APanel:TCustomTeePanel; const ACanvas:TCanvas; Const R:TRect); overload;
    Procedure SendAsBitmap(const APanel:TCustomTeePanel; Const R:TRect); overload;
    Procedure SetAsBitmap(Value:Boolean);
    Procedure SetMargins(const Value:TPreviewChartPen);
    Procedure SetOrientation(const Value:TTeePreviewPanelOrientation);
    Procedure SetPanel(const Value:TCustomTeePanel);
    Procedure SetPaperColor(Value:TColor);
    Procedure SetPaperShadow(const Value:TTeeShadow);
    Procedure SetShadowColor(Value:TColor);  // obsolete
    Procedure SetShadowSize(Value:Integer);  // obsolete
    Procedure SetShowImage(Value:Boolean);
    procedure SetSmoothBitmap(const Value: Boolean);
  protected
    Function CalcImagePrintMargins(const APanel:TCustomTeePanel):TRect;
    Procedure DrawPaper;
    Procedure DrawPanelImage(const APanel:TCustomTeePanel);
    Procedure DrawMargins(Const R:TRect);
    Procedure InternalDraw(Const UserRectangle:TRect); override;

    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
                        X, Y: TCoordinate); override;

    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
                      X, Y: TCoordinate); override;

    procedure MouseMove(Shift: TShiftState; X, Y: TCoordinate); override;

    procedure Notification( AComponent: TComponent;
                            Operation: TOperation); override;
    Function WhereIsCursor(const x,y: TCoordinate):TeePreviewZones;
  public
    ImageRect : TRect;
    PaperRect : TRect;

    Constructor Create(AOwner:TComponent); override;
    Destructor Destroy; override;

    Procedure Print;
    property Panels:TTeePanelsList read FPanels;

    // compatibility with v5 (obsolete)
    property ShadowColor:TColor read GetShadowColor write SetShadowColor;
    property ShadowSize:Integer read GetShadowSize write SetShadowSize;
  published
    property AllowResize:Boolean read FAllowResize write FAllowResize default True;
    property AllowMove:Boolean read FAllowMove write FAllowMove default True;
    property AsBitmap:Boolean read FAsBitmap write SetAsBitmap default {$IFDEF FMX}True{$ELSE}False{$ENDIF};
    property DragImage:Boolean read FDragImage write FDragImage default False;
    property Margins:TPreviewChartPen read FMargins write SetMargins;
    property Orientation:TTeePreviewPanelOrientation read FOrientation
                     write SetOrientation default ppoDefault;
    property Panel:TCustomTeePanel read GetPanel write SetPanel;
    property PaperColor:TColor read FPaperColor write SetPaperColor default {$IFDEF FMX}TAlphaColors.White{$ELSE}clWhite{$ENDIF};

    property PaperShadow:TTeeShadow read FPaperShadow write SetPaperShadow;
    property Shadow;

    property ShowImage:Boolean read FShowImage write SetShowImage default True;
    property SmoothBitmap:Boolean read FSmoothBitmap write SetSmoothBitmap default True;
    property Title:String read FTitle write FTitle;

    property OnChangeMargins:TOnChangeMarginsEvent read FOnChangeMargins
                                                   write FOnChangeMargins;
    property OnGetPaperRect:TOnGetPaperRect read FOnGetPaperRect
                                            write FOnGetPaperRect;

    { TeePanelExtended }
    property BackImage;
    property BackImageMode;
    property Border;
    property BorderRound;
    property Gradient;

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

    {$IFNDEF FMX}
    property Color;
    property DragCursor;
    {$ENDIF}

    property Enabled;

    {$IFDEF FMX}
    {$IFDEF D23}
    property ParentShowHint;
    {$ENDIF}
    {$ELSE}
    property ParentColor;
    property ParentShowHint;
    property PopupMenu;
    {$ENDIF}

    property ShowHint;
    property TabOrder;

    {$IFNDEF FMX}
    property TabStop;

    {$IFDEF D14}
    property Touch;
    {$ENDIF}

    {$ENDIF}

    property Visible;

    {$IFDEF FMX}
    {$IFDEF D17}
    property Action;
    property Anchors;
    property Position;
    property Width;
    property Height;
    property ClipChildren;
    {$ENDIF}
    {$ELSE}
    property Anchors;
    {$ENDIF}

    {$IFDEF FMX}
    property Locked;
    {$ELSE}

    property AutoSize;
    property Constraints;
    property DragKind;
    {$IFNDEF LCL}
    property Locked;
    {$ENDIF}

    {$ENDIF}

    property OnAfterDraw;

    { TPanel events }
    property OnClick;

    {$IFNDEF FMX}
    property OnContextPopup;
    {$ENDIF}

    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;

    {$IFNDEF FMX}
    property OnEndDrag;
    property OnStartDrag;
    {$ENDIF}

    property OnEnter;
    property OnExit;
    property OnKeyDown;

    {$IFNDEF FMX}
    property OnKeyPress;
    {$ENDIF}

    property OnKeyUp;
    property OnMouseDown;

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

    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
    property OnMouseWheel;

    {$IFNDEF FMX}
    property OnMouseWheelDown;
    property OnMouseWheelUp;

    {$IFNDEF LCL}
    property OnCanResize;
    {$ENDIF}

    property OnConstrainedResize;
    property OnDockDrop;
    property OnDockOver;
    property OnEndDock;
    property OnGetSiteInfo;
    property OnStartDock;
    property OnUnDock;
    {$ENDIF}

    {$IFNDEF FMX}
    {$IFDEF D14}
    property OnGesture;
    {$ENDIF}
    {$ENDIF}
  end;

implementation

uses
  Math, SysUtils
  {$IFDEF FMX}
  , FMX.Platform

  {$IFNDEF TEENOPRINT}
  , FMX.Printer
  {$ENDIF}

  {$ENDIF}
  ;

type
  TShadowAccess=class(TTeeShadow);

Const TeePreviewCursors:Array[0..9] of TCursor=
           ( crDefault, { none }
             crHSplit,
             crVSplit,
             crHSplit,
             crVSplit,
             {$IFDEF FMX}crHandPoint{$ELSE}crTeeHand{$ENDIF},
             crSizeNWSE,
             crSizeNESW,
             crSizeNESW,
             crSizeNWSE );

{ TeePreviewPanel }

Constructor TTeePreviewPanel.Create(AOwner:TComponent);
Begin
  inherited;

  FPanels:=TTeePanelsList.Create;
  FDragImage:=False;
  FOrientation:=ppoDefault;

  FMargins:=TPreviewChartPen.Create(CanvasChanged);
  FMargins.SmallDots:=True;
  FMargins.Style:=psDot;
  FMargins.EndStyle:=esFlat;

  FShowImage:=True;
  IOldShowImage:=True;
  IDragged:=teePrev_None;

  FAsBitmap:={$IFDEF FMX}True{$ELSE}False{$ENDIF};
  FSmoothBitmap:=True;

  FPaperColor:={$IFDEF FMX}TAlphaColors.White{$ELSE}clWhite{$ENDIF};

  FAllowResize:=True;
  FAllowMove:=True;
  FTitle:='';

  FPaperShadow:=TTeeShadow.Create(CanvasChanged);
  TShadowAccess(FPaperShadow).InitValues(FPaperShadow.Visible,clDkGray,4);

  Width :=432;
  Height:=312;
end;

Destructor TTeePreviewPanel.Destroy;
begin
  {$IFDEF D18}
  Margins.DisposeOf;
  {$ELSE}
  Margins.Free;
  {$ENDIF}

  FPaperShadow.Free;
  FreeAndNil(FPanels);
  inherited;
end;

Function TTeePreviewPanel.GetPrintingBitmap(const APanel:TCustomTeePanel):TBitmap;
var tmpR      : TRect;
    WinWidth  : Integer;
    WinHeight : Integer;
    tmpW      : Integer;
    tmpH      : Integer;
    tmpWidth  : TCoordinate;
    tmpHeight : TCoordinate;
begin
  APanel.Printing:=True;
  try
    With APanel.GetRectangle do
    begin
      tmpWidth:=Right-Left;
      tmpHeight:=Bottom-Top;
    end;

    tmpR:=CalcImagePrintMargins(APanel);
    APanel.CalcMetaBounds(tmpR,TeeRect(tmpWidth,tmpHeight),WinWidth,WinHeight,tmpW,tmpH);
    result:=APanel.TeeCreateBitmap(FPaperColor,TeeRect(WinWidth,WinHeight),TeePixelFormat);
  finally
    APanel.Printing:=False;
  end;
end;

Procedure TTeePreviewPanel.SendAsBitmap(const APanel:TCustomTeePanel; const ACanvas:TCanvas; Const R:TRect);
var tmpBitmap : TBitmap;
begin
  tmpBitmap:=GetPrintingBitmap(APanel);
  try
    {$IFDEF FMX}
    ACanvas.DrawBitmap(tmpBitmap, TeeRect(tmpBitmap.Width,tmpBitmap.Height),
                       R,AbsoluteOpacity);
    {$ELSE}
    ACanvas.StretchDraw(R,tmpBitmap);
    {$ENDIF}
  finally
    tmpBitmap.Free;
  end;
end;

Procedure TTeePreviewPanel.SendAsBitmap(const APanel:TCustomTeePanel; Const R:TRect);
var tmpBitmap : TBitmap;
    tmpSmooth : TBitmap;
begin
  tmpBitmap:=GetPrintingBitmap(APanel);
  try
    if SmoothBitmap and
      (
        ((R.Right-R.Left)<>tmpBitmap.Width) or
        ((R.Bottom-R.Top)<>tmpBitmap.Height)
      )  then
    begin
      tmpSmooth:=TBitmap.Create{$IFDEF FMX}(Round(R.Right-R.Left), Round(R.Bottom-R.Top)){$ENDIF};
      try
        {$IFNDEF FMX}
        TeeSetBitmapSize(tmpSmooth,R.Right-R.Left,R.Bottom-R.Top);
        {$ENDIF}

        SmoothStretch(tmpBitmap,tmpSmooth,ssBestQuality);
        Canvas.Draw({$IFDEF FMX}Round{$ENDIF}(R.Left),
                    {$IFDEF FMX}Round{$ENDIF}(R.Top),tmpSmooth);
      finally
        tmpSmooth.Free;
      end;
    end
    else
       Canvas.StretchDraw(R,tmpBitmap);
  finally
    tmpBitmap.Free;
  end;
end;

Procedure TTeePreviewPanel.Print;
{$IFNDEF TEENOPRINT}
var t : Integer;
{$ENDIF}
Begin
  if FPanels.Count>0 then
  Begin
    TeeChangeCursor(nil, crHourGlass);

    try
      CheckPrinterOrientation;

      {$IFNDEF TEENOPRINT}
      if FTitle='' then
      begin
        if Panel.Name<>'' then
           Printer.Title:=Panel.Name;
      end
      else
        Printer.Title:=FTitle;

      Printer.BeginDoc;
      try
        for t:=0 to Panels.Count-1 do
            if FAsBitmap then SendAsBitmap(Panels[t],Printer.Canvas,Panels[t].ChartPrintRect)
                         else Panels[t].PrintPartial(Panels[t].ChartPrintRect);

        if Assigned(FOnAfterDraw) then FOnAfterDraw(Self);
        Printer.EndDoc;
      except
        on Exception do
        begin
          Printer.Abort;

          if Printer.Printing then
             Printer.EndDoc;

          Raise;
        end;
      end;
      {$ENDIF}
      
    finally
      TeeChangeCursor(nil, crDefault);
    end;
  end;
end;

Procedure TTeePreviewPanel.DrawPaper;
Begin
  PaperShadow.Draw(Canvas,PaperRect);

  With Canvas do
  Begin
    Pen.Style:=psSolid;
    Pen.Color:={$IFDEF FMX}TAlphaColors.Black{$ELSE}clBlack{$ENDIF};
    Pen.Width:=1;
    Brush.Color:=FPaperColor;
    Rectangle(PaperRect);
  end;
end;

Procedure TTeePreviewPanel.SetAsBitmap(Value:Boolean);
begin
  SetBooleanProperty(FAsBitmap,Value);
end;

Procedure TTeePreviewPanel.SetPaperColor(Value:TColor);
begin
  SetColorProperty(FPaperColor,Value);
end;

Procedure TTeePreviewPanel.SetShadowSize(Value:Integer);
begin
  PaperShadow.Size:=Value;
end;

Procedure TTeePreviewPanel.SetShowImage(Value:Boolean);
begin
  SetBooleanProperty(FShowImage,Value);
end;

Procedure TTeePreviewPanel.SetMargins(const Value:TPreviewChartPen);
Begin
  FMargins.Assign(Value);
End;

Procedure TTeePreviewPanel.SetPanel(const Value:TCustomTeePanel);
Begin
  if (Panel<>Value) and (Value<>Self) then
  begin
    if FPanels.Count>0 then
       FPanels.Delete(0);

    if Assigned(Value) then
       if FPanels.IndexOf(Value)=-1 then
       begin
         FPanels.Add(Value);
         Value.FreeNotification(Self);
       end;

    if Assigned(Panel) and Panel.Canvas.SupportsFullRotation then
       FAsBitmap:=True;

    Invalidate;
  end;
End;

Function TTeePreviewPanel.CalcImagePrintMargins(const APanel:TCustomTeePanel):TRect;
var PaperWidth  : Integer;
    PaperHeight : Integer;
begin
  RectSize(PaperRect,PaperWidth,PaperHeight);

  if Assigned(APanel) then
  begin
    with APanel do
       if PrintProportional and (PrinterCount>0) then
          PrintMargins:=CalcProportionalMargins;

    result:=APanel.PrintMargins
  end
  else result:=TeeRect(15,15,15,15);

  With result do
  begin
    Left  :=PaperRect.Left  +(Left  *PaperWidth {$IFDEF FMX}*0.01{$ELSE}div 100{$ENDIF});
    Right :=PaperRect.Right -(Right *PaperWidth {$IFDEF FMX}*0.01{$ELSE}div 100{$ENDIF});
    Top   :=PaperRect.Top   +(Top   *PaperHeight {$IFDEF FMX}*0.01{$ELSE}div 100{$ENDIF});
    Bottom:=PaperRect.Bottom-(Bottom*PaperHeight {$IFDEF FMX}*0.01{$ELSE}div 100{$ENDIF});
  end;
end;

function TTeePreviewPanel.PrinterCount:Integer;
begin
  {$IFDEF TEENOPRINT}
  result:=0; // ??
  {$ELSE}
  {$IFDEF MACOS}
  result:=0; // Abstract
  {$ELSE}
  if Printer<>nil then
     {$IFDEF FMX}

     {$IFDEF D17}
     result:=Printer.Count
     {$ELSE}
      // Workaround fix XE2 bug when Printer capabilities return -1
      try
        result:=Printer.Count;
      except
        //on ERangeCheckError do
           result:=0;
      end
     {$ENDIF}

     {$ELSE}
     result:=Printer.Printers.Count
     {$ENDIF}
  else
     result:=0;
  {$ENDIF}
  {$ENDIF}
end;

Procedure TTeePreviewPanel.CheckPrinterOrientation;
begin
  {$IFNDEF ANDROID}
  if PrinterCount>0 then
  Case FOrientation of
     ppoDefault: ;
    ppoPortrait: Printer.Orientation:={$IFDEF FMX}TPrinterOrientation.{$ENDIF}poPortrait;
  else
    Printer.Orientation:={$IFDEF FMX}TPrinterOrientation.{$ENDIF}poLandscape;
  end;
  {$ENDIF}
end;

Procedure TTeePreviewPanel.InternalDraw(Const UserRectangle:TRect);

  Procedure CalcPaperRectangles;
  var
    PrinterWidth  : TCoordinate;
    PrinterHeight : TCoordinate;

    procedure SetScreenSize;
    var P : TPoint;
    begin
      P:=TeeGetScreenSize;
      PrinterWidth:=P.X;
      PrinterHeight:=P.Y;
    end;

  Const Margin=5;
  Var tmpClientWidth,
      tmpClientHeight,
      tmpWidth,
      tmpHeight : TCoordinate;
  begin
    CheckPrinterOrientation;

    if PrinterCount>0 then
    begin
      {$IFDEF ANDROID}
      SetScreenSize;
      {$ELSE}
      try
        PrinterWidth :=Printer.PageWidth;
        PrinterHeight:=Printer.PageHeight;
      except
        on EPrinter do
           SetScreenSize;
      end;
      {$ENDIF}
    end
    else
      SetScreenSize;

    tmpClientWidth:={$IFDEF FMX}Width{$ELSE}ClientWidth{$ENDIF};
    tmpClientHeight:={$IFDEF FMX}Height{$ELSE}ClientHeight{$ENDIF};

    if (tmpClientWidth*PrinterHeight)>(tmpClientHeight*PrinterWidth) then
    Begin
      tmpHeight:=tmpClientHeight-Round(tmpClientHeight/Margin);
      PaperRect.Top:=Round(tmpClientHeight/(2*Margin));
      PaperRect.Bottom:=PaperRect.Top+tmpHeight;

      if PrinterHeight>0 then
        tmpWidth:=(tmpHeight*PrinterWidth {$IFDEF FMX}/{$ELSE}div{$ENDIF} PrinterHeight)
      else
        tmpWidth:=tmpClientWidth;

      PaperRect.Left:=(tmpClientWidth-tmpWidth) {$IFDEF FMX}*0.5{$ELSE}div 2{$ENDIF};
      PaperRect.Right:=PaperRect.Left+tmpWidth;
    end
    else
    Begin
      tmpWidth:=tmpClientWidth-Round(tmpClientWidth/Margin);
      PaperRect.Left:=Round(tmpClientWidth/(2*Margin));
      PaperRect.Right:=PaperRect.Left+tmpWidth;

      if PrinterWidth>0 then
        tmpHeight:=(tmpWidth*PrinterHeight {$IFDEF FMX}/{$ELSE}div{$ENDIF} PrinterWidth)
      else
        tmpHeight:=tmpClientHeight;

      PaperRect.Top:=(tmpClientHeight-tmpHeight) {$IFDEF FMX}*0.5{$ELSE}div 2{$ENDIF};
      PaperRect.Bottom:=PaperRect.Top+tmpHeight;
    end;
  end;

var t : Integer;
begin
  ChartRect:=UserRectangle;
  PanelPaint(ChartRect);
  RecalcWidthHeight;
  InternalCanvas.Projection(100,ChartBounds,ChartRect);
  Canvas.ResetState;

  CalcPaperRectangles;

  if Assigned(FOnGetPaperRect) then
     FOnGetPaperRect(Self,PaperRect);

  DrawPaper;
  ImageRect:=CalcImagePrintMargins(Panel);

  for t:=0 to Panels.Count-1 do
      DrawPanelImage(Panels[t]);

  DrawMargins(ImageRect);
  Canvas.ResetState;

  if Assigned(FOnAfterDraw) then
     FOnAfterDraw(Self);
end;

Procedure TTeePreviewPanel.DrawMargins(Const R:TRect);
Begin
  if Margins.Visible then
  With Canvas do
  Begin
    AssignVisiblePen(Margins);
    Pen.Mode:=pmNotXor;
    Brush.Style:=bsClear;
    Brush.Color:=FPaperColor;
    BackMode:=cbmTransparent;

    With R do
    Begin
      DoVertLine(Left-1,PaperRect.Top+1,PaperRect.Bottom);
      DoVertLine(Right,PaperRect.Top+1,PaperRect.Bottom);
      DoHorizLine(PaperRect.Left+1,PaperRect.Right,Top-1);
      DoHorizLine(PaperRect.Left+1,PaperRect.Right,Bottom);
    end;

    BackMode:=cbmOpaque;
    Pen.Mode:=pmCopy;
  end;
end;

Procedure TTeePreviewPanel.DrawPanelImage(const APanel:TCustomTeePanel);
Var PanelRect : TRect;

  Procedure DrawAsMetafile;
  var tmpR      : TRect;
      tmpMeta   : TMetafile;
      WinWidth  : Integer;
      WinHeight : Integer;
      tmpW      : Integer;
      tmpH      : Integer;
  begin
    tmpR:=PanelRect;
    APanel.CalcMetaBounds(tmpR,APanel.GetRectangle,WinWidth,WinHeight,tmpW,tmpH);

    tmpMeta:=APanel.TeeCreateMetafile(True,TeeRect(WinWidth,WinHeight));
    try
      //Canvas.StretchDrawQuality:=sqLow; <-- Not necessary for GDI+ canvas
      Canvas.StretchDraw(PanelRect,tmpMeta);
    finally
      tmpMeta.Free;
    end;
  end;

Begin
  PanelRect:=CalcImagePrintMargins(APanel);
  APanel.Printing:=True;

  if APanel.CanClip then Canvas.ClipRectangle(PanelRect)
                    else Canvas.ClipRectangle(PaperRect);

  if FShowImage then
     {$IFDEF FMX}
     SendAsBitmap(APanel,PanelRect);
     {$ELSE}
     if AsBitmap then
        SendAsBitmap(APanel,PanelRect)
     else
        {$IFDEF FMX}
        SendAsBitmap(APanel,PanelRect);
        {$ELSE}
        DrawAsMetafile;
        {$ENDIF}
     {$ENDIF}

  Canvas.UnClipRectangle;
  APanel.Printing:=False;
end;

procedure TTeePreviewPanel.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;

  if (Operation=opRemove) and Assigned(Panel) and (AComponent=Panel) then
     Panel:=nil;
end;

Function TTeePreviewPanel.WhereIsCursor(const x,y: TCoordinate):TeePreviewZones;
Const MinPixels=5;
var xLeft,
    xRight,
    yTop,
    yBottom : TCoordinate;
Begin
  With ImageRect do
  begin
    xLeft  :=Abs(x-Left);
    XRight :=Abs(x-Right);
    yTop   :=Abs(y-Top);
    yBottom:=Abs(y-Bottom);

    if (xLeft<MinPixels)  and (yTop<MinPixels)    then result:=teePrev_LeftTop else
    if (xLeft<MinPixels)  and (yBottom<MinPixels) then result:=teePrev_LeftBottom else
    if (xRight<MinPixels) and (yTop<MinPixels)    then result:=teePrev_RightTop else
    if (xRight<MinPixels) and (yBottom<MinPixels) then result:=teePrev_RightBottom else
    if xLeft<MinPixels   then result:=teePrev_Left else
    if xRight<MinPixels  then result:=teePrev_Right else
    if yTop<MinPixels    then result:=teePrev_Top else
    if yBottom<MinPixels then result:=teePrev_Bottom else

    if PointInRect(ImageRect,x,y) then
    begin
      if FAllowMove then
      begin
        result:=teePrev_Image;
        exit;
      end else result:=teePrev_None;
    end
    else result:=teePrev_None;

    if (result<>teePrev_None) and (not FAllowResize) then
       result:=teePrev_None;
  end;
End;

Procedure TTeePreviewPanel.MouseMove(Shift: TShiftState; X, Y: TCoordinate);
var tmpR        : TRect;
    PaperWidth  : Integer;
    PaperHeight : Integer;
begin
  inherited;

  if PointInRect(PaperRect,x,y) then
  Begin
    if IDragged=teePrev_None then
    begin
      Cursor:=TeePreviewCursors[Ord(WhereIsCursor(x,y))];
      Exit;
    end
    else
    begin
      if not FDragImage then
         DrawMargins(ImageRect);

      Case IDragged of
        { sides }
        teePrev_Left   : if (x>=PaperRect.Left) and (x<ImageRect.Right) then ImageRect.Left:=x;
        teePrev_Top    : if (y>=PaperRect.Top) and (y<ImageRect.Bottom) then ImageRect.Top:=y;
        teePrev_Right  : if (x<=PaperRect.Right) and (x>ImageRect.Left) then ImageRect.Right:=x;
        teePrev_Bottom : if (y<=PaperRect.Bottom) and (y>ImageRect.Top) then ImageRect.Bottom:=y;

        teePrev_Image  : Begin
                           tmpR.Left  :=Math.Max(PaperRect.Left,OldRect.Left+(x-OldX));
                           tmpR.Top   :=Math.Max(PaperRect.Top,OldRect.Top+(y-OldY));
                           tmpR.Right :=Math.Min(PaperRect.Right,tmpR.Left+(OldRect.Right-OldRect.Left));
                           tmpR.Bottom:=Math.Min(PaperRect.Bottom,tmpR.Top+(OldRect.Bottom-OldRect.Top));

                           if PointInRect(PaperRect,tmpR.TopLeft) and
                              PointInRect(PaperRect,tmpR.BottomRight) then
                                ImageRect:=tmpR;
                         End;
        { corners }
       teePrev_LeftTop : if (x>=PaperRect.Left) and (x<ImageRect.Right) and
                            (y>=PaperRect.Top) and (y<ImageRect.Bottom) then
                         Begin
                           ImageRect.Left:=x;
                           ImageRect.Top:=y;
                         end;

    teePrev_LeftBottom : if (x>=PaperRect.Left) and (x<ImageRect.Right) and
                            (y<=PaperRect.Bottom) and (y>ImageRect.Top) then
                         Begin
                           ImageRect.Left:=x;
                           ImageRect.Bottom:=y;
                         end;

      teePrev_RightTop : if (x<=PaperRect.Right) and (x>ImageRect.Left) and
                            (y>=PaperRect.Top) and (y<ImageRect.Bottom) then
                         Begin
                           ImageRect.Right:=x;
                           ImageRect.Top:=y;
                         end;

   teePrev_RightBottom : if (x<=PaperRect.Right) and (x>ImageRect.Left) and
                            (y<=PaperRect.Bottom) and (y>ImageRect.Top) then
                         Begin
                           ImageRect.Right:=x;
                           ImageRect.Bottom:=y;
                         end;
      end;

      RectSize(PaperRect,PaperWidth,PaperHeight);

      if Assigned(Panel) then
      begin
        Panel.PrintProportional:=False;

        tmpR:=Panel.PrintMargins;

        tmpR.Left  :=((ImageRect.Left-PaperRect.Left)*100 {$IFDEF FMX}/{$ELSE} div{$ENDIF} PaperWidth);
        tmpR.Right :=((PaperRect.Right-ImageRect.Right)*100 {$IFDEF FMX}/{$ELSE} div{$ENDIF} PaperWidth);
        tmpR.Top   :=((ImageRect.Top-PaperRect.Top)*100  {$IFDEF FMX}/{$ELSE} div{$ENDIF} PaperHeight);
        tmpR.Bottom:=((PaperRect.Bottom-ImageRect.Bottom)*100  {$IFDEF FMX}/{$ELSE} div{$ENDIF} PaperHeight);

        Panel.PrintMargins:=tmpR;
      end;

      if Assigned(FOnChangeMargins) and Assigned(Panel) then
         FOnChangeMargins(Self,True,Panel.PrintMargins);

      if FDragImage or (not Margins.Visible) then
         Invalidate
      else
         DrawMargins(ImageRect);
    end;
  end;
end;

procedure TTeePreviewPanel.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: TCoordinate);
begin
  CancelMouse:=False;

  inherited;

  if IDragged<>teePrev_None then
  begin
    IDragged:=teePrev_None;

    if not FDragImage then
       Invalidate;
  end;
end;

procedure TTeePreviewPanel.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: TCoordinate);
begin
  inherited;

  IDragged:=WhereIsCursor(x,y);

  if IDragged=teePrev_Image then
  Begin
    OldX:=x;
    OldY:=y;
    OldRect:=ImageRect;
  end;
end;

Procedure TTeePreviewPanel.SetOrientation(const Value:TTeePreviewPanelOrientation);
begin
  if Value<>FOrientation then
  begin
    FOrientation:=Value;
    Invalidate;
  end;
end;

procedure TTeePreviewPanel.SetShadowColor(Value: TColor);  // obsolete
begin
  PaperShadow.Color:=Value;
end;

function TTeePreviewPanel.GetShadowColor: TColor; // obsolete
begin
  result:=PaperShadow.Color;
end;

function TTeePreviewPanel.GetShadowSize: Integer; // obsolete
begin
  result:=PaperShadow.Size;
end;

procedure TTeePreviewPanel.SetPaperShadow(const Value: TTeeShadow);
begin
  PaperShadow.Assign(Value);
end;

function TTeePreviewPanel.GetPanel: TCustomTeePanel;
begin
  if Assigned(FPanels) and (Panels.Count>0) then result:=Panels[0]
                                            else result:=nil;
end;

{ TTeePanelsList }
{$IFNDEF D18}

function TTeePanelsList.Get(Index: Integer): TCustomTeePanel;
begin
  result:=TCustomTeePanel(inherited Items[Index]);
end;

procedure TTeePanelsList.Put(Index: Integer; Value: TCustomTeePanel);
begin
  inherited Items[Index]:=Value;
end;
{$ENDIF}

procedure TTeePreviewPanel.SetSmoothBitmap(const Value: Boolean);
begin
  SetBooleanProperty(FSmoothBitmap,Value);
end;

end.
