unit PrvForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ExtCtrls,Printers,PCTypesUtils, siComp, siLngLnk,
  Mask, RzEdit, RzSpnEdt, RzCmboBx;

type
  TfrmPrv = class(TForm)
    ScrollBox1: TScrollBox;
    bClose: TBitBtn;
    prnLabel: TLabel;
    pbox: TPaintBox;
    bSetting: TBitBtn;
    bPrint: TBitBtn;
    lng_Forms: TsiLangLinked;
    pnDivOverlay: TPanel;
    lbDivOverlay: TLabel;
    seDivOverlay: TRzSpinEdit;
    lbDivOverlayUOM: TLabel;
    pnScale: TPanel;
    lbScale: TLabel;
    cbScale: TRzComboBox;
    Label1: TLabel;
    Label2: TLabel;
    lbPageCount: TLabel;
    Timer_Scale: TTimer;
    procedure bCloseClick(Sender: TObject);
    procedure pboxPaint(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure bSettingClick(Sender: TObject);
    procedure bPrintClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure cbScaleKeyPress(Sender: TObject; var Key: Char);
    procedure Timer_ScaleTimer(Sender: TObject);
    procedure cbScaleChange(Sender: TObject);
  private
    FScaleKoeff: Double;
    FIdxScaleToPaper: Integer;
    { Private declarations }
    Procedure DrawPage;
    Procedure DrawMargins;
    procedure AddIntItemToScales(AVal: Integer);
    procedure DefineScaleKoeff;
  public
    { Public declarations }
    tBmp: TBitmap;
    CadControl: Pointer;
    FPrRect: TDoubleRect;
    FIsRect: Boolean;
    Procedure Init(AStartPreview: Boolean=false);
  end;

var
  frmPrv: TfrmPrv;
  prnName: String;
  resX,resY: Integer;
  offX,offY: Integer;
  dx,dy: Integer;
  dScale: Double;
  ox,oy,pw,ph:Integer;
  dpm: Double;
  Init_prnW: Integer;
  Init_prnH: Integer;


implementation

{$R *.DFM}
uses PCDrawing, U_Constants, U_Common, U_BaseCommon;

{ TfrmPrv }

procedure TfrmPrv.Init(AStartPreview: Boolean=false);
var
  Cad: TPCDrawing;
  TmpInitPrnW: Integer;
  TmpInitPrnH: Integer;
  prnW,prnH: Double; //06.12.2011 Integer;
  pw, ph: integer;
  prow, pcol : integer;
  OFFX, OFFY: integer;
  ShowDivOverlay: Boolean;
begin
  Cad := TPCDrawing(CadControl);
  prnName := Printer.Printers[Printer.PrinterIndex];
  prnLabel.Caption := cPrevForm_Mes1 + prnName;

  CAD.DefinePrnDivIndent;
  
  ShowDivOverlay := false;
  if Not FIsRect then
    FPrRect := DoubleRect(0,0,Cad.WorkWidth,Cad.WorkHeight);

  if AStartPreview then
  begin
    cbScale.ItemIndex := cbScale.IndexOf(IntToStr(100));
    FScaleKoeff := 1;
    DefineScaleKoeff;
  end;

  if not GPreview then
  begin
    //02.12.2011 Init_prnW := GetDeviceCaps(printer.Handle, PHYSICALWIDTH);
    //02.12.2011 Init_prnH := GetDeviceCaps(printer.Handle, PHYSICALHEIGHT);
  end;
  //25.11.2011 - подганяем превью под выделенный размер
  TmpInitPrnW := GetDeviceCaps(printer.Handle, PHYSICALWIDTH);
  TmpInitPrnH := GetDeviceCaps(printer.Handle, PHYSICALHEIGHT);
  prnW := GetDeviceCaps(printer.Handle, PHYSICALWIDTH);
  prnH := GetDeviceCaps(printer.Handle, PHYSICALHEIGHT);
  resX := GetDeviceCaps(printer.Handle, LOGPIXELSX);
  resY := GetDeviceCaps(printer.Handle, LOGPIXELSY);
  OFFX := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
  OFFY := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);
  pw := round(prnW / (resX / 25.4));
  ph := round(prnH / (resY / 25.4));
  // Переводим в точки
  //prnW := round(prnW * ( (Abs(FPrRect.Right - FPrRect.Left)*FScaleKoeff) / pw));
  //prnH := round(prnH * ( (Abs(FPrRect.Bottom - FPrRect.Top)*FScaleKoeff) / ph));
  prnW := round(prnW * ( (Abs(FPrRect.Right - FPrRect.Left)) / pw));
  prnH := round(prnH * ( (Abs(FPrRect.Bottom - FPrRect.Top)) / ph));
  if (prnW > TmpInitPrnW) or (prnH > TmpInitPrnH) then
  begin
    //ShowDivOverlay := true;
    if FIsRect then
    begin
      TmpInitPrnW := Round(PrnW);
      TmpInitPrnH := Round(PrnH);
    end;
  end;
  if not GPreview then
  begin
    Init_prnW := TmpInitPrnW;
    Init_prnH := TmpInitPrnH;
  end;

  //06.12.2011 Если печатаемый размер больше размера страницы, то отображаем параметры наложения
  prnW := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH);
  prnH := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);
  resX := GetDeviceCaps(printer.Handle, LOGPIXELSX);
  resY := GetDeviceCaps(printer.Handle, LOGPIXELSY);
  // Переводим в мм
  prnW := (prnW / resX) * 25.4;
  prnH := (prnH / resY) * 25.4;
  // Если размера бумаги меньше размера печатаемой области
  if ((prnW+prnReservTiling) < (Abs(FPrRect.Right - FPrRect.Left)*FScaleKoeff)) or
     ((prnH+prnReservTiling) < (Abs(FPrRect.Bottom - FPrRect.Top)*FScaleKoeff)) then
    ShowDivOverlay := true;
  //Количество листов
  Cad.CalcPrDims(prnW, prnH, prow, pcol, Abs(FPrRect.Right - FPrRect.Left), Abs(FPrRect.Bottom - FPrRect.Top), FScaleKoeff);
  lbPageCount.Caption := IntToStr(prow * pcol);

//  GPreview := False;
  resX := GetDeviceCaps(printer.Handle, LOGPIXELSX);
  resY := GetDeviceCaps(printer.Handle, LOGPIXELSY);
  offX := GetDeviceCaps(printer.Handle, PHYSICALOFFSETX	);
  offY := GetDeviceCaps(printer.Handle, PHYSICALOFFSETY	);
//  offX := 0;
//  offY := 0;

  //01.12.2011
  pnDivOverlay.Visible := ShowDivOverlay;
  seDivOverlay.Value := 0;
  lbDivOverlayUOM.Caption := GetNameUOM(ConvertUOMToMin(GCurrProjUnitOfMeasure), true);
end;

procedure TfrmPrv.bCloseClick(Sender: TObject);
begin
  Close;
end;

procedure TfrmPrv.pboxPaint(Sender: TObject);
var
  //clpRgn: Integer;
  clpRgn: HRGN;
begin
  {//24.11.2011
  DrawPage;
  tbmp.Canvas.Brush.Color := clWhite;
  tbmp.Canvas.Brush.Style := bsSolid;
  tbmp.Canvas.FillRect(Rect(0,0,tbmp.Width,tbmp.Height));
  TPCDrawing(CadControl).DrawToCanvas(tbmp.canvas, dx, dy, dScale);
  clpRgn := CreateRectRgn(dx + ox, dy + ox, dx + pw - ox, dy + ph - ox);
  SelectClipRgn(pbox.canvas.handle,clpRgn);
  Pbox.Canvas.Draw(0, 0, tbmp);
  SelectClipRgn(pbox.canvas.handle, 0);
  DeleteObject(ClpRgn);
  DrawMargins; }

  DrawPage;
  tbmp.Canvas.Brush.Color := clWhite;
  tbmp.Canvas.Brush.Style := bsSolid;
  tbmp.Canvas.FillRect(Rect(0,0,tbmp.Width,tbmp.Height));
  if Not FIsRect then
  begin
    TPCDrawing(CadControl).DrawToCanvas(tbmp.canvas, dx, dy, dScale);
  end
  else
  begin
    //TPCDrawing(CadControl).tileX := ;
    //TPCDrawing(CadControl).tileY := y1;
    TPCDrawing(CadControl).DrawRectToCanvas(FPrRect, tbmp.canvas, dx, dy, dScale);
  end;
  clpRgn := CreateRectRgn(dx + ox, dy + ox, dx + pw - ox, dy + ph - ox);
  SelectClipRgn(pbox.canvas.handle,clpRgn);
  Pbox.Canvas.Draw(0, 0, tbmp);
  SelectClipRgn(pbox.canvas.handle, 0);
  DeleteObject(ClpRgn);
  DrawMargins;
end;

procedure TfrmPrv.DrawPage;
var
  xr, yr, cr: Double;
  dpmO: Double;
  q: integer;
begin
//  q := prnW;
//  prnW := (prnH * 2);
//  prnH := q;
  xr := (pbox.Width - 10) / Init_prnW;
  yr := (pBox.Height - 10) / Init_prnH;
  if xr < yr then
    cr := xr
  else
    cr := yr;
  pw := round(Init_prnW * cr);
  ph := round(Init_prnH * cr);
  ox := round(offX * cr);
  oy := round(offY * cr);
  if ox < 3 then
    ox := 3;
  if oy < 3 then
    oy := 3;
  dx := (pbox.Width - pw) div 2;
  dy := (pbox.Height - ph) div 2;

  dpm := (((pw * resx) / Init_prnW) / 25.4);
  dpmO := TPCDrawing(CadControl).DotsPerMilOrig;
  dScale := dpm / dpmO;

  pbox.Canvas.Brush.Style := bsSolid;
  pbox.Canvas.Brush.Color := clGray;
  pbox.Canvas.Pen.Color := clGray;
  pbox.Canvas.Pen.Style := psSolid;
  pbox.Canvas.Rectangle(dx + 4, dy + 4, dx + pw + 4, dy + ph + 4);
  pbox.Canvas.Pen.Color := clBlack;
  pbox.Canvas.Brush.Color := clWhite;
  pbox.Canvas.Rectangle(dx, dy, dx + pw, dy + ph);
end;

procedure TfrmPrv.DrawMargins;
begin
  pbox.Canvas.pen.Color := clRed;
  pbox.Canvas.MoveTo(dx+ox,dy);
  pbox.Canvas.LineTo(dx+ox,dy+ph);
  pbox.Canvas.MoveTo(dx,dy+oy);
  pbox.Canvas.LineTo(dx+pw,dy+oy);
  pbox.Canvas.MoveTo(dx+pw-ox,dy);
  pbox.Canvas.LineTo(dx+pw-ox,dy+ph);
  pbox.Canvas.MoveTo(dx,dy+ph-oy);
  pbox.Canvas.LineTo(dx+pw,dy+ph-oy);
end;

procedure TfrmPrv.AddIntItemToScales(AVal: Integer);
begin
  cbScale.Items.AddObject(IntToStr(AVal), TObject(AVal));  
end;

procedure TfrmPrv.DefineScaleKoeff;
var
  Prcnt: Double;

  TmpInitPrnW: Integer;
  TmpInitPrnH: Integer;
  prnW,prnH: Double;
  pw, ph: Double;
  WorkWidth, WorkHeight: Double;
  OFFX, OFFY: integer;
begin
  if (cbScale.ItemIndex <> -1) then
  begin
    // Подганяем под размер бумаги
    if (cbScale.ItemIndex = FIdxScaleToPaper) then
    begin
      { //06.12.2011 - работате не очень кошерно
      //OFFX := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
      //OFFY := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);
      TmpInitPrnW := GetDeviceCaps(printer.Handle, PHYSICALWIDTH);
      TmpInitPrnH := GetDeviceCaps(printer.Handle, PHYSICALHEIGHT);
      prnW := TmpInitPrnW; // - OFFX*2;
      prnH := TmpInitPrnH; // - OFFY*2;
      resX := GetDeviceCaps(printer.Handle, LOGPIXELSX);
      resY := GetDeviceCaps(printer.Handle, LOGPIXELSY);

      pw := prnW / (resX / 25.4);
      ph := prnH / (resY / 25.4);

      // Переводим в точки
      prnW := round(prnW * (Abs(FPrRect.Right - FPrRect.Left) / pw));
      prnH := round(prnH * (Abs(FPrRect.Bottom - FPrRect.Top) / ph));
      // Если выходим за пределы размера бумаги
      if (prnW > TmpInitPrnW) or (prnH > TmpInitPrnH) then
      begin
        // Если по ширине больше
        if Abs(prnW - TmpInitPrnW) > Abs(prnH - TmpInitPrnH) then
          FScaleKoeff := TmpInitPrnW / prnW
        else
        // Иначе если по высоте больше
          FScaleKoeff := TmpInitPrnH / prnH;
      end
      else
      // Иначе увеличить под размер бумаги
      if (TmpInitPrnW > prnW) or (TmpInitPrnH > prnH) then
      begin
        // Если по ширине ближе к краю бумаги
        if Abs(TmpInitPrnW - prnW) < Abs(TmpInitPrnH - prnH) then
          FScaleKoeff := TmpInitPrnW / prnW
        else
          FScaleKoeff := TmpInitPrnH / prnH;
      end;}

      //------------------------------
      WorkWidth := Abs(FPrRect.Right - FPrRect.Left); // - TPCDrawing(CadControl).prnDivIndentX;
      WorkHeight := Abs(FPrRect.Bottom - FPrRect.Top); // - TPCDrawing(CadControl).prnDivIndentY;
      prnW := GetDeviceCaps(Printer.Handle, PHYSICALWIDTH);
      prnH := GetDeviceCaps(Printer.Handle, PHYSICALHEIGHT);
      resX := GetDeviceCaps(printer.Handle, LOGPIXELSX);
      resY := GetDeviceCaps(printer.Handle, LOGPIXELSY);
      // Переводим в мм
      prnW := (prnW / resX) * 25.4;
      prnH := (prnH / resY) * 25.4;
      // Если размера бумаги меньше размера печатаемой области
      if (prnW < WorkWidth) or (prnH < WorkHeight) then
      begin
        // Если по ширине больше
        if Abs(WorkWidth - prnW) > Abs(WorkHeight - prnH) then
          FScaleKoeff := (prnW-TPCDrawing(CadControl).prnDivIndentX*1.5) / WorkWidth
        else
        // Иначе если по высоте больше
          FScaleKoeff := (prnH-TPCDrawing(CadControl).prnDivIndentY*1.5) / WorkHeight;
      end
      else
      if (WorkWidth < prnW) or (WorkHeight < prnH) then
      begin
        // Если по ширине больше
        if Abs(prnW - WorkWidth) < Abs(prnH - WorkHeight) then
          FScaleKoeff := (prnW - TPCDrawing(CadControl).prnDivIndentX) / WorkWidth
        else
        // Иначе если по высоте больше
          FScaleKoeff := (prnH - TPCDrawing(CadControl).prnDivIndentY) / WorkHeight;
      end;
    end
    else
    begin
      Prcnt := StrToFloatDef_My(cbScale.Items[cbScale.ItemIndex], 0);
      if Prcnt > 0 then
        FScaleKoeff := Prcnt / 100;
    end;
  end
  else
  begin
    Prcnt := StrToFloatDef_My(cbScale.Text, 0);
    if Prcnt > 0 then
      FScaleKoeff := Prcnt / 100;
  end;
end;

procedure TfrmPrv.FormCreate(Sender: TObject);
begin
  tBmp := tBitmap.Create;
  tbmp.Width := pbox.width;
  tbmp.Height := pbox.height;

  FIsRect := false;

  //AddIntItemToScales(10);
  AddIntItemToScales(25);
  AddIntItemToScales(50);
  AddIntItemToScales(75);
  AddIntItemToScales(100);
  AddIntItemToScales(150);
  AddIntItemToScales(200);
  AddIntItemToScales(400);
  AddIntItemToScales(500);
  FIdxScaleToPaper := cbScale.Items.Add(cPrnScaleToPaper);
  FScaleKoeff := 1;
end;

procedure TfrmPrv.bSettingClick(Sender: TObject);
begin
  TPCDrawing(CadControl).ExecuteTBCommand(cPrinterSetup);
  Init;
  PBox.Refresh;
end;

procedure TfrmPrv.bPrintClick(Sender: TObject);
var
  oldScale: Double;
begin
  TPCDrawing(CadControl).prnDivOverlay := FloatInUOM(seDivOverlay.Value, ConvertUOMToMin(GCurrProjUnitOfMeasure), umMM);
  oldScale := TPCDrawing(CadControl).prnScale;
  TPCDrawing(CadControl).prnScale := FScaleKoeff;
  try
    if Not FIsRect then
      TPCDrawing(CadControl).ExecuteTBCommand(cPrint)
    else
      TPCDrawing(CadControl).PrintRect(FPrRect);
  finally
    TPCDrawing(CadControl).prnScale := oldScale;
  end;
end;

procedure TfrmPrv.FormDestroy(Sender: TObject);
begin
  //tbmp.FreeImage;
  //tbmp.Free;
  //tbmp.free;
end;

procedure TfrmPrv.cbScaleKeyPress(Sender: TObject; var Key: Char);
begin
  Timer_Scale.Enabled := true;
end;

procedure TfrmPrv.cbScaleChange(Sender: TObject);
begin
  Timer_Scale.Enabled := true;
end;


procedure TfrmPrv.Timer_ScaleTimer(Sender: TObject);
begin
  TTimer(Sender).Enabled := false;

  DefineScaleKoeff;
  Init;
  PBox.Refresh;
end;

end.
