{********************************************************************}
{                                                                    }
{ written by TMS Software                                            }
{            copyright © 2013                                        }
{            Email : info@tmssoftware.com                            }
{            Web : http://www.tmssoftware.com                        }
{                                                                    }
{ The source code is given as is. The author is not responsible      }
{ for any possible damage done due to the use of this code.          }
{ The complete source code remains property of the author and may    }
{ not be distributed, published, given or sold in any form as such.  }
{ No parts of the source code can be included in any other component }
{ or application without written authorization of the author.        }
{********************************************************************}

unit FMX.TMSPrintPreview;

interface

{$I TMSDEFS.INC}

uses
  SysUtils, Types, UITypes, Classes, Variants, StrUtils,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.TMSGrid, FMX.Objects,
  FMX.TMSBitmap, FMX.Edit, FMX.TMSProgressBar, {$IFNDEF ANDROID}FMX.Printer,{$ENDIF} FMX.TMSBaseControl
  , FMX.StdCtrls
  {$IFDEF DELPHIXE5_LVL}
  , FMX.Graphics
  {$ENDIF}
  ;

type
  TTMSFMXGridPrintPreviewDialog = class;

  TTMSFMXPrintPreviewDialogForm = class(TForm)
    btnNext: TButton;
    btnPrevious: TButton;
    TMSFMXBitmap1: TTMSFMXBitmap;
    Panel1: TPanel;
    GroupBox1: TGroupBox;
    rdbAll: TRadioButton;
    rdbPages: TRadioButton;
    rdbCurrent: TRadioButton;
    Edit1: TEdit;
    TMSFMXProgressBar1: TTMSFMXProgressBar;
    btnPrint: TButton;
    Button1: TButton;
    StyleBook1: TStyleBook;
    procedure Button1Click(Sender: TObject);
    procedure btnPrintClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnNextClick(Sender: TObject);
    procedure btnPreviousClick(Sender: TObject);
    procedure FormResize(Sender: TObject);
  private
    FDialog: TTMSFMXGridPrintPreviewDialog;
    FOnPrint: TNotifyEvent;
    FOnClose: TNotifyEvent;
    { Private declarations }
  public
    { Public declarations }
    procedure Init;
    {$IFNDEF ANDROID}
    procedure PrintProgress(Sender: TObject; APageIndex: Integer; APrinter: TPrinter; APrintProgress: Single);
    {$ENDIF}
    property Dialog: TTMSFMXGridPrintPreviewDialog read FDialog write FDialog;
    property OnClose: TNotifyEvent read FOnClose write FOnClose;
    property OnPrint: TNotifyEvent read FOnPrint write FOnPrint;
  end;

  TPrintPreviewUILanguage = class(TPersistent)
  public
    constructor Create(AOwner: TComponent);
    procedure Assign(Source: TPersistent); override;
  published
  end;

  TTMSFMXPrintPreviewDialogOption = (pdoTitle, pdoPageNavigation, pdoPrintButton, pdoPageSelection);

  TTMSFMXPrintPreviewDialogOptions = set of TTMSFMXPrintPreviewDialogOption;

  [ComponentPlatformsAttribute(TMSPlatforms)]
  TTMSFMXGridPrintPreviewDialog = class(TComponent)
  private
    FUILanguage: TPrintPreviewUILanguage;
    FOptions: TTMSFMXPrintPreviewDialogOptions;
    FGrid: TTMSFMXGrid;
    FCloseOnPrint: Boolean;
    FOnPrint: TNotifyEvent;
    FOnClose: TNotifyEvent;
    procedure SetUILanguage(const Value: TPrintPreviewUILanguage);
    procedure SetOptions(const Value: TTMSFMXPrintPreviewDialogOptions);
  protected
    function CreateDialogForm(AOwner: TComponent): TTMSFMXPrintPreviewDialogForm; virtual;
    function InitDialog: TCustomForm; virtual;
    procedure DoClose(Sender: TObject);
    procedure DoPrint(Sender: TObject);
  public
    procedure Execute; virtual;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Options: TTMSFMXPrintPreviewDialogOptions read FOptions write SetOptions default [pdoTitle, pdoPageNavigation, pdoPrintButton, pdoPageSelection];
    property UILanguage: TPrintPreviewUILanguage read FUILanguage write SetUILanguage;
    property Grid: TTMSFMXGrid read FGrid write FGrid;
    property CloseOnPrint: Boolean read FCloseOnPrint write FCloseOnPrint default True;
    property OnClose: TNotifyEvent read FOnClose write FOnClose;
    property OnPrint: TNotifyEvent read FOnPrint write FOnPrint;
  end;


var
  TMSFMXPrintPreviewDialogForm: TTMSFMXPrintPreviewDialogForm;
  MaxPages: Integer;
  PageIndex: Integer;
  bmp: TBitmap;

implementation

{$R *.fmx}

{ TTMSFMXPrintPreviewDialog }

constructor TTMSFMXGridPrintPreviewDialog.Create(AOwner: TComponent);
begin
  inherited;
  FUILanguage := TPrintPreviewUILanguage.Create(Self);
  FOptions := [pdoTitle, pdoPageNavigation, pdoPrintButton, pdoPageSelection];
  FCloseOnPrint := True;
end;

function TTMSFMXGridPrintPreviewDialog.CreateDialogForm(
  AOwner: TComponent): TTMSFMXPrintPreviewDialogForm;
begin
  Result := TTMSFMXPrintPreviewDialogForm.Create(AOwner);
end;

destructor TTMSFMXGridPrintPreviewDialog.Destroy;
begin
  FUILanguage.Free;
  inherited;
end;

procedure TTMSFMXGridPrintPreviewDialog.DoClose(Sender: TObject);
begin
  if Assigned(OnClose) then
    OnClose(Self);
end;

procedure TTMSFMXGridPrintPreviewDialog.DoPrint(Sender: TObject);
begin
  if Assigned(OnPrint) then
    OnPrint(Self);
end;

procedure TTMSFMXGridPrintPreviewDialog.Execute;
var
  frm: TTMSFMXPrintPreviewDialogForm;
begin
  if not Assigned(Grid) then
  begin
    raise Exception.Create('The dialog does not have a TMS FireMonkey Grid Component assigned.');
    Exit;
  end;

  frm := InitDialog as TTMSFMXPrintPreviewDialogForm;
  frm.ShowModal;
end;

function TTMSFMXGridPrintPreviewDialog.InitDialog: TCustomForm;
var
  frm: TTMSFMXPrintPreviewDialogForm;
begin
  frm := CreateDialogForm(Self);
  frm.Dialog := Self;
  frm.OnClose := DoClose;
  frm.OnPrint := DoPrint;
  frm.btnPrevious.Enabled := False;
  frm.Init;

  Result := frm;
end;

procedure TTMSFMXGridPrintPreviewDialog.SetOptions(
  const Value: TTMSFMXPrintPreviewDialogOptions);
begin
  if FOptions <> Value then
    FOptions := Value;
end;

procedure TTMSFMXGridPrintPreviewDialog.SetUILanguage(
  const Value: TPrintPreviewUILanguage);
begin
  FUILanguage.Assign(Value);
end;

{ TPrintPreviewUILanguage }

procedure TPrintPreviewUILanguage.Assign(Source: TPersistent);
begin
  inherited;
end;

constructor TPrintPreviewUILanguage.Create(AOwner: TComponent);
begin

end;

procedure TTMSFMXPrintPreviewDialogForm.Button1Click(Sender: TObject);
begin
  Close;
end;

procedure TTMSFMXPrintPreviewDialogForm.FormDestroy(Sender: TObject);
begin
  if Assigned(bmp) then
    bmp.Free;
end;

procedure TTMSFMXPrintPreviewDialogForm.FormResize(Sender: TObject);
begin
  btnNext.Position.X := ClientWidth - btnNext.Width - 3;
  btnPrevious.Position.X := 3;
  btnPrevious.Position.Y := ((ClientHeight - Panel1.Height) - (btnPrevious.Height)) / 2;
  btnNext.Position.Y := ((ClientHeight - Panel1.Height) - (btnNext.Height)) / 2;

  Button1.Position.X := Panel1.Width - Button1.Width - 5;
  btnPrint.Position.X := Button1.Position.X - btnPrint.width - 5;
end;

procedure TTMSFMXPrintPreviewDialogForm.Init;
begin
  {$IFNDEF ANDROID}
  MaxPages := Dialog.Grid.GetPrintPageCount;
  PageIndex := 1;

  Printer.Orientation := Dialog.Grid.Options.Printing.PrinterOrientation;
  bmp := TBitmap.Create(Printer.PageWidth, Printer.PageHeight);
  bmp.Canvas.BeginScene;

  Dialog.Grid.PrintPage(PageIndex, bmp.Canvas, True);

  bmp.Canvas.EndScene;

  TMSFMXBitmap1.Bitmap.Assign(bmp);

  btnNext.Enabled := MaxPages > 1;
  {$ENDIF}
end;

{$IFNDEF ANDROID}
procedure TTMSFMXPrintPreviewDialogForm.PrintProgress(Sender: TObject; APageIndex: Integer;
  APrinter: TPrinter; APrintProgress: Single);
begin
  TMSFMXProgressBar1.Value := APrintProgress;
  TMSFMXProgressBar1.Repaint;
end;
{$ENDIF}

procedure TTMSFMXPrintPreviewDialogForm.btnNextClick(Sender: TObject);
begin
  {$IFNDEF ANDROID}
  Inc(PageIndex);
  bmp.Canvas.BeginScene;
  Dialog.Grid.PrintPage(PageIndex, bmp.Canvas, True);
  bmp.Canvas.EndScene;
  TMSFMXBitmap1.Bitmap.Assign(bmp);
  btnNext.Enabled := PageIndex < MaxPages;
  btnPrevious.Enabled := PageIndex > 1;
  {$ENDIF}
end;

procedure TTMSFMXPrintPreviewDialogForm.btnPreviousClick(Sender: TObject);
begin
  {$IFNDEF ANDROID}
  Dec(PageIndex);
  bmp.Canvas.BeginScene;
  Dialog.Grid.PrintPage(PageIndex, bmp.Canvas, True);
  bmp.Canvas.EndScene;
  TMSFMXBitmap1.Bitmap.Assign(bmp);
  btnNext.Enabled := PageIndex < MaxPages;
  btnPrevious.Enabled := PageIndex > 1;
  {$ENDIF}
end;

procedure TTMSFMXPrintPreviewDialogForm.btnPrintClick(Sender: TObject);
{$IFNDEF ANDROID}
var
  strPages: String;
  strArr: TStringDynArray;
  pg: Array of Integer;
  I: Integer;
{$ENDIF}
begin
  {$IFNDEF ANDROID}
  TMSFMXProgressBar1.Visible := True;
  Dialog.Grid.OnPrintPreviewProgress := PrintProgress;

  if rdbAll.IsChecked then
    Dialog.Grid.Print
  else if rdbCurrent.IsChecked then
    Dialog.Grid.PrintPage(PageIndex)
  else if rdbPages.IsChecked then
  begin
    strPages := Edit1.Text;
    strarr := SplitString(strPages, ',');

    for I := 0 to Length(strArr) - 1 do
    begin
      SetLength(pg, I + 1);
      pg[I] := strtoint(strArr[I]);
    end;

    Dialog.Grid.PrintPages(pg);
  end;

  if Assigned(OnPrint) then
    OnPrint(Self);

  Dialog.Grid.OnPrintPreviewProgress := nil;
  TMSFMXProgressBar1.Visible := False;

  if Dialog.CloseOnPrint then
    Close;
  {$ENDIF}
end;

end.
