faxfield.pas
上传用户:dgeyuang
上传日期:2007-01-11
资源大小:65k
文件大小:76k
源码类别:

传真(Fax)编程

开发平台:

Delphi

  1. unit FaxField;
  2. {$I AWDEFINE.INC}
  3. interface
  4. uses
  5.   {$IFDEF Win32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  6.   Messages, Classes, Graphics, Controls, Forms, StdCtrls, ExtCtrls,
  7.   {$IFDEF DELPHI3} ExtDlgs, {$ENDIF}
  8.   Dialogs, Ruler,jpeg,menus;
  9. type
  10.   {Records used for saving cover page to a disk file}
  11.   TUserDataArray = array[0..1023] of Byte;
  12.   TPageRecord = packed record
  13.     prVersionNum       : string[11];
  14.     prPageWidthPixels  : LongInt;
  15.     prPageHeightPixels : LongInt;
  16.     prPageWidthInches  : Double;
  17.     prPageHeightInches : Double;
  18.     prIsMetric         : Boolean;
  19.     {Extra field for storing miscellaneous additional data}
  20.     prUserData         : TUserDataArray;
  21.   end;
  22.   TFieldRecord = packed record
  23.     frLeftInches   : Double;
  24.     frTopInches    : Double;
  25.     frWidthInches  : Double;
  26.     frHeightInches : Double;
  27.   end;
  28.   TFontRecord = packed record
  29.     frCharSet       : Byte;
  30.     frColor         : LongInt;
  31.     frHeight        : LongInt;
  32.     frName          : string[255];
  33.     frPitch         : Byte;
  34.     frSize          : LongInt;
  35.     frFontBold      : Boolean;
  36.     frFontItalic    : Boolean;
  37.     frFontUnderline : Boolean;
  38.     frFontStrikeout : Boolean;
  39.   end;
  40.   TStretchModes = (smNone, smDrag, smE, smW, smS, smN, smNE, smSW, smSE, smNW);
  41.   TStretchHandle = class(TPaintBox)
  42.   private
  43.     FHandlePosition : TStretchModes;
  44.   protected
  45.     procedure Paint; override;
  46.   public
  47.     constructor Create(AOwner : TComponent); override;
  48.     property HandlePosition : TStretchModes
  49.       read FHandlePosition write FHandlePosition;
  50.   end;
  51.   TStretchHandleArray = array[0..7] of TStretchHandle;
  52.   TBaseField = class(TShape)
  53.   private
  54.     FSelected        : Boolean;
  55.     FStretchMode     : TStretchModes;
  56.     bfStretchHandles : TStretchHandleArray;
  57.   protected
  58.     procedure bfMouseDown(Sender: TObject; Button: TMouseButton;
  59.                           Shift: TShiftState; X, Y: Integer);
  60.     procedure bfMouseUp(Sender: TObject; Button: TMouseButton;
  61.                         Shift: TShiftState; X, Y: Integer);
  62.     procedure bfMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  63.     procedure SetParent(AParent: TWinControl); override;
  64.     procedure SetSelected(IsSelected : Boolean);
  65.     function GetStretchHandleCoords(WhichHandle : TStretchModes) : TPoint;
  66.       {-Returns the coordinates (Left, Top) where the StretchHandle should be drawn}
  67.     procedure Write(Stream : TStream); virtual;
  68.       {-Writes all necessary TBaseField properties out to Stream}
  69.     procedure Read(Stream : TStream); virtual;
  70.       {-Reads BaseField properties from Stream and assigns those properties to Self}
  71.     procedure Draw(ACanvas : TCanvas); virtual; abstract;
  72.       {-Draws Self on ACanvas}
  73.   public
  74.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  75.     constructor Create(AOwner: TComponent); override;
  76.     property Selected : Boolean read FSelected write SetSelected;
  77.     property StretchMode : TStretchModes read FStretchMode write FStretchMode;
  78.   end;
  79.   TTextField = class(TBaseField)
  80.   protected
  81.     FMemo : TMemo;
  82.     FPopupMenu:TPopupMenu;
  83.     procedure SetParent(AParent: TWinControl); override;
  84.     function GetTextHeight : Integer;
  85.       {-Returns the height of one row of text, including external leading, given the
  86.         current font assigned to the field}
  87.     function GetText : string;
  88.     procedure Write(Stream : TStream); override;
  89.       {-Writes all necessary properties out to Stream}
  90.     procedure Read(Stream : TStream); override;
  91.       {-Reads properties from Stream and assigns those properties to Self}
  92.     procedure Draw(ACanvas : TCanvas); override;
  93.       {-Draws Self on ACanvas}
  94.     procedure tfEnter(Sender : TObject);
  95.     procedure tfExit(Sender : TObject);
  96.   public
  97.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  98.     constructor Create(AOwner: TComponent); override;
  99.     procedure MemoDblClick(Sender: TObject);
  100.     procedure OnLoadFromFile(Sender: TObject);
  101.     procedure SetFocus;
  102.     property Text : string read GetText;
  103.   end;
  104.   TImageField = class(TBaseField)
  105.   protected
  106.     FImage : TImage;
  107.     procedure SetParent(AParent: TWinControl); override;
  108.     function GetPicture : TPicture;
  109.     procedure Write(Stream : TStream); override;
  110.       {-Writes all necessary properties out to Stream}
  111.     procedure Read(Stream : TStream); override;
  112.       {-Reads properties from Stream and assigns those properties to Self}
  113.     procedure Draw(ACanvas : TCanvas); override;
  114.       {-Draws Self on ACanvas}
  115.   public
  116.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  117.     constructor Create(AOwner: TComponent); override;
  118.     procedure ImageDblClick(Sender: TObject);
  119.     property Picture : TPicture read GetPicture;
  120.   end;
  121.   TSelectionChangeEvent = procedure(IsFieldSelected : Boolean) of object;
  122.   TPositionChangeEvent = procedure(Left, Top, Width, Height : Integer) of object;
  123.   TFaxPanel = class(TPanel)
  124.   private
  125.     FShowGrid               : Boolean;
  126.     FSnapToGrid             : Boolean;
  127.     FGridSpacingX           : Integer;
  128.     FGridSpacingY           : Integer;
  129.     FPageWidthInches        : Double;
  130.     FPageHeightInches       : Double;
  131.     FEditMode               : Boolean; {Are we in Edit Mode or Design Mode}
  132.     FStretchMode            : TStretchModes;
  133.     FOnFieldSelectionChange : TSelectionChangeEvent;
  134.     FOnFieldPositionChange  : TPositionChangeEvent;
  135.     FNeedsSaving            : Boolean;
  136.     FPageCount              : Integer;
  137.     FPageNumber             : Integer;
  138.     FSender                 : string;
  139.     FRecipient              : string;
  140.     FPageTitle              : string;
  141.     FStationID              : string;
  142.     fpDragging              : Boolean;
  143.     fpMaxGridLine           : TPoint;
  144.     fpHorzPixelsPerInch     : Double;
  145.     fpVertPixelsPerInch     : Double;
  146.     fpMouseAnchor           : TPoint;
  147.     fpIsMouseDown           : Boolean;
  148.     fpFieldList             : TList;
  149.     function GetFieldCount : Integer;
  150.     function GetField(Index : Integer) : TBaseField;
  151.     function GetSelectedField : TBaseField;
  152.     procedure SetEditMode(Value : Boolean);
  153.     procedure SetPageWidthInches(AWidth : Double);
  154.     procedure SetPageHeightInches(AHeight : Double);
  155.     procedure SetShowGrid(AShowGrid : Boolean);
  156.     procedure SetSnapToGrid(ASnapToGrid : Boolean);
  157.     procedure SetGridSpacingX(GridSpacing : Integer);
  158.     procedure SetGridSpacingY(GridSpacing : Integer);
  159.     procedure AdjustLeftToGrid(var ALeft : Integer);
  160.       {-If SnapToGrid is True, adjusts ALeft to be on the nearest grid line}
  161.     procedure AdjustTopToGrid(var ATop : Integer);
  162.       {-If SnapToGrid is True, adjusts ATop to be on the nearest grid line}
  163.     procedure AdjustWidthToGrid(ALeft : Integer; var AWidth : Integer);
  164.       {-If SnapToGrid is True, adjusts AWidth to be on the nearest grid line.
  165.         Caller should ensure that ALeft is already on a grid line, possibly by
  166.         calling AdjustLeftToGrid.}
  167.     procedure AdjustHeightToGrid(ATop : Integer; var AHeight : Integer);
  168.       {-If SnapToGrid is True, adjusts AHeight to be on the nearest grid line.
  169.         Caller should ensure that ATop is already on a grid line, possibly by
  170.         calling AdjustTopToGrid.}
  171.     function GetDrawAdjustFactor : Double;
  172.     function GetDrawWidth : Integer;
  173.       {-Returns the width that the TCanvas passed to the Draw method should be}
  174.     function GetDrawHeight : Integer;
  175.       {-Returns the height that the TCanvas passed to the Draw method should be}
  176.     procedure SetStretchMode(NewStretchMode : TStretchModes);
  177.     procedure DeselectAllFields;
  178.     procedure DeleteAllFields;
  179.     procedure AddField(Field : TBaseField);
  180.   protected
  181.     procedure Paint; override;
  182.     procedure fpResize(Sender : TObject);
  183.     procedure fpMouseUp(Sender: TObject; Button: TMouseButton;
  184.       Shift: TShiftState; X, Y: Integer);
  185.     procedure fpMouseDown(Sender: TObject; Button: TMouseButton;
  186.       Shift: TShiftState; X, Y: Integer);
  187.     procedure fpMouseMove(Sender: TObject; Shift: TShiftState; X,
  188.       Y: Integer);
  189.     procedure FieldSelectionChange(IsFieldSelected : Boolean);
  190.       {-Calls OnFieldSelectionChange event handler when a field becomes
  191.         deselected or when a new field becomes selected}
  192.     procedure FieldPositionChange(ALeft, ATop, AWidth, AHeight : Integer);
  193.       {-Calls OnFieldPositionChange event handler when the location or size of
  194.         the currently-selected field changes}
  195.     procedure FieldChange(Sender : TObject);
  196.     property Canvas;
  197.     property StretchMode : TStretchModes read FStretchMode write SetStretchMode;
  198.     property PageWidthInches : Double read FPageWidthInches write SetPageWidthInches;
  199.     property PageHeightInches : Double read FPageHeightInches write SetPageHeightInches;
  200.     property DrawAdjustFactor : Double read GetDrawAdjustFactor;
  201.   public
  202.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  203.     constructor Create(AOwner : TComponent); override;
  204.     destructor Destroy; override;
  205.     function HorzPixelsToInches(P : Integer) : Double;
  206.       {-Returns the value of P converted to inches given the current values of
  207.         Width and PageWidthInches}
  208.     function VertPixelsToInches(P : Integer) : Double;
  209.       {-Returns the value of P converted to inches given the current values of
  210.         Height and PageHeightInches}
  211.     function HorzInchesToPixels(Inches : Double) : Integer;
  212.       {-Returns the value of Inches converted to pixels given the current values
  213.         of Width and PageWidthInches}
  214.     function VertInchesToPixels(Inches : Double) : Integer;
  215.       {-Returns the value of Inches converted to pixels given the current values
  216.         of Height and PageHeightInches}
  217.     procedure SizeMove(Sender : TObject; Key : Word; Shift : TShiftState);
  218.       {-move/size the field}
  219.     function AddTextField : TTextField;
  220.     function AddImageField : TImageField;
  221.     procedure DeleteSelectedField;
  222.       {-Deletes currently selected field}
  223.     procedure CenterSelectedField(IsHorizontal : Boolean);
  224.       {-Centers the currently-selected field within the panel. IsHorizontal
  225.         specifies whether the field will be centered vertically or horizontally.}
  226.     function SelectedFieldsExist : Boolean;
  227.       {-Returns True if the panel contains at least one selected field}
  228.     procedure FieldPositionChangeForSelectedField;
  229.       {-If a selected field exists, calls FieldPositionChange with that field's
  230.         coordinates}
  231.     procedure Write(Stream : TStream);
  232.       {-Writes all defining information out to Stream}
  233.     procedure Read(Stream : TStream);
  234.       {-Reads Stream and loads its properties into Self}
  235.     procedure Draw(ACanvas : TCanvas);
  236.       {-Draws an image of Self, including all fields, on ACanvas}
  237.     property ShowGrid : Boolean read FShowGrid write SetShowGrid;
  238.     property SnapToGrid : Boolean read FSnapToGrid write SetSnapToGrid;
  239.     property GridSpacingX : Integer read FGridSpacingX write SetGridSpacingX;
  240.     property GridSpacingY : Integer read FGridSpacingY write SetGridSpacingY;
  241.     property EditMode : Boolean
  242.       read FEditMode
  243.       write SetEditMode;
  244.     property NeedsSaving : Boolean read FNeedsSaving write FNeedsSaving;
  245.     property OnFieldSelectionChange : TSelectionChangeEvent
  246.       read FOnFieldSelectionChange write FOnFieldSelectionChange;
  247.     property OnFieldPositionChange : TPositionChangeEvent
  248.       read FOnFieldPositionChange write FOnFieldPositionChange;
  249.     {When creating a bitmap for use in creating an APF file, the bitmap's width
  250.      should be set to TFaxPanel.DrawWidth, and the bitmap's height should be
  251.      set to TFaxPanel.DrawHeight.}
  252.     property DrawWidth : Integer read GetDrawWidth;
  253.       {-Returns the width that the TCanvas passed to the Draw method should be}
  254.     property DrawHeight : Integer read GetDrawHeight;
  255.       {-Returns the height that the TCanvas passed to the Draw method should be}
  256.     property FieldCount : Integer
  257.       read GetFieldCount;
  258.     property Field[Index : Integer] : TBaseField
  259.       read GetField;
  260.     property SelectedField : TBaseField
  261.       read GetSelectedField;
  262.     {These properties are the values that are substituted for replacement tags
  263.      when the cover page is saved as an APF file}
  264.     property PageCount : Integer read FPageCount write FPageCount;
  265.       {-Value substituted for $N replacement tag}
  266.     property PageNumber : Integer read FPageNumber write FPageNumber;
  267.       {-Value substituted for $P replacement tag}
  268.     property Sender : string read FSender write FSender;
  269.       {-Value substituted for $F replacement tag}
  270.     property Recipient : string read FRecipient write FRecipient;
  271.       {-Value substituted for $R replacement tag}
  272.     property PageTitle : string read FPageTitle write FPageTitle;
  273.       {-Value substituted for $S replacement tag}
  274.     property StationID : string read FStationID write FStationID;
  275.       {-Value substituted for $I replacement tag}
  276.   end;
  277.   TFaxScrollBox = class(TScrollBox)
  278.   private
  279.     FOnHorzScroll : TScrollEvent;
  280.     FOnVertScroll : TScrollEvent;
  281.     procedure WMHScroll(var Message : TWMHScroll); message WM_HSCROLL;
  282.     procedure WMVScroll(var Message : TWMVScroll); message WM_VSCROLL;
  283.   public
  284.     property OnHorzScroll : TScrollEvent read FOnHorzScroll write FOnHorzScroll;
  285.     property OnVertScroll : TScrollEvent read FOnVertScroll write FOnVertScroll;
  286.   end;
  287.   TFaxDesigner = class(TPanel)
  288.   private
  289.     FFaxPanel   : TFaxPanel;
  290.     FIsNew      : Boolean;
  291.     FIsMetric   : Boolean;
  292.     FUserData   : TUserDataArray;
  293.     fdHorzRuler : TRuler;
  294.     fdVertRuler : TRuler;
  295.     fdScrollBox : TFaxScrollBox;
  296.     procedure HorzScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer);
  297.     procedure VertScroll(Sender: TObject; ScrollCode: TScrollCode; var ScrollPos: Integer);
  298.     function GetPageWidthPixels : Integer;
  299.     procedure SetPageWidthPixels(AWidth : Integer);
  300.     function GetPageHeightPixels : Integer;
  301.     procedure SetPageHeightPixels(AHeight : Integer);
  302.     function GetPageWidthInches : Double;
  303.     procedure SetPageWidthInches(AWidth : Double);
  304.     function GetPageHeightInches : Double;
  305.     procedure SetPageHeightInches(AHeight : Double);
  306.     procedure SetIsMetric(AIsMetric : Boolean);
  307.     procedure SetMarkPositions(ALeft, ATop, AWidth, AHeight : Integer);
  308.       {-Sets the position of the red position marks on the Ruler bars. To
  309.         suppress drawing of the marks, set to a negative value.}
  310.   protected
  311.     procedure SetParent(AParent: TWinControl); override;
  312.   public
  313.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  314.     constructor Create(AOwner : TComponent); override;
  315.     procedure Write(Stream : TStream);
  316.       {-Writes all defining information out to Stream}
  317.     procedure Read(Stream : TStream);
  318.       {-Reads Stream and loads its properties into Self}
  319.     property FaxPanel : TFaxPanel read FFaxPanel;
  320.     property PageWidthPixels  : Integer read GetPageWidthPixels write SetPageWidthPixels;
  321.     property PageHeightPixels : Integer read GetPageHeightPixels write SetPageHeightPixels;
  322.     property PageWidthInches  : Double read GetPageWidthInches write SetPageWidthInches;
  323.     property PageHeightInches : Double read GetPageHeightInches write SetPageHeightInches;
  324.     property IsMetric : Boolean read FIsMetric write SetIsMetric;
  325.     property UserData : TUserDataArray read FUserData write FUserData;
  326.       {-Misc data field. Gets written to and read from the Stream when Write or
  327.         Read are called}
  328.     property IsNew : Boolean read FIsNew write FIsNew;
  329.       {-Returns True if this is a new cover page that hasn't been given a real
  330.         name yet. Returns False if this cover page was read in using the Read
  331.         method or if it was written out using the Write method.}
  332.   end;
  333. implementation
  334. uses SysUtils;
  335. const
  336.   ctVersionNum   = '1.00';
  337.   ftTextField    = 0;
  338.   ftImageField   = 1;
  339.   ctGridStart    = 1;
  340.   ctGridSpacingX = 20;
  341.   ctGridSpacingY = 20;
  342.   ctDefaultWidthPixels  = 600;
  343.   ctDefaultHeightPixels = 776;
  344.   ctDefaultWidthInches  = 8.5;
  345.   ctDefaultHeightInches = 11.0;
  346.   ctStretchHandleSize   = 5; {Stretch handles are 5 x 5 pixels}
  347. procedure Constrain(var X : Integer; MinVal, MaxVal : Integer);
  348.   {-Forces an integer between two values}
  349. begin
  350.   if X > MaxVal then
  351.     X := MaxVal
  352.   else if X < MinVal then
  353.     X := MinVal;
  354. end;  { Constrain }
  355. procedure ConvertCoords(Source, Target : TControl; var X, Y : Integer);
  356.   {-Converts Source coordinates X, Y to Target coordinates}
  357. var
  358.   P : TPoint;
  359. begin
  360.   P.X := X;
  361.   P.Y := Y;
  362.   P   := Target.ScreenToClient(Source.ClientToScreen(P));
  363.   X   := P.X;
  364.   Y   := P.Y;
  365. end;
  366. {*** TStretchHandle *}
  367. constructor TStretchHandle.Create(AOwner: TComponent);
  368. begin
  369.   inherited Create(AOwner);
  370.   Canvas.Brush.Color := clBlack;
  371.   Canvas.Brush.Style := bsSolid;
  372.   SetBounds(Top, Left, ctStretchHandleSize, ctStretchHandleSize);
  373. end;
  374. procedure TStretchHandle.Paint;
  375. begin
  376.   Canvas.FillRect(Rect(0, 0, Width, Height));
  377. end;
  378. {------------------------------ TBaseField ---------------------------------}
  379. constructor TBaseField.Create(AOwner: TComponent);
  380. begin
  381.   inherited Create(AOwner);
  382.   Brush.Color := clWindow;
  383.   Brush.Style := bsClear;
  384.   DragCursor  := crCross;
  385.   DragMode    := dmManual;
  386.   Pen.Mode    := pmCopy;
  387.   Pen.Style   := psDashDot;
  388.   Pen.Color   := clBlack;
  389.   Pen.Width   := 1;
  390.   Shape       := stRectangle;
  391.   Visible     := False; {Caller must make visible after setting size and position}
  392.   SetSelected(False);
  393. end;
  394. procedure TBaseField.bfMouseDown(Sender: TObject; Button: TMouseButton;
  395.                                  Shift: TShiftState; X, Y: Integer);
  396. begin
  397.   if Parent is TPanel then begin
  398.     {If Sender is one of the StretchHandles, convert its coordinates to our own}
  399.     if Sender is TStretchHandle then
  400.       ConvertCoords(Sender as TStretchHandle, Self, X, Y);
  401.     (Parent as TPanel).OnMouseDown(Self, Button, Shift, X, Y);
  402.   end;
  403. end;
  404. procedure TBaseField.bfMouseUp(Sender: TObject; Button: TMouseButton;
  405.                                Shift: TShiftState; X, Y: Integer);
  406. begin
  407.   if Parent is TPanel then begin
  408.     {If Sender is one of the StretchHandles, convert its coordinates to our own}
  409.     if Sender is TStretchHandle then
  410.       ConvertCoords(Sender as TStretchHandle, Self, X, Y);
  411.     (Parent as TPanel).OnMouseUp(Self, Button, Shift, X, Y);
  412.   end;
  413. end;
  414. procedure TBaseField.bfMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
  415. begin
  416.   if Parent is TPanel then begin
  417.     {If Sender is one of the StretchHandles, convert its coordinates to our own}
  418.     if Sender is TStretchHandle then begin
  419.       ConvertCoords(Sender as TStretchHandle, Self, X, Y);
  420.       if not (ssLeft in Shift) then
  421.         StretchMode := (Sender as TStretchHandle).HandlePosition;
  422.     end else
  423.       StretchMode := smDrag;
  424.     (Parent as TPanel).OnMouseMove(Self, Shift, X, Y);
  425.   end;
  426. end;
  427. procedure TBaseField.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  428. var
  429.   I : Integer;
  430.   P : TPoint;
  431. begin
  432.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  433.   {Move all StretchHandles to the proper positions}
  434.   for I := Low(bfStretchHandles) to High(bfStretchHandles) do
  435.     if Assigned(bfStretchHandles[I]) then
  436.       with bfStretchHandles[I] do begin
  437.         P := GetStretchHandleCoords(HandlePosition);
  438.         SetBounds(P.X, P.Y, Width, Height);
  439.       end;
  440. end;
  441. procedure TBaseField.SetParent(AParent: TWinControl);
  442.   function CreateStretchHandle(WhichHandle : TStretchModes) : TStretchHandle;
  443.   var
  444.     P : TPoint;
  445.   begin
  446.     P := GetStretchHandleCoords(WhichHandle);
  447.     Result := TStretchHandle.Create(Self);
  448.     with Result do begin
  449.       HandlePosition := WhichHandle;
  450.       Parent         := AParent;
  451.       Visible        := Selected;
  452.       OnMouseDown    := bfMouseDown;
  453.       OnMouseUp      := bfMouseUp;
  454.       OnMouseMove    := bfMouseMove;
  455.       SetBounds(P.X, P.Y, Width, Height);
  456.     end;
  457.   end;
  458. const
  459.   ctStretchHandleCorners :
  460.     array[Low(TStretchHandleArray)..High(TStretchHandleArray)] of TStretchModes =
  461.       (smNW, smN, smNE, smE, smSE, smS, smSW, smW);
  462. var
  463.   I : Integer;
  464. begin
  465.   if AParent <> Parent then begin
  466.     inherited SetParent(AParent);
  467.     if Assigned(AParent) then begin
  468.       OnMouseDown := (AParent as TPanel).OnMouseDown;
  469.       OnMouseUp   := (AParent as TPanel).OnMouseUp;
  470.       OnMouseMove := (AParent as TPanel).OnMouseMove;
  471.       {If StretchHandles already exist, destroy them}
  472.       for I := Low(bfStretchHandles) to High(bfStretchHandles) do
  473.         if Assigned(bfStretchHandles[I]) then begin
  474.           bfStretchHandles[I].Free;
  475.           bfStretchHandles[I] := nil;
  476.         end;
  477.       {Create new StretchHandles}
  478.       for I := Low(bfStretchHandles) to High(bfStretchHandles) do
  479.         bfStretchHandles[I] := CreateStretchHandle(ctStretchHandleCorners[I]);
  480.     end else begin
  481.       OnMouseDown := nil;
  482.       OnMouseUp   := nil;
  483.       OnMouseMove := nil;
  484.     end;
  485.   end;
  486. end;
  487. procedure TBaseField.SetSelected(IsSelected : Boolean);
  488. var
  489.   I : Integer;
  490. begin
  491.   if IsSelected <> FSelected then begin
  492.     FSelected := IsSelected;
  493.     for I := Low(bfStretchHandles) to High(bfStretchHandles) do
  494.       with bfStretchHandles[I] do begin
  495.         Visible := FSelected;
  496.         {BringToFront to ensure that if this is a TImageField, StretchHandle
  497.          isn't partially hidden behind the image}
  498.         if FSelected then
  499.           BringToFront;
  500.       end;
  501.     Refresh;
  502.   end;
  503. end;
  504. function TBaseField.GetStretchHandleCoords(WhichHandle : TStretchModes) : TPoint;
  505.   {-Returns the coordinates (Left, Top) where the StretchHandle should be drawn}
  506. var
  507.   Offset : Integer;
  508. begin
  509.   with Result do
  510.     case WhichHandle of
  511.       smNW : begin
  512.                Offset := ctStretchHandleSize div 2;
  513.                X      := Left - Offset;
  514.                Y      := Top - Offset;
  515.              end;
  516.       smN  : begin
  517.                Offset := ctStretchHandleSize div 2;
  518.                X      := Left + (Width div 2) - Offset;
  519.                Y      := Top - Offset;
  520.              end;
  521.       smNE : begin
  522.                Offset := (ctStretchHandleSize + 1) div 2;
  523.                X      := Left + Width - Offset;
  524.                Offset := ctStretchHandleSize div 2;
  525.                Y      := Top - Offset;
  526.              end;
  527.       smE  : begin
  528.                Offset := (ctStretchHandleSize + 1) div 2;
  529.                X      := Left + Width - Offset;
  530.                Offset := ctStretchHandleSize div 2;
  531.                Y      := Top + (Height div 2) - Offset;
  532.              end;
  533.       smSE : begin
  534.                Offset := (ctStretchHandleSize + 1) div 2;
  535.                X      := Left + Width - Offset;
  536.                Y      := Top + Height - Offset;
  537.              end;
  538.       smS  : begin
  539.                Offset := ctStretchHandleSize div 2;
  540.                X      := Left + (Width div 2) - Offset;
  541.                Offset := (ctStretchHandleSize + 1) div 2;
  542.                Y      := Top + Height - Offset;
  543.              end;
  544.       smSW : begin
  545.                Offset := ctStretchHandleSize div 2;
  546.                X      := Left - Offset;
  547.                Offset := (ctStretchHandleSize + 1) div 2;
  548.                Y      := Top + Height - Offset;
  549.              end;
  550.       smW  : begin
  551.                Offset := ctStretchHandleSize div 2;
  552.                X      := Left - Offset;
  553.                Y      := Top + (Height div 2) - Offset;
  554.              end;
  555.       else begin
  556.         X := 0;
  557.         Y := 0;
  558.       end;
  559.     end;
  560. end;
  561. procedure TBaseField.Read(Stream : TStream);
  562. var
  563.   FieldRec : TFieldRecord;
  564. begin
  565.   Stream.ReadBuffer(FieldRec, SizeOf(FieldRec));
  566.   if Parent is TFaxPanel then
  567.     with (Parent as TFaxPanel), FieldRec do begin
  568.       Self.Left   := HorzInchesToPixels(frLeftInches);
  569.       Self.Top    := VertInchesToPixels(frTopInches);
  570.       Self.Width  := HorzInchesToPixels(frWidthInches);
  571.       Self.Height := VertInchesToPixels(frHeightInches);
  572.     end;
  573. end;
  574. procedure TBaseField.Write(Stream : TStream);
  575. var
  576.   FieldRec : TFieldRecord;
  577. begin
  578.   FillChar(FieldRec, SizeOf(FieldRec), 0);
  579.   if Parent is TFaxPanel then
  580.     with (Parent as TFaxPanel), FieldRec do begin
  581.       frLeftInches   := HorzPixelsToInches(Self.Left);
  582.       frTopInches    := VertPixelsToInches(Self.Top);
  583.       frWidthInches  := HorzPixelsToInches(Self.Width);
  584.       frHeightInches := VertPixelsToInches(Self.Height);
  585.     end;
  586.   Stream.WriteBuffer(FieldRec, SizeOf(FieldRec));
  587. end;
  588. {*** TTextField ***}
  589. constructor TTextField.Create(AOwner: TComponent);
  590. const
  591.   ctDefWidth = 200;
  592. var
  593.   Items1:TMenuItem;
  594. begin
  595.   inherited Create(AOwner);
  596.   Pen.Style := psClear;  {Don't need the TShape border because FMemo will have a border}
  597.   FpopupMenu:=TPopupMenu.Create(self);
  598.   Items1:=TMenuItem.Create(self);
  599.   Items1.Caption:='载入文本';
  600.   Items1.OnClick:=OnLoadFromFile;
  601.   FPopupmenu.Items.Add(items1);
  602.   FMemo := TMemo.Create(Self);
  603.   FMemo.PopupMenu:=FPopupMenu;
  604.   with FMemo do begin
  605.     Ctl3D       := False;
  606.     ParentCtl3D := False;
  607.     WordWrap    := True;
  608.     OnMouseDown := bfMouseDown;
  609.     OnMouseUp   := bfMouseUp;
  610.     OnMouseMove := bfMouseMove;
  611.     OnDblClick  := MemoDblClick;
  612.     OnEnter     := tfEnter;
  613.     OnExit      := tfExit;
  614.   end;
  615.   FMemo.Font.Name:='宋体';
  616.   FMemo.Font.Size:=11;
  617.   SetBounds(Left, Top, ctDefWidth, Height);
  618. end;
  619. procedure TTextField.Draw(ACanvas : TCanvas);
  620.   procedure ReplaceTags(TagStr     : string;
  621.                   const ReplaceStr : string;
  622.                     var TargetStr  : string);
  623.   var
  624.     Posn    : Integer;
  625.     TempStr : string;
  626.   begin
  627.     TagStr := UpperCase(TagStr);
  628.     repeat
  629.       TempStr := UpperCase(TargetStr);
  630.       Posn    := Pos(TagStr, TempStr);
  631.       if Posn > 0 then begin
  632.         Delete(TargetStr, Posn, Length(TagStr));
  633.         Insert(ReplaceStr, TargetStr, Posn);
  634.       end;
  635.     until Posn = 0;
  636.   end;
  637. var
  638.   I          : Integer;
  639.   X, Y       : Integer;
  640.   TextHeight : Integer;
  641.   S          : string;
  642.   DateStr    : string;
  643.   TimeStr    : string;
  644. begin
  645.   with FMemo do begin
  646.     ACanvas.Font := Font;
  647.     TextHeight := GetTextHeight;
  648.     {Format date string to use for $D replacement tag}
  649.     DateStr := DateToStr(Date);
  650.     {Format time string to use for $T replacement tag}
  651.     TimeStr := TimeToStr(Time);
  652.     Delete(TimeStr, Length(TimeStr) - 5, 4);  {Strip off the seconds}
  653.     TimeStr := LowerCase(TimeStr); {Convert AM or PM to lower case}
  654.     X := Round((Parent as TFaxPanel).DrawAdjustFactor * Self.Left);
  655.     for I := 0 to Lines.Count - 1 do begin
  656.       S := Lines[I];
  657.       {Look for replaceable tags and do replacements as required}
  658.       ReplaceTags('$D', DateStr, S);
  659.       ReplaceTags('$T', TimeStr, S);
  660.       ReplaceTags('$N', IntToStr((Parent as TFaxPanel).PageCount), S);
  661.       ReplaceTags('$P', IntToStr((Parent as TFaxPanel).PageNumber), S);
  662.       ReplaceTags('$F', (Parent as TFaxPanel).Sender, S);
  663.       ReplaceTags('$R', (Parent as TFaxPanel).Recipient, S);
  664.       ReplaceTags('$S', (Parent as TFaxPanel).PageTitle, S);
  665.       ReplaceTags('$I', (Parent as TFaxPanel).StationID, S);
  666.       Y := Round((Parent as TFaxPanel).DrawAdjustFactor * (Self.Top + (I * TextHeight)));
  667.       ACanvas.TextOut(X, Y, S);
  668.     end;
  669.   end;
  670. end;
  671. procedure TTextField.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  672. begin
  673.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  674.   if Assigned(FMemo) then
  675.     FMemo.SetBounds(ALeft, ATop, AWidth, AHeight);
  676. end;
  677. procedure TTextField.SetParent(AParent: TWinControl);
  678. var
  679.   NewHeight : Integer;
  680. begin
  681.   inherited SetParent(AParent);
  682.   if Assigned(FMemo) then begin
  683.     FMemo.Parent := AParent;
  684.     {If no text has yet been entered, get the height of one row of text for the
  685.      current font, and adjust the field height to match}
  686.     if (FMemo.Text = '') and Assigned(AParent) then begin
  687.       NewHeight := GetTextHeight + 4;
  688.       {If SnapToGrid is enabled, adjust height to fall on a grid line}
  689.       with Parent as TFaxPanel do
  690.         if SnapToGrid then
  691.           AdjustHeightToGrid(Top, NewHeight);
  692.       SetBounds(Left, Top, Width, NewHeight);
  693.     end;
  694.     if AParent is TFaxPanel then
  695.       FMemo.OnChange := (AParent as TFaxPanel).FieldChange;
  696.   end;
  697. end;
  698. procedure TTextField.SetFocus;
  699. begin
  700.   FMemo.SetFocus;
  701. end;
  702. function TTextField.GetTextHeight : Integer;
  703. var
  704.   Canvas     : TCanvas;
  705.   TextMetric : TTextMetric;
  706. begin
  707.   Canvas := TCanvas.Create;
  708.   try
  709.     Canvas.Handle := GetDC(FMemo.Handle);
  710.     try
  711.       Canvas.Font := FMemo.Font;
  712.       GetTextMetrics(Canvas.Handle, TextMetric);
  713.       with TextMetric do
  714.         Result := tmHeight + tmExternalLeading;
  715.     finally
  716.       ReleaseDC(FMemo.Handle, Canvas.Handle);
  717.     end;
  718.   finally
  719.     Canvas.Free;
  720.   end;
  721. end;
  722. procedure TTextField.MemoDblClick(Sender: TObject);
  723. var
  724.   NewHeight  : Integer;
  725.   LineCount  : Integer;
  726.   FontDialog : TFontDialog;
  727. begin
  728.   FontDialog := TFontDialog.Create(nil);
  729.   try
  730.     FontDialog.Font := FMemo.Font;
  731.     if FontDialog.Execute then begin
  732.       FMemo.Font := FontDialog.Font;
  733.       {Adjust field height to allow for the new font size}
  734.       LineCount := FMemo.Lines.Count;
  735.       if LineCount < 1 then
  736.         LineCount := 1;
  737.       NewHeight := GetTextHeight * LineCount + 4;
  738.       Constrain(NewHeight, 0, (Parent as TWinControl).Height - Top);
  739.       {If SnapToGrid is enabled, adjust height to fall on a grid line}
  740.       if (Parent as TFaxPanel).SnapToGrid then
  741.         (Parent as TFaxPanel).AdjustHeightToGrid(Top, NewHeight);
  742.       SetBounds(Left, Top, Width, NewHeight);
  743.       if FSelected then begin
  744.         (Parent as TFaxPanel).FieldPositionChange(Left, Top, Width, Height);
  745.         {Set Ruler position marks to the new coordinates}
  746.         if (Parent as TFaxPanel).Owner is TFaxDesigner then
  747.           ((Parent as TFaxPanel).Owner as TFaxDesigner).SetMarkPositions(Left, Top, Width, Height);
  748.       end;
  749.     end;
  750.     if Parent is TFaxPanel then
  751.       (Parent as TFaxPanel).FieldChange(nil);
  752.   finally
  753.     FontDialog.Free;
  754.   end;
  755. end;
  756. procedure TTextField.OnLoadFromFile(Sender: TObject);
  757. var
  758.   OpenDialog : TOpenDialog;
  759. begin
  760.   OpenDialog := TOpenDialog.Create(nil);
  761.   OpenDialog.Filter:='文本文件 (*.txt)|*.TXT|所有文件(*.*)|*.*';
  762.   if OpenDialog.Execute then
  763.   begin
  764.     FMemo.WordWrap:=true;
  765.     FMemo.Lines.LoadFromFile(OpenDialog.FileName);
  766.   end;
  767. end;
  768. function TTextField.GetText : string;
  769. begin
  770.   if Assigned(FMemo) then
  771.     Result := FMemo.Text
  772.   else
  773.     Result := '';
  774. end;
  775. type
  776.   TLocalMemo = class(TMemo);
  777. procedure TTextField.tfEnter(Sender : TObject);
  778. var
  779.   PF : {$IFDEF DELPHI3}TCustomForm{$ELSE}TForm{$ENDIF};
  780. begin
  781.   if (Parent as TFaxPanel).EditMode then begin
  782.     TLocalMemo(FMemo).SetDesigning(False);
  783.   end else begin
  784.     PF := GetParentForm(FMemo);
  785.     PF.DefocusControl(FMemo, False);
  786.     TLocalMemo(FMemo).SetDesigning(True);
  787.   end;
  788. end;
  789. procedure TTextField.tfExit(Sender : TObject);
  790. begin
  791.   TLocalMemo(FMemo).SetDesigning(True);
  792. end;
  793. procedure TTextField.Read(Stream : TStream);
  794. var
  795.   BufSize : LongInt;
  796.   Buffer  : PChar;
  797.   FontRec : TFontRecord;
  798. begin
  799.   {Read BaseField properties}
  800.   inherited Read(Stream);
  801.   {Read the font properties and assign them to TMemo.Font}
  802.   Stream.ReadBuffer(FontRec, SizeOf(FontRec));
  803.   with FMemo.Font, FontRec do begin
  804.     {$IFDEF DELPHI3}
  805.     CharSet := TFontCharSet(frCharSet);
  806.     {$ENDIF}
  807.     Color   := TColor(frColor);
  808.     Height  := frHeight;
  809.     Name    := frName;
  810.     Pitch   := TFontPitch(frPitch);
  811.     Size    := frSize;
  812.     Style   := [];
  813.     if frFontBold then
  814.       Style := Style + [fsBold];
  815.     if frFontItalic then
  816.       Style := Style + [fsItalic];
  817.     if frFontUnderline then
  818.       Style := Style + [fsUnderline];
  819.     if frFontStrikeout then
  820.       Style := Style + [fsStrikeout];
  821.   end;
  822.   {Read the buffer size needed to store the text}
  823.   Stream.ReadBuffer(BufSize, SizeOf(BufSize));
  824.   {If text exists, read it into the buffer and assign it to the TMemo}
  825.   if BufSize > 1 then begin
  826.     GetMem(Buffer, BufSize);
  827.     try
  828.       FillChar(Buffer^, BufSize, 0);
  829.       Stream.ReadBuffer(Buffer^, BufSize);
  830.       FMemo.Text := StrPas(Buffer);
  831.     finally
  832.       FreeMem(Buffer, BufSize);
  833.     end;
  834.   end;
  835. end;
  836. procedure TTextField.Write(Stream : TStream);
  837. var
  838.   FieldType : Byte;
  839.   BufSize   : LongInt;
  840.   Buffer    : PChar;
  841.   FontRec   : TFontRecord;
  842. begin
  843.   {First thing to write out is the field type}
  844.   FieldType := ftTextField;
  845.   Stream.WriteBuffer(FieldType, SizeOf(FieldType));
  846.   {Write out BaseField properties}
  847.   inherited Write(Stream);
  848.   {Initialize FontRec with the font properties and write it out}
  849.   with FMemo.Font, FontRec do begin
  850.     {$IFDEF DELPHI3}
  851.     frCharSet       := Ord(CharSet);
  852.     {$ELSE}
  853.     frCharSet       := 0;
  854.     {$ENDIF}
  855.     frColor         := Color;
  856.     frHeight        := Height;
  857.     frName          := Name;
  858.     frPitch         := Ord(Pitch);
  859.     frSize          := Size;
  860.     frFontBold      := fsBold in Style;
  861.     frFontItalic    := fsItalic in Style;
  862.     frFontUnderline := fsUnderline in Style;
  863.     frFontStrikeout := fsStrikeout in Style;
  864.   end;
  865.   Stream.WriteBuffer(FontRec, SizeOf(FontRec));
  866.   {Find out how big a buffer we need, and write out the buffer size}
  867.   BufSize := FMemo.GetTextLen + 1; {Add one to allow for null character}
  868.   Stream.WriteBuffer(BufSize, SizeOf(BufSize));
  869.   {If the buffer isn't empty, get the memo text and write it out}
  870.   if BufSize > 1 then begin
  871.     GetMem(Buffer, BufSize);
  872.     try
  873.       FillChar(Buffer^, BufSize, 0);
  874.       FMemo.GetTextBuf(Buffer, BufSize);
  875.       Stream.WriteBuffer(Buffer^, BufSize);
  876.     finally
  877.       FreeMem(Buffer, BufSize);
  878.     end;
  879.   end;
  880. end;
  881. {------------------------------ TImageField --------------------------------}
  882. constructor TImageField.Create(AOwner: TComponent);
  883. const
  884.   DefWidth  = 120;
  885.   DefHeight = 120;
  886. begin
  887.   inherited Create(AOwner);
  888.   FImage := TImage.Create(Self);
  889.   with FImage do begin
  890.     Stretch     := True;
  891.     OnMouseDown := bfMouseDown;
  892.     OnMouseUp   := bfMouseUp;
  893.     OnMouseMove := bfMouseMove;
  894.     OnDblClick  := ImageDblClick;
  895.   end;
  896.   SetBounds(Left, Top, DefWidth, DefHeight);
  897. end;  
  898. procedure TImageField.Draw(ACanvas : TCanvas);
  899. var
  900.   AdjustFactor : Double;
  901. begin
  902.   if not FImage.Picture.Bitmap.Empty then begin
  903.     AdjustFactor := (Parent as TFaxPanel).DrawAdjustFactor;
  904.     ACanvas.StretchDraw(Rect(Round(Left * AdjustFactor), Round(Top * AdjustFactor),
  905.                              Round((Left + Width) * AdjustFactor),
  906.                              Round((Top + Height) * AdjustFactor)),
  907.                         FImage.Picture.Bitmap);
  908.   end;
  909. end;
  910. function TImageField.GetPicture : TPicture;
  911. begin
  912.   if Assigned(FImage) then
  913.     Result := FImage.Picture
  914.   else
  915.     Result := nil;
  916. end;
  917. procedure TImageField.ImageDblClick(Sender: TObject);
  918. var
  919.   {$IFDEF DELPHI3}
  920.   PictureDialog : TOpenPictureDialog;
  921.   {$ELSE}
  922.   PictureDialog : TOpenDialog;
  923.   {$ENDIF}
  924.   I             : Integer;
  925.   Ext:String;
  926.   image1:TImage;
  927.   bmp:TBitmap;
  928. begin
  929.   {$IFDEF DELPHI3}
  930.   PictureDialog := TOpenPictureDialog.Create(nil);
  931.   {$ELSE}
  932.   PictureDialog := TOpenDialog.Create(nil);
  933.   {$ENDIF}
  934.   try
  935.     {$IFNDEF DELPHI3}
  936.     PictureDialog.Filter := 'Bitmap files|*.BMP';
  937.     {$ENDIF}
  938.     PictureDialog.Options := [ofHideReadOnly, ofFileMustExist,
  939.                               ofPathMustExist, ofNoChangeDir];
  940.     if PictureDialog.Execute then begin
  941.       Ext:=Uppercase(ExtractFileExt(PictureDialog.FileName));
  942.        if (Ext='.JPG') or (Ext='.JPEG') then
  943.         begin
  944.           image1:=Timage.Create(self);
  945.           image1.picture.loadfromfile(pictureDialog.filename);
  946.           bmp:=TBitmap.create;
  947.           bmp.assign(TJPEGImage(image1.picture.Graphic));
  948.           Fimage.Picture.Bitmap:=bmp;
  949.         end
  950.         else
  951.         FImage.Picture.LoadFromFile(PictureDialog.FileName);
  952.         FImage.Visible := True;
  953.         {Bring all StretchHandles to front so they draw on top of the image}
  954.         for I := Low(bfStretchHandles) to High(bfStretchHandles) do
  955.           bfStretchHandles[I].BringToFront;
  956.         if Parent is TFaxPanel then
  957.           (Parent as TFaxPanel).FieldChange(nil);
  958.     end;
  959.   finally
  960.     PictureDialog.Free;
  961.   end;
  962. end;
  963. procedure TImageField.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  964. begin
  965.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  966.   if Assigned(FImage) then
  967.     FImage.SetBounds(ALeft, ATop, AWidth, AHeight);
  968. end;
  969. procedure TImageField.SetParent(AParent: TWinControl);
  970. begin
  971.   inherited SetParent(AParent);
  972.   if Assigned(FImage) then
  973.     FImage.Parent := AParent;
  974. end;
  975. type
  976.   TLocalBitmap = class(TBitmap);
  977. procedure TImageField.Read(Stream : TStream);
  978. var
  979.   IsEmpty : Boolean;
  980. begin
  981.   {Read BaseField properties}
  982.   inherited Read(Stream);
  983.   {Read the IsEmpty value to determine if a bitmap exists}
  984.   Stream.ReadBuffer(IsEmpty, SizeOf(IsEmpty));
  985.   {If we have a bitmap, read it in}
  986.   if not IsEmpty then
  987.     TLocalBitmap(FImage.Picture.Bitmap).ReadData(Stream);
  988.     {ReadData is used because when using SaveToStream/LoadFromStream,
  989.      LoadFromStream assumes that the bitmap occupies the remaining data
  990.      in the stream, therefor no other items can be stored after the bitmap.
  991.      ReadData first reads in the size of the bitmap.
  992.      The WriteData/ReadData routines are protected, but the type-cast using
  993.      a local class alias allow us to access them anyway}
  994.     {FImage.Picture.Bitmap.LoadFromStream(Stream);}
  995. end;
  996. procedure TImageField.Write(Stream : TStream);
  997. var
  998.   FieldType : Byte;
  999.   IsEmpty   : Boolean;
  1000. begin
  1001.   {First thing to write out is the field type}
  1002.   FieldType := ftImageField;
  1003.   Stream.WriteBuffer(FieldType, SizeOf(FieldType));
  1004.   {Write out BaseField properties}
  1005.   inherited Write(Stream);
  1006.   {Determine whether a Bitmap is assigned and write this boolean value out}
  1007.   IsEmpty := FImage.Picture.Bitmap.Empty;
  1008.   Stream.WriteBuffer(IsEmpty, SizeOf(IsEmpty));
  1009.   {If we have a bitmap, write it out}
  1010.   if not IsEmpty then
  1011.     TLocalBitmap(FImage.Picture.Bitmap).WriteData(Stream);
  1012.     {WriteData is used because when using SaveToStream/LoadFromStream,
  1013.      LoadFromStream assumes that the bitmap occupies the remaining data
  1014.      in the stream, therefor no other items can be stored after the bitmap.
  1015.      WriteData first writes out the size of the bitmap data.
  1016.      The WriteData/ReadData routines are protected, but the type-cast using
  1017.      a local class alias allow us to access them anyway}
  1018.     {FImage.Picture.Bitmap.SaveToStream(Stream);}
  1019. end;
  1020. {*** TFaxPanel ***}
  1021. constructor TFaxPanel.Create(AOwner : TComponent);
  1022. begin
  1023.   inherited Create(AOwner);
  1024.   FGridSpacingX     := ctGridSpacingX;
  1025.   FGridSpacingY     := ctGridSpacingY;
  1026.   OnResize          := fpResize;
  1027.   OnMouseDown       := fpMouseDown;
  1028.   OnMouseUp         := fpMouseUp;
  1029.   OnMouseMove       := fpMouseMove;
  1030.   fpFieldList       := TList.Create;
  1031. end;
  1032. destructor TFaxPanel.Destroy;
  1033. begin
  1034.   {Destroy all items in fpFieldList}
  1035.   DeleteAllFields;
  1036.   {Now destroy the list itself}
  1037.   fpFieldList.Free;
  1038.   inherited Destroy;
  1039. end;
  1040. function TFaxPanel.GetFieldCount : Integer;
  1041. begin
  1042.   Result := fpFieldList.Count;
  1043. end;
  1044. function TFaxPanel.GetField(Index : Integer) : TBaseField;
  1045. begin
  1046.   Result := TBaseField(fpFieldList[Index]);
  1047. end;
  1048. function TFaxPanel.GetSelectedField : TBaseField;
  1049. var
  1050.   I      : Integer;
  1051. begin
  1052.   for I := fpFieldList.Count - 1 downto 0 do begin
  1053.     Result := fpFieldList[I];
  1054.     if Result.Selected then
  1055.       Exit;
  1056.   end;
  1057.   Result := nil;
  1058. end;
  1059. procedure TFaxPanel.SetEditMode(Value : Boolean);
  1060. var
  1061.   I     : Integer;
  1062.   Field : TBaseField;
  1063. begin
  1064.   if Value <> FEditMode then begin
  1065.     FEditMode := Value;
  1066.     for I := fpFieldList.Count - 1 downto 0 do begin
  1067.       Field := fpFieldList[I];
  1068.       if Field.Selected and (Field is TTextField) then begin
  1069.         TTextField(Field).tfEnter(nil);
  1070.         if Value then
  1071.           TTextField(Field).SetFocus;
  1072.       end;
  1073.     end;
  1074.   end;
  1075. end;
  1076. procedure TFaxPanel.SetPageWidthInches(AWidth : Double);
  1077. begin
  1078.   if AWidth <> FPageWidthInches then begin
  1079.     FPageWidthInches := AWidth;
  1080.     {Recalc pixels per inch and post position messages if necessary}
  1081.     SetBounds(Left, Top, Width, Height);
  1082.     FNeedsSaving := True;
  1083.   end;
  1084. end;
  1085. procedure TFaxPanel.SetPageHeightInches(AHeight : Double);
  1086. begin
  1087.   if AHeight <> FPageHeightInches then begin
  1088.     FPageHeightInches := AHeight;
  1089.     {SetBounds recalcs pixels per inch and calls OnFieldPositionChange if
  1090.      necessary}
  1091.     SetBounds(Left, Top, Width, Height);
  1092.     FNeedsSaving := True;
  1093.   end;
  1094. end;  
  1095. procedure TFaxPanel.SetShowGrid(AShowGrid : Boolean);
  1096. begin
  1097.   if AShowGrid <> FShowGrid then begin
  1098.     FShowGrid := AShowGrid;
  1099.     Invalidate;
  1100.   end;
  1101. end;
  1102. procedure TFaxPanel.SetSnapToGrid(ASnapToGrid : Boolean);
  1103. var
  1104.   I         : Integer;
  1105.   NewLeft   : Integer;
  1106.   NewTop    : Integer;
  1107.   NewWidth  : Integer;
  1108.   NewHeight : Integer;
  1109.   Field     : TBaseField;
  1110. begin
  1111.   if ASnapToGrid <> FSnapToGrid then begin
  1112.     FSnapToGrid := ASnapToGrid;
  1113.     {If SnapToGrid was just turned on, force all existing fields to snap to the grid}
  1114.     if FSnapToGrid then begin
  1115.       for I := 0 to fpFieldList.Count - 1 do begin
  1116.         Field     := fpFieldList[I];
  1117.         NewLeft   := Field.Left;
  1118.         NewTop    := Field.Top;
  1119.         NewWidth  := Field.Width;
  1120.         NewHeight := Field.Height;
  1121.         {Adjust coordinates to be on grid lines}
  1122.         AdjustLeftToGrid(NewLeft);
  1123.         AdjustTopToGrid(NewTop);
  1124.         AdjustWidthToGrid(NewLeft, NewWidth);
  1125.         AdjustHeightToGrid(NewTop, NewHeight);
  1126.         Field.SetBounds(NewLeft, NewTop, NewWidth, NewHeight);
  1127.       end;
  1128.       FNeedsSaving := True;
  1129.     end;
  1130.   end;
  1131. end;
  1132. procedure TFaxPanel.SetGridSpacingX(GridSpacing : Integer);
  1133. begin
  1134.   if (GridSpacing > 0) and (GridSpacing <> FGridSpacingX) then begin
  1135.     FGridSpacingX := GridSpacing;
  1136.     fpResize(nil);  {Recalculate fpMaxGridLine}
  1137.     if FSnapToGrid then begin
  1138.       {Turn SnapToGrid off and back on to force all fields to align to the new grid size}
  1139.       SetSnapToGrid(False);
  1140.       SetSnapToGrid(True);
  1141.     end;
  1142.     if FShowGrid then
  1143.       Invalidate;
  1144.   end;
  1145. end;
  1146. procedure TFaxPanel.SetGridSpacingY(GridSpacing : Integer);
  1147. begin
  1148.   if (GridSpacing > 0) and (GridSpacing <> FGridSpacingY) then begin
  1149.     FGridSpacingY := GridSpacing;
  1150.     fpResize(nil);  {Recalculate fpMaxGridLine}
  1151.     if FSnapToGrid then begin
  1152.       {Turn SnapToGrid off and back on to force all fields to align to the new grid size}
  1153.       SetSnapToGrid(False);
  1154.       SetSnapToGrid(True);
  1155.     end;
  1156.     if FShowGrid then
  1157.       Invalidate;
  1158.   end;
  1159. end;
  1160. procedure TFaxPanel.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  1161.   procedure UpdateFieldPositionsAndSizes(OldWidth, OldHeight : Integer);
  1162.   var
  1163.     I           : Integer;
  1164.     NewLeft     : Integer;
  1165.     NewTop      : Integer;
  1166.     NewWidth    : Integer;
  1167.     NewHeight   : Integer;
  1168.     Field       : TBaseField;
  1169.     WidthRatio  : Double;
  1170.     HeightRatio : Double;
  1171.   begin
  1172.     if OldWidth = 0 then
  1173.       WidthRatio := 0.0
  1174.     else
  1175.       WidthRatio  := Width / OldWidth;
  1176.     if OldHeight = 0 then
  1177.       HeightRatio := 0.0
  1178.     else
  1179.       HeightRatio  := Height / OldHeight;
  1180.     for I := fpFieldList.Count - 1 downto 0 do begin
  1181.       Field := fpFieldList[I];
  1182.       with Field do begin
  1183.         NewLeft   := Round(Left * WidthRatio);
  1184.         NewTop    := Round(Top * HeightRatio);
  1185.         NewWidth  := Round(Width * WidthRatio);
  1186.         NewHeight := Round(Height * HeightRatio);
  1187.         AdjustLeftToGrid(NewLeft);
  1188.         AdjustWidthToGrid(NewLeft, NewWidth);
  1189.         AdjustTopToGrid(NewTop);
  1190.         AdjustHeightToGrid(NewTop, NewHeight);
  1191.         SetBounds(NewLeft, NewTop, NewWidth, NewHeight);
  1192.         if Selected then begin
  1193.           FieldPositionChange(Left, Top, Width, Height);
  1194.           {Set Ruler position marks to the new coordinates}
  1195.           if Self.Owner is TFaxDesigner then
  1196.             (Self.Owner as TFaxDesigner).SetMarkPositions(Left, Top, Width, Height);
  1197.         end;
  1198.       end;
  1199.     end;
  1200.   end;  
  1201. var
  1202.   OldWidth  : Integer;
  1203.   OldHeight : Integer;
  1204. begin
  1205.   OldWidth  := Width;
  1206.   Oldheight := Height;
  1207.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  1208.   if FPageWidthInches = 0.0 then
  1209.     fpHorzPixelsPerInch := 0.0
  1210.   else
  1211.     fpHorzPixelsPerInch := Width / FPageWidthInches;
  1212.   if FPageHeightInches = 0.0 then
  1213.     fpVertPixelsPerInch := 0.0
  1214.   else
  1215.     fpVertPixelsPerInch := Height / FPageHeightInches;
  1216.   {Move and resize all fields so they retain the same relative positions and
  1217.    sizes in relation to the FaxPanel size}
  1218.   if Assigned(fpFieldList) then
  1219.     UpdateFieldPositionsAndSizes(OldWidth, OldHeight);
  1220. end;
  1221. procedure TFaxPanel.Paint;
  1222. var
  1223.   X, Y : Integer;
  1224. begin
  1225.   inherited Paint;
  1226.   if FShowGrid then begin
  1227.     X := ctGridStart;
  1228.     with Canvas do
  1229.       while X < Width do begin
  1230.         {To improve painting performance, don't draw anything that isn't
  1231.          within the current ClipRect}
  1232.         if (ClipRect.Left <= X) and (X <= ClipRect.Right) then begin
  1233.           Y := ctGridStart;
  1234.           while Y < Height do begin
  1235.             {To improve painting performance, don't draw anything that isn't
  1236.              within the current ClipRect}
  1237.             if (ClipRect.Top <= Y) and (Y <= ClipRect.Bottom) then
  1238.               Canvas.Pixels[X,Y] := clBlack;
  1239.             Y := Y + FGridSpacingY;
  1240.           end;
  1241.         end;
  1242.         X := X + FGridSpacingX;
  1243.       end;
  1244.   end;
  1245. end;
  1246. procedure TFaxPanel.fpResize(Sender : TObject);
  1247. var
  1248.   Extent      : Integer;
  1249.   NrGridLines : Integer;
  1250. begin
  1251.   {Calculate the coordinates of the rightmost and bottommost grid lines given
  1252.    the current panel size, and store the results in fpMaxGridLine}
  1253.   Extent := Width - ctGridStart;
  1254.   NrGridLines := Extent div FGridSpacingX;
  1255.   fpMaxGridLine.X := (NrGridLines * FGridSpacingX) + ctGridStart;
  1256.   Extent := Height - ctGridStart;
  1257.   NrGridLines := Extent div FGridSpacingY;
  1258.   fpMaxGridLine.Y := (NrGridLines * FGridSpacingY) + ctGridStart;
  1259. end;
  1260. procedure TFaxPanel.fpMouseDown(Sender: TObject;
  1261.   Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  1262. begin
  1263.   {If user clicked on a field, translate the coordinates to MainPanel
  1264.    coordinates and set fpMouseAnchor to those coordinates}
  1265.   if Sender is TBaseField then begin
  1266.     ConvertCoords(Sender as TControl, Self, X, Y);
  1267.     fpMouseAnchor := Point(X, Y);
  1268.     if (Button = mbLeft) and not (ssDouble in Shift) then
  1269.       fpIsMouseDown := True;
  1270.   end else
  1271.     fpMouseAnchor := Point(X, Y);
  1272. end;
  1273. procedure TFaxPanel.fpMouseUp(Sender: TObject; Button: TMouseButton;
  1274.   Shift: TShiftState; X, Y: Integer);
  1275. var
  1276.   IsFieldSelected : Boolean;
  1277. begin
  1278.   case Button of
  1279.     mbRight : if Sender is TControl then begin
  1280.                 ConvertCoords(Sender as TControl, Self, X, Y);
  1281.                 fpMouseAnchor := Point(X, Y);
  1282.               end;
  1283.     mbLeft :
  1284.       begin
  1285.         DeselectAllFields;
  1286.         IsFieldSelected := False;  {No fields are currently selected}
  1287.         {If user clicked on a field, mark it as selected}
  1288.         if Sender is TBaseField then begin
  1289.           IsFieldSelected := True;
  1290.           fpIsMouseDown   := False;
  1291.           with Sender as TBaseField do begin
  1292.             Selected := True;
  1293.             {Set Ruler position marks to the new coordinates}
  1294.             (Self.Owner as TFaxDesigner).SetMarkPositions(Left, Top, Width, Height);
  1295.           end;
  1296.         end else
  1297.           {Turn Ruler position marks off since no fields are selected}
  1298.           (Self.Owner as TFaxDesigner).SetMarkPositions(-1, -1, -1, -1);
  1299.         FieldSelectionChange(IsFieldSelected);
  1300.         if IsFieldSelected then
  1301.           with Sender as TBaseField do
  1302.             FieldPositionChange(Left, Top, Width, Height);
  1303.       end;
  1304.   end;
  1305. end;
  1306. procedure TFaxPanel.fpMouseMove(Sender: TObject; Shift: TShiftState;
  1307.   X, Y: Integer);
  1308. var
  1309.   XDiff     : Integer;
  1310.   YDiff     : Integer;
  1311.   OldLeft   : Integer;
  1312.   OldTop    : Integer;
  1313.   NewLeft   : Integer;
  1314.   NewTop    : Integer;
  1315.   NewWidth  : Integer;
  1316.   NewHeight : Integer;
  1317. begin
  1318.   if Sender is TBaseField then begin
  1319.     if fpIsMouseDown and (ssLeft in Shift) then begin
  1320.       if fpDragging then
  1321.         Exit;
  1322.       fpDragging := True;
  1323.       try
  1324.         case (Sender as TBaseField).StretchMode of
  1325.           smDrag :
  1326.             begin
  1327.               {TextFields can't be moved while in Edit Mode}
  1328.               if FEditMode and (Sender is TTextField) then
  1329.                 Exit;
  1330.               ConvertCoords(Sender as TControl, Self, X, Y);
  1331.               Constrain(X, 0, Width);
  1332.               Constrain(Y, 0, Height);
  1333.               XDiff := X - fpMouseAnchor.X;
  1334.               YDiff := Y - fpMouseAnchor.Y;
  1335.               with Sender as TBaseField do begin
  1336.                 NewLeft := Left + XDiff;
  1337.                 NewTop  := Top + YDiff;
  1338.                 {Ensure field remains entirely within Self}
  1339.                 Constrain(NewLeft, 0, Self.Width  - Width);
  1340.                 Constrain(NewTop,  0, Self.Height - Height);
  1341.                 if FSnapToGrid then begin
  1342.                   {Adjust NewLeft and NewTop to be on grid lines if necessary}
  1343.                   AdjustLeftToGrid(NewLeft);
  1344.                   AdjustTopToGrid(NewTop);
  1345.                   {Make sure we haven't moved past the rightmost or bottommost grid line}
  1346.                   if NewLeft + Width - 1 > fpMaxGridLine.X then
  1347.                     NewLeft := NewLeft - FGridSpacingX;
  1348.                   if NewTop + Height - 1 > fpMaxGridLine.Y then
  1349.                     NewTop := NewTop - FGridSpacingY;
  1350.                 end;
  1351.                 OldLeft := Left;
  1352.                 OldTop  := Top;
  1353.                 SetBounds(NewLeft, NewTop, Width, Height);
  1354.               end;
  1355.               {Set fpMouseAnchor to new mouse position, but ONLY if the field
  1356.                position has changed. If SnapToGrid is enabled, the field position
  1357.                might not have changed even though the mouse position did.}
  1358.               fpMouseAnchor.X := fpMouseAnchor.X + NewLeft - OldLeft;
  1359.               fpMouseAnchor.Y := fpMouseAnchor.Y + NewTop - OldTop;
  1360.             end;
  1361.           smE :
  1362.             with Sender as TBaseField do begin
  1363.               NewWidth := X;
  1364.               Constrain(NewWidth, 0, Self.Width - Left);
  1365.               AdjustWidthToGrid(Left, NewWidth);
  1366.               SetBounds(Left, Top, NewWidth, Height);
  1367.               if Width <= 1 then
  1368.                 StretchMode := smW;
  1369.             end;
  1370.           smW :
  1371.             with Sender as TBaseField do begin
  1372.               NewLeft := Left + X;
  1373.               {Prevent creeping to right when switching from smW to smE}
  1374.               Constrain(NewLeft, 0, Left + Width);
  1375.               AdjustLeftToGrid(NewLeft);
  1376.               NewWidth := Width + Left - NewLeft;
  1377.               Constrain(NewWidth, 0, Self.Width - NewLeft);
  1378.               AdjustWidthToGrid(NewLeft, NewWidth);
  1379.               SetBounds(NewLeft, Top, NewWidth, Height);
  1380.               if Width <= 1 then
  1381.                 StretchMode := smE;
  1382.             end;
  1383.           smS :
  1384.             with Sender as TBaseField do begin
  1385.               NewHeight := Y;
  1386.               Constrain(NewHeight, 0, Self.Height - Top);
  1387.               AdjustHeightToGrid(Top, NewHeight);
  1388.               SetBounds(Left, Top, Width, NewHeight);
  1389.               if Height <= 1 then
  1390.                 StretchMode := smN;
  1391.             end;
  1392.           smN :
  1393.             with Sender as TBaseField do begin
  1394.               NewTop := Top + Y;
  1395.               {Prevent creeping down when switching from smN to smS}
  1396.               Constrain(NewTop, 0, Top + Height);
  1397.               AdjustTopToGrid(NewTop);
  1398.               NewHeight := Height + Top - NewTop;
  1399.               Constrain(NewHeight, 0, Self.Height - NewTop);
  1400.               AdjustHeightToGrid(NewTop, NewHeight);
  1401.               SetBounds(Left, NewTop, Width, NewHeight);
  1402.               if Height <= 1 then
  1403.                 StretchMode := smS;
  1404.             end;
  1405.           smNE :
  1406.             with Sender as TBaseField do begin
  1407.               NewTop := Top + Y;
  1408.               {Prevent creeping down when switching from smN? to smS?}
  1409.               Constrain(NewTop, 0, Top + Height);
  1410.               AdjustTopToGrid(NewTop);
  1411.               NewWidth := X;
  1412.               Constrain(NewWidth, 0, Self.Width - Left);
  1413.               AdjustWidthToGrid(Left, NewWidth);
  1414.               NewHeight := Height + Top - NewTop;
  1415.               Constrain(NewHeight, 0, Self.Height - NewTop);
  1416.               AdjustHeightToGrid(NewTop, NewHeight);
  1417.               SetBounds(Left, NewTop, NewWidth, NewHeight);
  1418.               if Width <= 1 then begin
  1419.                 if Height <= 1 then
  1420.                   StretchMode := smSW
  1421.                 else
  1422.                   StretchMode := smNW;
  1423.               end else if Height <= 1 then
  1424.                 StretchMode := smSE;
  1425.             end;
  1426.           smSW :
  1427.             with Sender as TBaseField do begin
  1428.               NewLeft := Left + X;
  1429.               {Prevent creeping to right when switching from smW to smE}
  1430.               Constrain(NewLeft, 0, Left + Width);
  1431.               AdjustLeftToGrid(NewLeft);
  1432.               NewWidth := Width + Left - NewLeft;
  1433.               Constrain(NewWidth, 0, Self.Width - NewLeft);
  1434.               AdjustWidthToGrid(NewLeft, NewWidth);
  1435.               NewHeight := Y;
  1436.               Constrain(NewHeight, 0, Self.Height - Top);
  1437.               AdjustHeightToGrid(Top, NewHeight);
  1438.               SetBounds(NewLeft, Top, NewWidth, NewHeight);
  1439.               if Width <= 1 then begin
  1440.                 if Height <= 1 then
  1441.                   StretchMode := smNE
  1442.                 else
  1443.                   StretchMode := smSE;
  1444.               end else if Height <= 1 then
  1445.                 StretchMode := smNW;
  1446.             end;
  1447.           smSE :
  1448.             with Sender as TBaseField do begin
  1449.               NewWidth := X;
  1450.               Constrain(NewWidth, 0, Self.Width - Left);
  1451.               AdjustWidthToGrid(Left, NewWidth);
  1452.               NewHeight := Y;
  1453.               Constrain(NewHeight, 0, Self.Height - Top);
  1454.               AdjustHeightToGrid(Top, NewHeight);
  1455.               SetBounds(Left, Top, NewWidth, NewHeight);
  1456.               if Width <= 1 then begin
  1457.                 if Height <= 1 then
  1458.                   StretchMode := smNW
  1459.                 else
  1460.                   StretchMode := smSW;
  1461.               end else if Height <= 1 then
  1462.                 StretchMode := smNE;
  1463.             end;
  1464.           smNW :
  1465.             with Sender as TBaseField do begin
  1466.               NewLeft := Left + X;
  1467.               {Prevent creeping to right when switching from sm?W to sm?E}
  1468.               Constrain(NewLeft, 0, Left + Width);
  1469.               AdjustLeftToGrid(NewLeft);
  1470.               NewWidth := Width + Left - NewLeft;
  1471.               Constrain(NewWidth, 0, Self.Width - NewLeft);
  1472.               AdjustWidthToGrid(NewLeft, NewWidth);
  1473.               NewTop := Top + Y;
  1474.               {Prevent creeping down when switching from smN? to smS?}
  1475.               Constrain(NewTop, 0, Top + Height);
  1476.               AdjustTopToGrid(NewTop);
  1477.               NewHeight := Height + Top - NewTop;
  1478.               Constrain(NewHeight, 0, Self.Height - NewTop);
  1479.               AdjustHeightToGrid(NewTop, NewHeight);
  1480.               SetBounds(NewLeft, NewTop, NewWidth, NewHeight);
  1481.               if Width <= 1 then begin
  1482.                 if Height <= 1 then
  1483.                   StretchMode := smSE
  1484.                 else
  1485.                   StretchMode := smNE;
  1486.               end else if Height <= 1 then
  1487.                 StretchMode := smSW;
  1488.             end;
  1489.         end;
  1490.         Application.ProcessMessages;
  1491.       finally
  1492.         fpDragging := False;
  1493.       end;
  1494.       with Sender as TBaseField do
  1495.         if Selected then begin
  1496.           FieldPositionChange(Left, Top, Width, Height);
  1497.           {Set Ruler position marks to the new coordinates}
  1498.           if Self.Owner is TFaxDesigner then
  1499.             (Self.Owner as TFaxDesigner).SetMarkPositions(Left, Top, Width, Height);
  1500.         end;
  1501.       FNeedsSaving := True;
  1502.     end;
  1503.     StretchMode := (Sender as TBaseField).StretchMode;
  1504.   end else
  1505.     StretchMode := smNone;
  1506. end;
  1507. procedure TFaxPanel.SizeMove(Sender : TObject; Key : Word; Shift : TShiftState);
  1508. var
  1509.   X, Y      : Integer;
  1510.   NewWidth  : Integer;
  1511.   NewHeight : Integer;
  1512.   Delta     : TPoint;
  1513.   I, J      : Integer;
  1514.   BF        : TBaseField;
  1515. begin
  1516.   if Sender is TBaseField then begin
  1517.     case Key of
  1518.       VK_UP    : Delta := Point(0, -1);
  1519.       VK_DOWN  : Delta := Point(0, 1);
  1520.       VK_RIGHT : Delta := Point(1, 0);
  1521.       VK_LEFT  : Delta := Point(-1, 0);
  1522.     else
  1523.       if (Key = VK_TAB) and (Shift = []) then begin
  1524.         {select next object}
  1525.         J := -1;
  1526.         for I := 0 to FieldCount-1 do
  1527.           if Field[I].Selected then begin
  1528.             J := I;
  1529.             Break;
  1530.           end;
  1531.         if J >= 0 then begin
  1532.           Field[J].Selected := False;
  1533.           Inc(J);
  1534.           if J >= FieldCount then
  1535.             J := 0;
  1536.           Field[J].Selected := True;
  1537.           Invalidate;
  1538.         end;
  1539.       end else if (Key = VK_TAB) and (Shift = [ssShift]) then begin
  1540.         {select previous object}
  1541.         J := -1;
  1542.         for I := 0 to FieldCount-1 do
  1543.           if Field[I].Selected then begin
  1544.             J := I;
  1545.             Break;
  1546.           end;
  1547.         if J >= 0 then begin
  1548.           Field[J].Selected := False;
  1549.           Dec(J);
  1550.           if J < 0 then
  1551.             J := FieldCount-1;
  1552.           Field[J].Selected := True;
  1553.           Invalidate;
  1554.         end;
  1555.       end;
  1556.       Exit;
  1557.     end;
  1558.     BF := Sender as TBaseField;
  1559.     if (ssShift in Shift) then begin
  1560.       {size}
  1561.       X := BF.Width + Delta.X;
  1562.       Y := BF.Height + Delta.Y;
  1563.       NewWidth := X;
  1564.       NewHeight := Y;
  1565.       Constrain(NewWidth, 0, Self.Width - BF.Left);
  1566.       Constrain(NewHeight, 0, Self.Height - BF.Top);
  1567.       BF.SetBounds(BF.Left, BF.Top, NewWidth, NewHeight);
  1568.     end else if (ssCtrl in Shift) then begin
  1569.       {move}
  1570.       X := BF.Left + Delta.X;
  1571.       Y := BF.Top + Delta.Y;
  1572.       Constrain(X, 0, Width);
  1573.       Constrain(Y, 0, Height);
  1574.       {Ensure field remains entirely within Self}
  1575.       Constrain(X, 0, Self.Width  - BF.Width);
  1576.       Constrain(Y,  0, Self.Height - BF.Height);
  1577.       BF.SetBounds(X, Y, BF.Width, BF.Height);
  1578.     end;
  1579.     
  1580.     with Sender as TBaseField do
  1581.       if Selected then begin
  1582.         FieldPositionChange(Left, Top, Width, Height);
  1583.         {Set Ruler position marks to the new coordinates}
  1584.         if Self.Owner is TFaxDesigner then
  1585.           (Self.Owner as TFaxDesigner).SetMarkPositions(Left, Top, Width, Height);
  1586.       end;
  1587.     FNeedsSaving := True;
  1588.   end;
  1589. end;
  1590. procedure TFaxPanel.FieldSelectionChange(IsFieldSelected : Boolean);
  1591.   {-Calls OnFieldSelectionChange event handler when a field becomes
  1592.     deselected or when a new field becomes selected}
  1593. begin
  1594.   if Assigned(FOnFieldSelectionChange) then
  1595.     FOnFieldSelectionChange(IsFieldSelected);
  1596. end;
  1597. procedure TFaxPanel.FieldPositionChange(ALeft, ATop, AWidth, AHeight : Integer);
  1598.   {-Calls OnFieldPositionChange event handler when the location or size of
  1599.     the currently-selected field changes}
  1600. begin
  1601.   if Assigned(FOnFieldPositionChange) then
  1602.     FOnFieldPositionChange(ALeft, ATop, AWidth, AHeight);
  1603. end;
  1604. procedure TFaxPanel.FieldChange(Sender : TObject);
  1605. begin
  1606.   FNeedsSaving := True;
  1607. end;
  1608. procedure TFaxPanel.AdjustLeftToGrid(var ALeft : Integer);
  1609. begin
  1610.   if FSnapToGrid then begin
  1611.     if ALeft < ctGridStart then
  1612.       ALeft := ctGridStart
  1613.     else if ALeft > fpMaxGridLine.X then
  1614.       ALeft := fpMaxGridLine.X
  1615.     else
  1616.       ALeft := (Round((ALeft - ctGridStart) / FGridSpacingX) * FGridSpacingX) + ctGridStart;
  1617.   end;
  1618. end;
  1619. procedure TFaxPanel.AdjustTopToGrid(var ATop : Integer);
  1620. begin
  1621.   if FSnapToGrid then begin
  1622.     if ATop < ctGridStart then
  1623.       ATop := ctGridStart
  1624.     else if ATop > fpMaxGridLine.Y then
  1625.       ATop := fpMaxGridLine.Y
  1626.     else
  1627.       ATop := (Round((ATop - ctGridStart) / FGridSpacingY) * FGridSpacingY) + ctGridStart;
  1628.   end;
  1629. end;
  1630. procedure TFaxPanel.AdjustWidthToGrid(ALeft : Integer; var AWidth : Integer);
  1631. begin
  1632.   if FSnapToGrid then begin
  1633.     if AWidth < 0 then
  1634.       AWidth := 0
  1635.     else if ALeft + AWidth > fpMaxGridLine.X then
  1636.       AWidth := fpMaxGridLine.X - ALeft
  1637.     else
  1638.       AWidth := Round((AWidth) / FGridSpacingX) * FGridSpacingX + 1;
  1639.   end;
  1640. end;
  1641. procedure TFaxPanel.AdjustHeightToGrid(ATop : Integer; var AHeight : Integer);
  1642. begin
  1643.   if FSnapToGrid then begin
  1644.     if AHeight < 0 then
  1645.       AHeight := 0
  1646.     else if ATop + AHeight > fpMaxGridLine.Y then
  1647.       AHeight := fpMaxGridLine.Y - ATop
  1648.     else
  1649.       AHeight := Round((AHeight) / FGridSpacingY) * FGridSpacingY + 1;
  1650.   end;
  1651. end;
  1652. function TFaxPanel.GetDrawAdjustFactor : Double;
  1653. const
  1654.   ctFaxWidthInPixels = 1728;  {Faxes are 1728 pixels in width}
  1655. begin
  1656.   if Width = 0 then
  1657.     Result := 0.0
  1658.   else
  1659.     Result := ((ctFaxWidthInPixels / 2) - 10) / Width;
  1660. end;
  1661. function TFaxPanel.GetDrawWidth : Integer;
  1662. begin
  1663.   Result := Round(Width * DrawAdjustFactor);
  1664. end;
  1665. function TFaxPanel.GetDrawHeight : Integer;
  1666. begin
  1667.   Result := Round(Height * DrawAdjustFactor);
  1668. end;
  1669. procedure TFaxPanel.SetStretchMode(NewStretchMode : TStretchModes);
  1670. begin
  1671.   if NewStretchMode <> FStretchMode then begin
  1672.     FStretchMode := NewStretchMode;
  1673.     case FStretchMode of
  1674.       smN, smS   : Cursor := crSizeNS;
  1675.       smE, smW   : Cursor := crSizeWE;
  1676.       smNW, smSE : Cursor := crSizeNWSE;
  1677.       smNE, smSW : Cursor := crSizeNESW;
  1678.       else Cursor := crDefault;
  1679.     end;
  1680.   end;
  1681. end;
  1682. procedure TFaxPanel.FieldPositionChangeForSelectedField;
  1683. var
  1684.   I     : Integer;
  1685.   Field : TBaseField;
  1686. begin
  1687.   for I := 0 to fpFieldList.Count - 1 do begin
  1688.     Field := fpFieldList[I];
  1689.     with Field do
  1690.       if Selected then begin
  1691.         FieldPositionChange(Left, Top, Width, Height);
  1692.         Break; {Only one field can be selected at a time and we just found it, so exit loop}
  1693.       end;
  1694.   end;
  1695. end;
  1696. procedure TFaxPanel.Write(Stream : TStream);
  1697. var
  1698.   I         : Integer;
  1699.   NumFields : LongInt;
  1700.   Field     : TBaseField;
  1701. begin
  1702.   {Write the number of fields to the stream}
  1703.   NumFields := fpFieldList.Count;
  1704.   Stream.WriteBuffer(NumFields, SizeOf(NumFields));
  1705.   {Write out each field's information}
  1706.   for I := 0 to fpFieldList.Count - 1 do begin
  1707.     Field := fpFieldList[I];
  1708.     Field.Write(Stream);
  1709.   end;
  1710.   {We just saved, so set NeedsSaving to False}
  1711.   FNeedsSaving := False;
  1712. end;
  1713. procedure TFaxPanel.Read(Stream : TStream);
  1714. var
  1715.   FieldType : Byte;
  1716.   I         : Integer;
  1717.   NumFields : LongInt;
  1718.   Field     : TBaseField;
  1719. begin
  1720.   {Clear out fpFieldList to ensure we're starting off with an empty FaxPanel}
  1721.   DeleteAllFields;
  1722.   {Read the number of fields that were written out to the stream}
  1723.   Stream.ReadBuffer(NumFields, SizeOf(NumFields));
  1724.   {For each field, create a new field of the proper type, and then let it read
  1725.    itself in}
  1726.   for I := 1 to NumFields do begin
  1727.     Field := nil;
  1728.     Stream.ReadBuffer(FieldType, SizeOf(FieldType));
  1729.     case FieldType of
  1730.       ftTextField  : Field := AddTextField;
  1731.       ftImageField : Field := AddImageField;
  1732.     end;
  1733.     if Assigned(Field) then
  1734.       Field.Read(Stream);
  1735.   end;
  1736.   {No changes have been made yet, so set NeedsSaving to False}
  1737.   FNeedsSaving := False;
  1738. end;
  1739. procedure TFaxPanel.Draw(ACanvas : TCanvas);
  1740. var
  1741.   I     : Integer;
  1742.   Field : TBaseField;
  1743. begin
  1744.   {Draw each field}
  1745.   for I := 0 to fpFieldList.Count - 1 do begin
  1746.     Field := fpFieldList[I];
  1747.     Field.Draw(ACanvas);
  1748.   end;
  1749. end;
  1750. function TFaxPanel.HorzPixelsToInches(P : Integer) : Double;
  1751. begin
  1752.   if fpHorzPixelsPerInch = 0.0 then
  1753.     Result := 0.0
  1754.   else
  1755.     Result := P / fpHorzPixelsPerInch;
  1756. end;
  1757. function TFaxPanel.VertPixelsToInches(P : Integer) : Double;
  1758. begin
  1759.   if fpVertPixelsPerInch = 0.0 then
  1760.     Result := 0.0
  1761.   else
  1762.     Result := P / fpVertPixelsPerInch;
  1763. end;
  1764. function TFaxPanel.HorzInchesToPixels(Inches : Double) : Integer;
  1765. begin
  1766.   Result := Round(Inches * fpHorzPixelsPerInch);
  1767. end;
  1768. function TFaxPanel.VertInchesToPixels(Inches : Double) : Integer;
  1769. begin
  1770.   Result := Round(Inches * fpVertPixelsPerInch);
  1771. end;
  1772. procedure TFaxPanel.DeselectAllFields;
  1773. var
  1774.   I     : Integer;
  1775.   Field : TBaseField;
  1776. begin
  1777.   for I := fpFieldList.Count - 1 downto 0 do begin
  1778.     Field := fpFieldList[I];
  1779.     Field.Selected := False;
  1780.   end;
  1781. end;
  1782. procedure TFaxPanel.DeleteAllFields;
  1783. var
  1784.   I     : Integer;
  1785.   Field : TBaseField;
  1786. begin
  1787.   for I := fpFieldList.Count - 1 downto 0 do begin
  1788.     Field := fpFieldList[I];
  1789.     Field.Free;
  1790.     fpFieldList.Remove(fpFieldList[I]);
  1791.   end;
  1792.   FNeedsSaving := True;
  1793. end;
  1794. procedure TFaxPanel.AddField(Field : TBaseField);
  1795. var
  1796.   NewLeft   : Integer;
  1797.   NewTop    : Integer;
  1798.   NewWidth  : Integer;
  1799.   NewHeight : Integer;
  1800. begin
  1801.   DeselectAllFields;
  1802.   NewLeft := fpMouseAnchor.X;
  1803.   NewTop  := fpMouseAnchor.Y;
  1804.   with Field do begin
  1805.     {Update NewLeft and NewTop to ensure new field will be entirely within MainPanel}
  1806.     Constrain(NewLeft, 0, Self.Width  - Width);
  1807.     Constrain(NewTop,  0, Self.Height - Height);
  1808.     NewWidth  := Width;
  1809.     NewHeight := Height;
  1810.     {If SnapToGrid is enabled, adjust coordinates to be on grid lines}
  1811.     if FSnapToGrid then begin
  1812.       AdjustLeftToGrid(NewLeft);
  1813.       AdjustTopToGrid(NewTop);
  1814.       AdjustWidthToGrid(NewLeft, NewWidth);
  1815.       AdjustHeightToGrid(NewTop, NewHeight);
  1816.     end;
  1817.     SetBounds(NewLeft, NewTop, NewWidth, NewHeight);
  1818.     Parent   := Self;
  1819.     Visible  := True;
  1820.     Selected := True; {New fields start out Selected}
  1821.   end;
  1822.   if Field is TTextField then
  1823.     (Field as TTextField).SetFocus;
  1824.   fpFieldList.Add(Field);
  1825.   FieldSelectionChange(True);
  1826.   with Field do
  1827.     FieldPositionChange(Left, Top, Width, Height);
  1828.   FNeedsSaving := True;
  1829.   Inc(fpMouseAnchor.X, 5);
  1830.   Inc(fpMouseAnchor.Y, 5);
  1831. end;
  1832. function TFaxPanel.AddTextField : TTextField;
  1833. begin
  1834.   Result := TTextField.Create(nil);
  1835.   AddField(Result);
  1836. end;
  1837. function TFaxPanel.AddImageField : TImageField;
  1838. begin
  1839.   Result := TImageField.Create(nil);
  1840.   AddField(Result);
  1841. end;
  1842. procedure TFaxPanel.DeleteSelectedField;
  1843. var
  1844.   I     : Integer;
  1845.   Field : TBaseField;
  1846. begin
  1847.   {Delete all fields that are currently selected}
  1848.   for I := fpFieldList.Count - 1 downto 0 do begin
  1849.     Field := fpFieldList[I];
  1850.     if Field.Selected then begin
  1851.       Field.Free;
  1852.       fpFieldList.Remove(fpFieldList[I]);
  1853.       FNeedsSaving := True;
  1854.     end;
  1855.   end;
  1856.   {Turn Ruler position marks off since no fields are selected}
  1857.   if Self.Owner is TFaxDesigner then
  1858.     (Self.Owner as TFaxDesigner).SetMarkPositions(-1, -1, -1, -1);
  1859. end;  
  1860. procedure TFaxPanel.CenterSelectedField(IsHorizontal : Boolean);
  1861. var
  1862.   I      : Integer;
  1863.   NewPos : Integer;
  1864.   Field  : TBaseField;
  1865. begin
  1866.   for I := fpFieldList.Count - 1 downto 0 do begin
  1867.     Field := fpFieldList[I];
  1868.     if Field.Selected then begin
  1869.       if IsHorizontal then begin
  1870.         NewPos := Round((Width - Field.Width) / 2);
  1871.         AdjustLeftToGrid(NewPos);  {Align to grid if SnapToGrid is enabled}
  1872.         Field.Left := NewPos;
  1873.       end else begin
  1874.         NewPos := Round((Height - Field.Height) / 2);
  1875.         AdjustTopToGrid(NewPos);  {Align to grid if SnapToGrid is enabled}
  1876.         Field.Top := NewPos;
  1877.       end;
  1878.       with Field do begin
  1879.         FieldPositionChange(Left, Top, Width, Height);
  1880.         {Set Ruler position marks to the new coordinates}
  1881.         if Self.Owner is TFaxDesigner then
  1882.           (Self.Owner as TFaxDesigner).SetMarkPositions(Left, Top, Width, Height);
  1883.       end;
  1884.       FNeedsSaving := True;
  1885.       Break;
  1886.     end;
  1887.   end;
  1888. end;
  1889. function TFaxPanel.SelectedFieldsExist : Boolean;
  1890. var
  1891.   I     : Integer;
  1892.   Field : TBaseField;
  1893. begin
  1894.   Result := False;
  1895.   for I := 0 to fpFieldList.Count - 1 do begin
  1896.     Field := fpFieldList[I];
  1897.     if Field.Selected then begin
  1898.       Result := True;
  1899.       Break;
  1900.     end;
  1901.   end;
  1902. end;
  1903. {------------------------------- TFaxScrollBox ------------------------------}
  1904. procedure TFaxScrollBox.WMHScroll(var Message : TWMHScroll);
  1905. var
  1906.   Dummy : Integer;
  1907. begin
  1908.   inherited;
  1909.   if Assigned(FOnHorzScroll) and (Message.ScrollBar = 0) and HorzScrollBar.Visible then
  1910.     {Doesn't matter what parameters we pass because they aren't used}
  1911.     FOnHorzScroll(nil, scTop, Dummy);
  1912. end;
  1913. procedure TFaxScrollBox.WMVScroll(var Message : TWMVScroll);
  1914. var
  1915.   Dummy : Integer;
  1916. begin
  1917.   inherited;
  1918.   if Assigned(FOnVertScroll) and (Message.ScrollBar = 0) and VertScrollBar.Visible then
  1919.     {Doesn't matter what parameters we pass because they aren't used}
  1920.     FOnVertScroll(nil, scTop, Dummy);
  1921. end;
  1922. {*** TFaxDesigner ***}
  1923. constructor TFaxDesigner.Create(AOwner : TComponent);
  1924. begin
  1925.   inherited Create(AOwner);
  1926.   Align       := alClient;
  1927.   BevelInner  := bvNone;
  1928.   BevelOuter  := bvRaised;
  1929.   BorderStyle := bsNone;
  1930.   FIsNew      := True;
  1931.   fdScrollBox := TFaxScrollBox.Create(Self);
  1932.   with fdScrollBox do begin
  1933.     BorderStyle := bsNone;
  1934.     Parent      := Self;
  1935.     {$IFDEF Win32}
  1936.     HorzScrollBar.Tracking := True;
  1937.     VertScrollBar.Tracking := True;
  1938.     {$ENDIF}
  1939.     OnHorzScroll := HorzScroll;
  1940.     OnVertScroll := VertScroll;
  1941.   end;
  1942.   fdHorzRuler := TRuler.Create(Self);
  1943.   with fdHorzRuler do begin
  1944.     IsHorizontal := True;
  1945.     Parent       := Self;
  1946.   end;
  1947.   fdVertRuler := TRuler.Create(Self);
  1948.   with fdVertRuler do begin
  1949.     IsHorizontal := False;
  1950.     Parent       := Self;
  1951.   end;
  1952.   FFaxPanel := TFaxPanel.Create(Self);
  1953.   with FFaxPanel do begin
  1954.     Color  := clWindow;
  1955.     Parent := fdScrollBox;
  1956.   end;
  1957.   {These access FFaxPanel, so they must be called AFTER FFaxPanel is created}
  1958.   SetPageWidthPixels(ctDefaultWidthPixels);
  1959.   SetPageHeightPixels(ctDefaultHeightPixels);
  1960.   SetPageWidthInches(ctDefaultWidthInches);
  1961.   SetPageHeightInches(ctDefaultHeightInches);
  1962.   {FaxPanel.NeedsSaving will have been changed to True when we set the Width and
  1963.    Height in Inches. No changes have actually been made, so reset it to False.}
  1964.   FFaxPanel.NeedsSaving := False;
  1965. end;
  1966. procedure TFaxDesigner.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  1967. var
  1968.   Length    : Integer;
  1969.   OldWidth  : Integer;
  1970.   OldHeight : Integer;
  1971.   Dummy     : Integer;
  1972. begin
  1973.   OldWidth  := Width;
  1974.   OldHeight := Height;
  1975.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  1976.   if Parent <> nil then begin
  1977.     fdScrollBox.SetBounds(ALeft + fdVertRuler.Width, ATop + fdHorzRuler.Height,
  1978.                           Self.ClientWidth - fdVertRuler.Width,
  1979.                           Self.ClientHeight - fdHorzRuler.Height);
  1980.     {Ensure that HorzRuler doesn't get longer than the width of the FaxPanel}
  1981.     if Self.ClientHeight - fdHorzRuler.Height < FFaxPanel.Height then
  1982.       Length := Self.ClientHeight - fdHorzRuler.Height
  1983.     else
  1984.       Length := FFaxPanel.Height;
  1985.     fdVertRuler.SetBounds(0, fdHorzRuler.Height, fdVertRuler.Width, Length);
  1986.     {Ensure that VertRuler doesn't get taller than the height of the FaxPanel}
  1987.     if Self.ClientWidth - fdVertRuler.Width < FFaxPanel.Width then
  1988.       Length := Self.ClientWidth - fdVertRuler.Width
  1989.     else
  1990.       Length := FFaxPanel.Width;
  1991.     fdHorzRuler.SetBounds(fdVertRuler.Width, 0, Length, fdHorzRuler.Height);
  1992.     {If the form has been made wider or taller, its possible that the one of the
  1993.      rulers might need to "scroll" to match, so call HorzScroll or VertScroll
  1994.      as needed. It doesn't matter what parameters we pass because the parameters
  1995.      aren't used.}
  1996.     if Width <> OldWidth then
  1997.       HorzScroll(nil, scTop, Dummy);
  1998.     if Height <> OldHeight then
  1999.       VertScroll(nil, scTop, Dummy);
  2000.   end;
  2001. end;  
  2002. procedure TFaxDesigner.SetParent(AParent: TWinControl);
  2003. begin
  2004.   inherited SetParent(AParent);
  2005.   if Assigned(AParent) then
  2006.     {Now that a Parent is set, call SetBounds to put the Rulers in the correct positions}
  2007.     SetBounds(Left, Top, Width, Height);
  2008. end;
  2009. procedure TFaxDesigner.HorzScroll(Sender: TObject; ScrollCode: TScrollCode;
  2010.                               var ScrollPos: Integer);
  2011. var
  2012.   X, Y : Integer;
  2013. begin
  2014.   {Find the leftmost FFaxPanel point that is displaying within fdScrollBox}
  2015.   X := 0;
  2016.   Y := 0;
  2017.   ConvertCoords(fdScrollBox, FFaxPanel, X, Y);
  2018.   {Scroll fdHorzRuler to match the scroll position of FFaxPanel}
  2019.   fdHorzRuler.StartPosition := X;
  2020. end; 
  2021. procedure TFaxDesigner.VertScroll(Sender: TObject; ScrollCode: TScrollCode;
  2022.                               var ScrollPos: Integer);
  2023. var
  2024.   X, Y : Integer;
  2025. begin
  2026.   {Find the topmost FFaxPanel point that is displaying within fdScrollBox}
  2027.   X := 0;
  2028.   Y := 0;
  2029.   ConvertCoords(fdScrollBox, FFaxPanel, X, Y);
  2030.   {Scroll fdVertRuler to match the scroll position of FFaxPanel}
  2031.   fdVertRuler.StartPosition := Y;
  2032. end;
  2033. function TFaxDesigner.GetPageWidthPixels : Integer;
  2034. begin
  2035.   Result := FFaxPanel.Width;
  2036. end;
  2037. procedure TFaxDesigner.SetPageWidthPixels(AWidth : Integer);
  2038. var
  2039.   Dummy : Integer;
  2040. begin
  2041.   if FFaxPanel.Width <> AWidth then begin
  2042.     FFaxPanel.Width := AWidth;
  2043.     if Assigned(fdHorzRuler) then begin
  2044.       fdHorzRuler.SizePixels := AWidth;
  2045.       {Call SetBounds to force fdHorzRuler to the correct size}
  2046.       SetBounds(Left, Top, Width, Height);
  2047.       if Parent <> nil then
  2048.         HorzScroll(nil, scTop, Dummy);  {Update ruler position}
  2049.     end;
  2050.   end;
  2051. end;
  2052. function TFaxDesigner.GetPageHeightPixels : Integer;
  2053. begin
  2054.   Result := FFaxPanel.Height;
  2055. end;
  2056. procedure TFaxDesigner.SetPageHeightPixels(AHeight : Integer);
  2057. var
  2058.   Dummy : Integer;
  2059. begin
  2060.   if FFaxPanel.Height <> AHeight then begin
  2061.     FFaxPanel.Height := AHeight;
  2062.     if Assigned(fdVertRuler) then begin
  2063.       fdVertRuler.SizePixels := AHeight;
  2064.       //设为正确的大小
  2065.       SetBounds(Left, Top, Width, Height);
  2066.       if Parent <> nil then
  2067.         VertScroll(nil, scTop, Dummy);//更新尺的位置
  2068.     end;
  2069.   end;
  2070. end;
  2071. function TFaxDesigner.GetPageWidthInches : Double;
  2072. begin
  2073.   Result := FFaxPanel.PageWidthInches;
  2074. end;
  2075. procedure TFaxDesigner.SetPageWidthInches(AWidth : Double);
  2076. begin
  2077.   if Assigned(fdHorzRuler) then
  2078.     fdHorzRuler.SizeInches := AWidth;
  2079.   //调整页度
  2080.   FFaxPanel.PageWidthInches := AWidth;
  2081.   if PageWidthInches <> 0.0 then
  2082.     SetPageHeightPixels(Round(PageHeightInches * PageWidthPixels / PageWidthInches));
  2083. end;
  2084. function TFaxDesigner.GetPageHeightInches : Double;
  2085. begin
  2086.   Result := FFaxPanel.PageHeightInches;
  2087. end;
  2088. procedure TFaxDesigner.SetPageHeightInches(AHeight : Double);
  2089. begin
  2090.   if Assigned(fdVertRuler) then
  2091.     fdVertRuler.SizeInches := AHeight;
  2092.   FFaxPanel.PageHeightInches := AHeight;
  2093.   //调整页高
  2094.   if PageWidthInches <> 0.0 then
  2095.     SetPageHeightPixels(Round(PageHeightInches * PageWidthPixels / PageWidthInches));
  2096. end;
  2097. procedure TFaxDesigner.SetIsMetric(AIsMetric : Boolean);
  2098. begin
  2099.   if AIsMetric <> FIsMetric then begin
  2100.     FIsMetric := AIsMetric;
  2101.     if Assigned(fdHorzRuler) then
  2102.       fdHorzRuler.IsMetric := AIsMetric;
  2103.     if Assigned(fdVertRuler) then
  2104.       fdVertRuler.IsMetric := AIsMetric;
  2105.     //
  2106.     FFaxPanel.FieldPositionChangeForSelectedField;
  2107.   end;
  2108. end;
  2109. procedure TFaxDesigner.SetMarkPositions(ALeft, ATop, AWidth, AHeight : Integer);
  2110. begin
  2111.   if Assigned(fdHorzRuler) then
  2112.     fdHorzRuler.SetMarkPositions(ALeft, ALeft + AWidth);
  2113.   if Assigned(fdVertRuler) then
  2114.     fdVertRuler.SetMarkPositions(ATop, ATop + AHeight);
  2115. end;
  2116. procedure TFaxDesigner.Read(Stream : TStream);
  2117. var
  2118.   PageRec : TPageRecord;
  2119. begin
  2120.    Stream.ReadBuffer(PageRec, SizeOf(PageRec));
  2121.   with PageRec do begin
  2122.     if prVersionNum <> ctVersionNum then begin
  2123.       MessageDlg('Version mismatch! Unable to read Fax Cover Page!', mtError, [mbOK], 0);
  2124.       Exit;
  2125.     end;
  2126.     SetPageWidthPixels(prPageWidthPixels);
  2127.     SetPageHeightPixels(prPageHeightPixels);
  2128.     SetPageWidthInches(prPageWidthInches);
  2129.     SetPageHeightInches(prPageHeightInches);
  2130.     SetIsMetric(prIsMetric);
  2131.     FUserData := prUserData;
  2132.   end;
  2133.    FFaxPanel.Read(Stream);
  2134.   //设置为已存在封面页
  2135.   FIsNew := False;
  2136. end;
  2137. procedure TFaxDesigner.Write(Stream : TStream);
  2138. var
  2139.   PageRec : TPageRecord;
  2140. begin
  2141.   //初始化pageRec
  2142.   FillChar(PageRec, SizeOf(PageRec), 0);
  2143.   with PageRec do begin
  2144.     prVersionNum       := ctVersionNum;
  2145.     prPageWidthPixels  := GetPageWidthPixels;
  2146.     prPageHeightPixels := GetPageHeightPixels;
  2147.     prPageWidthInches  := GetPageWidthInches;
  2148.     prPageHeightInches := GetPageHeightInches;
  2149.     prIsMetric         := FIsMetric;
  2150.     prUserData         := FUserData;
  2151.   end;
  2152.   Stream.WriteBuffer(PageRec, SizeOf(PageRec));
  2153.   FFaxPanel.Write(Stream);
  2154.  
  2155.   FIsNew := False;
  2156. end;
  2157. end.