{*********************************************}
{  TeeChart Charting Library for FireMonkey   }
{  Copyright (c) 2012 by Steema Software      }
{  All Rights Reserved                        }
{*********************************************}
unit FMXTee.Print.Preview;
{$I TeeDefs.inc}

interface

uses
  System.SysUtils, System.UITypes, System.Types, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms,
  FMX.Dialogs, FMX.ListBox, FMXTee.Procs, FMXTee.Print.PreviewPanel, FMX.Edit;

type
  TChartPreview = class(TForm)
    Panel1: TPanel;
    BPrint: TButton;
    Label1: TLabel;
    CBPrinters: TComboBox;
    Panel2: TPanel;
    BSetupPrinter: TButton;
    Orientation: TComboBox;
    LBPortrait: TListBoxItem;
    LBLandscape: TListBoxItem;
    GBMargins: TGroupBox;
    UDTop: TNumberBox;
    UDBottom: TNumberBox;
    UDLeft: TNumberBox;
    UDRight: TNumberBox;
    CBProp: TCheckBox;
    BReset: TButton;
    ShowMargins: TCheckBox;
    CBPrintPanel: TCheckBox;
    CBSmooth: TCheckBox;
    ChangeDetailGroup: TGroupBox;
    Label2: TLabel;
    Label3: TLabel;
    Resolution: TTrackBar;
    TeePreviewPanel1: TTeePreviewPanel;
    procedure FormCreate(Sender: TObject);
    procedure BSetupPrinterClick(Sender: TObject);
    procedure BPrintClick(Sender: TObject);
    procedure OrientationChange(Sender: TObject);
    procedure CBPropChange(Sender: TObject);
    procedure BResetClick(Sender: TObject);
    procedure ShowMarginsChange(Sender: TObject);
    procedure CBPrintPanelChange(Sender: TObject);
    procedure CBPrintersChange(Sender: TObject);
    procedure UDTopChangeTracking(Sender: TObject);
    procedure UDRightChangeTracking(Sender: TObject);
    procedure UDBottomChangeTracking(Sender: TObject);
    procedure UDLeftChangeTracking(Sender: TObject);
    procedure CBSmoothChange(Sender: TObject);
    procedure ResolutionChange(Sender: TObject);
    procedure TeePreviewPanel1ChangeMargins(Sender: TObject;
      DisableProportional: Boolean; const NewMargins: TRectF);
  private
    { Private declarations }
    ChangingProp,
    ChangingMargins : Boolean;

    OldMargins      : TRectF;

    procedure ChangeMargin(UpDown:TNumberBox; var APos:Single; const OtherSide:Single);
    procedure CheckOrientation;
    function PrinterCount:Integer;
    procedure RefreshPanel(APanel:TCustomTeePanel);
    Procedure ResetMargins;
  public
    { Public declarations }
    class function CreateEditor(AOwner:TComponent; APanel:TCustomTeePanel):TForm;
    class procedure Preview(AOwner:TComponent; APanel:TCustomTeePanel);
  end;

implementation

{$R *.fmx}

uses
  FMX.Printer, FMXTee.Constants;

procedure TChartPreview.BPrintClick(Sender: TObject);
begin
  TeePreviewPanel1.Print;
end;

procedure TChartPreview.BResetClick(Sender: TObject);
begin
  With TeePreviewPanel1 do
  Begin
    Panel.PrintMargins:=OldMargins;
    TeePreviewPanel1ChangeMargins(Self,False,Panel.PrintMargins);
    Invalidate;
  end;

  BReset.Enabled:=False;
end;

procedure TChartPreview.BSetupPrinterClick(Sender: TObject);
begin
  // FMX bug workaround: set printer again
  Printer.ActivePrinter:=Printer.Printers[CBPrinters.ItemIndex];

  with TPrinterSetupDialog.Create(Self) do
  try
    Execute;
  finally
    Free;
  end;

  // Force painting (fmx bug?)
  Invalidate;
end;

procedure TChartPreview.RefreshPanel(APanel: TCustomTeePanel);
begin
  TeePreviewPanel1.Panel:=APanel;

  UDLeft.Value:=APanel.PrintMargins.Left;
  UDTop.Value:=APanel.PrintMargins.Top;
  UDRight.Value:=APanel.PrintMargins.Right;
  UDBottom.Value:=APanel.PrintMargins.Bottom;

  ChangingProp:=True;
  try
    CBProp.IsChecked:=APanel.PrintProportional;
  finally
    ChangingProp:=False;
  end;

  CBPrintPanel.IsChecked:=PrintTeePanel;
end;

function TChartPreview.PrinterCount:Integer;
begin
  {$IFDEF MACOS}
  result:=0; // Abstract XE2
  {$ELSE}

  {$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}

  {$ENDIF}
end;

Procedure TChartPreview.ResetMargins;
begin
  with TeePreviewPanel1 do
  if Assigned(Panel) then
  begin
    if Panel.PrintProportional and (PrinterCount>0) then
       Panel.PrintMargins:=Panel.CalcProportionalMargins;

    TeePreviewPanel1ChangeMargins(Self,False,Panel.PrintMargins);
    Invalidate;
  end;
end;

procedure TChartPreview.ShowMarginsChange(Sender: TObject);
begin
  TeePreviewPanel1.Margins.Visible:=ShowMargins.IsChecked;
end;

procedure TChartPreview.TeePreviewPanel1ChangeMargins(Sender: TObject;
  DisableProportional: Boolean; const NewMargins: TRectF);
begin
  ChangingMargins:=True;
  try
    UDLeft.Value:=NewMargins.Left;
    UDRight.Value:=NewMargins.Right;
    UDTop.Value:=NewMargins.Top;
    UDBottom.Value:=NewMargins.Bottom;

    if DisableProportional then
    begin
      TeePreviewPanel1.Panel.PrintProportional:=False;
      ChangingProp:=True;
      CBProp.IsChecked:=False;
      ChangingProp:=False;
    end;
  finally
    ChangingMargins:=False;
  end;
end;

procedure TChartPreview.ResolutionChange(Sender: TObject);
begin
  With TeePreviewPanel1 do
  Begin
    Panel.PrintResolution:=Round(Resolution.Value)-100;
    Invalidate;
  end;
end;

procedure TChartPreview.ChangeMargin(UpDown:TNumberBox; var APos:Single; const OtherSide:Single);
var tmpR : TRectF;
begin
  if UpDown.Value+OtherSide<100 then
  begin
    APos:=UpDown.Value;

    if not ChangingMargins then
    With TeePreviewPanel1 do
    Begin
      Invalidate;

      tmpR:=Panel.PrintMargins;
      CBProp.IsChecked:=False;
    end;

    BReset.Enabled:=not EqualRect(tmpR,OldMargins);
  end
  else UpDown.Value:=APos;
end;

procedure TChartPreview.UDBottomChangeTracking(Sender: TObject);
var R: TRectF;
begin
  if not Assigned(TeePreviewPanel1.Panel) then Exit;

  R:=TeePreviewPanel1.Panel.PrintMargins;
  ChangeMargin(UDBottom,R.Bottom,R.Top);
  TeePreviewPanel1.Panel.PrintMargins:=R;
end;

procedure TChartPreview.UDLeftChangeTracking(Sender: TObject);
var R: TRectF;
begin
  if not Assigned(TeePreviewPanel1.Panel) then Exit;

  R:=TeePreviewPanel1.Panel.PrintMargins;
  ChangeMargin(UDLeft,R.Left,R.Right);
  TeePreviewPanel1.Panel.PrintMargins:=R;
end;

procedure TChartPreview.UDRightChangeTracking(Sender: TObject);
var R: TRectF;
begin
  if not Assigned(TeePreviewPanel1.Panel) then Exit;

  R:=TeePreviewPanel1.Panel.PrintMargins;
  ChangeMargin(UDRight,R.Right,R.Left);
  TeePreviewPanel1.Panel.PrintMargins:=R;
end;

procedure TChartPreview.UDTopChangeTracking(Sender: TObject);
var R: TRectF;
begin
  if not Assigned(TeePreviewPanel1.Panel) then Exit;

  R:=TeePreviewPanel1.Panel.PrintMargins;
  ChangeMargin(UDTop,R.Top,R.Bottom);
  TeePreviewPanel1.Panel.PrintMargins:=R;
end;

procedure TChartPreview.OrientationChange(Sender: TObject);
begin
  Printer.Orientation:=TPrinterOrientation(Orientation.ItemIndex);
  ResetMargins;
  TeePreviewPanel1.Invalidate;
end;

Procedure TChartPreview.CheckOrientation;
begin
  Orientation.ItemIndex:=Ord(Printer.Orientation);
end;

procedure TChartPreview.CBPrintersChange(Sender: TObject);
var Old : TPrinterOrientation;
begin
  Old:=Printer.Orientation;
  Printer.ActivePrinter:=Printer.Printers[CBPrinters.ItemIndex];

  Printer.Orientation:=Old;  // <-- warning fmx bug: printer is set back to 0
  Printer.ActivePrinter:=Printer.Printers[CBPrinters.ItemIndex];

  TeePreviewPanel1.Invalidate;

  if Orientation.ItemIndex<>Ord(Printer.Orientation) then
  begin
    CheckOrientation;
    OrientationChange(Self);
  end;
end;

procedure TChartPreview.CBPrintPanelChange(Sender: TObject);
begin
  PrintTeePanel:=CBPrintPanel.IsChecked;
  TeePreviewPanel1.Invalidate;
end;

procedure TChartPreview.CBPropChange(Sender: TObject);
begin
  if not ChangingProp then
  begin
    TeePreviewPanel1.Panel.PrintProportional:=CBProp.IsChecked;
    ResetMargins;
    BReset.Enabled:=not CBProp.IsChecked;
  end;
end;

procedure TChartPreview.CBSmoothChange(Sender: TObject);
begin
  TeePreviewPanel1.AsBitmap:=CBSmooth.IsChecked;
end;

class function TChartPreview.CreateEditor(AOwner: TComponent;
  APanel: TCustomTeePanel): TForm;
begin
  result:=TChartPreview.Create(AOwner);
  TChartPreview(result).RefreshPanel(APanel);
end;

procedure TChartPreview.FormCreate(Sender: TObject);

  procedure AddPrinters;
  var t : Integer;
      tmp : TListBoxItem;
  begin
    for t:=0 to PrinterCount-1 do
    begin
      tmp:=TListBoxItem.Create(Self);
      tmp.Text:=Printer.Printers[t].Device;

      if Printer.ActivePrinter=Printer.Printers[t] then
         CBPrinters.ItemIndex:=t;

      CBPrinters.AddObject(tmp);
    end;
  end;

begin
  AddPrinters;
end;

class procedure TChartPreview.Preview(AOwner: TComponent;
  APanel: TCustomTeePanel);
begin
  with TChartPreview.CreateEditor(AOwner,APanel) do
  try
    ShowModal;
  finally
    Free;
  end;
end;

end.
