unit SpecForm;
{$I DEFINE.PAS}
interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, ExtCtrls, StdCtrls, Printers,
  {$IFDEF WIN32}
  CommInt, ComPort, Menus, Buttons,
  {$ELSE}
  Comm,
  {$ENDIF}
  ConfType,

  TVType, MyLib, Fileu, MyType, Stru, confu,
  ListType, Listu,
  Timer, BinHex,
  ShowMsg, cmgh,
  ApexType, Spectrum, Globals, Axisu, Plotu,
  drawbuf, repform,
  UlanType, UlanGlob, ghlbtype,
  UldrvTyp, ul_lcabs, devmode, filtdlg,
  ULRecTyp, ULObju,
  ULBRType, ULBRObju,
  ULPRType, ULPRObju,
  ULVLType, ULVLObju,
  ULVOType, ULVOObju,

  MouseLin, WinUtl, ComCtrls, ToolWin, FontUtl, PrnUtl
  ;
type

  TSpectrumForm = class(TForm)
    PaintBox: TPaintBox;
    Timer1: TTimer;
    SpectrumMemo: TMemo;
    PopupMenu: TPopupMenu;
    LogMenuItem: TMenuItem;
    MarginsItem: TMenuItem;
    RunStopItem: TMenuItem;
    ToolsPanel: TPanel;
    DefineBaseLineSpeedButton: TSpeedButton;
    DefinePeaksSpeedButton: TSpeedButton;
    ReportPanel: TPanel;
    ReportMemo: TMemo;
    DefineMarginsSpeedButton: TSpeedButton;
    MarginBackSpeedButton: TSpeedButton;
    DefineLabel: TLabel;
    ViewLabel: TLabel;
    BaseLineCheckBox: TCheckBox;
    AxisCheckBox: TCheckBox;
    PeaksCheckBox: TCheckBox;
    ReportCheckBox: TCheckBox;
    RunPanel: TPanel;
    RunButton: TButton;
    StopButton: TButton;
    N1: TMenuItem;
    HeaderItem: TMenuItem;
    SaveDialog: TSaveDialog;
    ViewItem: TMenuItem;
    PeaksItem: TMenuItem;
    PeaksClearMenuItem: TMenuItem;
    PeaksDeleteLastItem: TMenuItem;
    Autodetect1: TMenuItem;
    PeaksBrowseItem: TMenuItem;
    BaseLineItem: TMenuItem;
    BaseLineDefineItem: TMenuItem;
    BaseLineBrowseItem: TMenuItem;
    PeaksDefineItem: TMenuItem;
    PrintItem: TMenuItem;
    XYEdit: TEdit;
    PeaksDeleteSelectedItem: TMenuItem;
    N2: TMenuItem;
    MethodItem: TMenuItem;
    MethodEditItem: TMenuItem;
    MethodPeaksItem: TMenuItem;
    MethodPeaksClearItem: TMenuItem;
    MethodPeaksBrowseItem: TMenuItem;
    FilterMenuItem: TMenuItem;
    PeaksToMethodItem: TMenuItem;
    procedure FormCreate(Sender: TObject);
    procedure ComPortReceive(Sender: TObject
      {$IFDEF WIN32};Count: Integer{$ELSE};Count: Word{$ENDIF});
    procedure Timer1Timer(Sender: TObject);
    procedure PaintBoxPaint(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure LogMenuItemClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure MarginsItemClick(Sender: TObject);
    procedure PopupMenuPopup(Sender: TObject);
    procedure RunStopItemClick(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure AxisItemClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormDeactivate(Sender: TObject);
    procedure PeaksClearMenuItemClick(Sender: TObject);
    procedure PaintBoxMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PaintBoxMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure BaseLineMenuItemClick(Sender: TObject);
    procedure PaintBoxMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure PeaksReportMenuItemClick(Sender: TObject);
    procedure PeaksMenuItemClick(Sender: TObject);
    procedure DefineSpeedButtonClick(Sender: TObject);
    procedure ReportPanelMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure MarginBackSpeedButtonClick(Sender: TObject);
    procedure StopButtonClick(Sender: TObject);
    procedure RunButtonClick(Sender: TObject);
    procedure BaseLineCheckBoxMouseUp(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure AxisCheckBoxMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure PeaksCheckBoxMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ReportCheckBoxMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FilterMenuItemClick(Sender: TObject);
    procedure HeaderItemClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure PeaksDeleteLastItemClick(Sender: TObject);
    procedure Autodetect1Click(Sender: TObject);
    procedure PeaksBrowseItemClick(Sender: TObject);
    procedure BaseLineDefineItemClick(Sender: TObject);
    procedure BaseLineBrowseItemClick(Sender: TObject);
    procedure PeaksDefineItemClick(Sender: TObject);
    procedure PrintItemClick(Sender: TObject);
    procedure ViewXYItemClick(Sender: TObject);
    procedure PeaksDeleteSelectedItemClick(Sender: TObject);
    procedure ViewHeaderItemClick(Sender: TObject);
    procedure ViewItemClick(Sender: TObject);
    procedure MethodEditItemClick(Sender: TObject);
    procedure MethodPeaksClearItemClick(Sender: TObject);
    procedure MethodPeaksBrowseItemClick(Sender: TObject);
    procedure PeaksToMethodItemClick(Sender: TObject);
  private
    { Private declarations }
    IsInTimer:boolean;
    IsInReceive:boolean;
    IsInPaint:boolean;
    RunningState:TRunningState;
    CommPort:TComm;
    RcvBuf:array[0..RcvBufSize - 1] of char;
    DrawLocked:integer;
    DrawWanted:boolean;
    ScrBuf: array[0..MaxDataCountInForm - 1] of TScrBuf;
    PeakDefineMode: TPeakDefineMode;
    BaseLineDefineMode: TPeakDefineMode;
    MarginML: TMouseLine;
    PeakML: TMouseLine;
    BaseLineML: TMouseLine;
    FDefineMode: TDefineMode;
    FDefineModePermanent: boolean;
      { If define mode initiated by clicking on toolbutton with shift pressed,
        then form remains in the define mode until explicitly canceled, otherwise
        define mode set dmNone after following mousedown/mouseup sequence }
    UserLimitStack:TLst;
    ChangingView:boolean;{true during call
      to SpectrumObjectShow..; prevents
      OnClick handlers to function during
      changing Checked properties }
    SII: PScanInputInfo;
      { used if DeviceMode = dmUlan }
    DataList: TList;
      { List of TAcqData, used if more chromatograms shown in one window }
    AngleText: TAngleText;
      { for drawing peak names }
    FDataPrinter: TDataPrinter;
    procedure DoInChar(CommChar:char);
      procedure DoApexChar(CommChar:char);
      procedure DoGHLabChar(CommChar:char);

    function GetFileName: string;
  protected
    procedure SetDefineMode(ADefineMode: TDefineMode);
      procedure MarginsDefineStart;
      procedure MarginsDefineStop;
      procedure BaseLineDefineStart;
      procedure BaseLineDefineStop;
      procedure PeaksDefineStart;
      procedure PeaksDefineStop;
    procedure UpdatePrinterDisp(APrinter:TPrinter);
    procedure UpdateViewLimitRecFromDataFile(force: boolean);
      { Called from SetDataFile, updates UserViewLimits record by values
        from Data.ULVL record (if (FixedView or force) and not Mode = omCreate) }
    procedure UpdateViewLimitRecToDataFile(force:boolean);
    procedure UpdateViewOptionsFromDataFile;


  public
    { Public declarations }
    DeviceMode: TDeviceMode;{dmApex, dmUlan or dmGHLab}
    PortName: shortstring;{portname assigned upon win create}
    UVDetAddr: longint;
      { ulan address of UV detector module (used if DeviceMode = dmUlan) }
    Data: TAcqData;
      { Currently selected data. In overlay mode more TAcqData object can
        be opened and stored in DataList. Data points to the default one. }
    DataIndex: integer;
      { Index of Data in DataList }

    PacketFifo:TLst;

    ApexPktInfo:TApexPacketInfo;{just beeing received packet apextype}
    GHLabPktInfo:TGHLabPacketInfo;

    ZeroValue:single;{currently set zero value (in absolute units)
      of the y value, used to  calculate apexdatarec.y value from
      apexpacket values}
    ZeroTime:Longint;

    OrigUserViewLimit, UserViewLimit: TUserViewLimit;

    ViewLimit: TExpViewLimit;
    Limit: TExpViewLimit;
    ScreenDisp: TScreenDisp;
    PrinterDisp: TScreenDisp;
    OutDisp: PScreenDisp;
      { points to one of the above }
    LogPackets: boolean;

    AxisPlotting: TPlotting;

    Spect:TSpectrum;
      { Spectrum used for peaks evaluation. }

    PeakStartPoint,PeakStopPoint:TPoint;
      { Used by StartPeak, FinishPeak and CreatePeak methods - manual,
        interactive with mouse defining of peaks }
    BaseLineStartPoint,BaseLineStopPoint:TPoint;

    ReportFrm:TReportForm;

    procedure DoApexPacket(var ai:TApexPacketInfo);
      { Converts received apex packet data to Data stream }
    procedure DoGHLabPacket(var gi:TGHLabPacketInfo);

    procedure UserViewRecToExpViewRec(const AUserViewLimit:TUserViewLimit;
      var AViewLimit:TExpViewLimit);

    {procedure ApexViewRecToUserViewRec(const AViewLimit:TExpViewLimit;
      var AUserViewLimit:TUserViewLimit); {apextype}
    function ApexRecToScreenRec(const AApexRec:TExpPoint;
      var AScreenRec:TScreenPoint):boolean;
    function ScreenPointToIndexPoint(const AScreenPoint:TPoint;
      var AIndexPoint:TIndexPoint):boolean;
      { ..get the datapoint (TIndexPoint = record Index:longint;
        Point:TExpPoint end;) that is closest to AScreenPoint }
    procedure SetPacketLogging(onOff:boolean);
    procedure DrawPoints(ACanvas:TCanvas);
      { Draw just the points not drawn yet. }
      procedure DrawScreenPoints(ACanvas:TCanvas);
        { Draw the points from buffer. }
    procedure Redraw;
      { All points. }
    procedure SetToRedraw(tr:TToRedraw);
      { Define what should be surely redrawn during next paint event
       (after call to Redraw), i.e. ignore all buffers etc.}
    procedure ReadFromIniFile;
    procedure WriteToIniFile;
    procedure SetDataFile(const AFileName:string; AMode: TOpenMode);
      { Set new data to be worked on. }
    procedure AddDataFile(const AFileName:string);
      { Add new data file (in OverlayMode more chromatograms can be shown in
        one window }
    procedure DataSetCurrent(Index: integer);
      { In overlay mode - set data with given index in
        DataList as Data }

    procedure DataListClear;
      { dispose all data }
    procedure Run;
    procedure Stop;
    procedure UpdateCaption;
    procedure ClearData;
    procedure DrawAxis(ACanvas: TCanvas);
    procedure DrawBaseLine(ACanvas: TCanvas);
    procedure DrawHeader(ACanvas: TCanvas);

    {procedure UndrawBaseLine;}
    procedure UpdateScreenDisp;
    procedure UpdateViewLimit;
    procedure PlottingToCanvas(var APlot:TPlotting; ACanvas:TCanvas);
    function DoSaveTo:boolean;
      { Calls SaveDialog.Execute - SaveTo, returns false if was not saved }
    procedure SaveTo(AFileName:string);
      { Saves current chromatogram to AFileName }
    procedure WMAppMessage(var Msg:TMessage);message WM_APPMESSAGE;{in globals}
      procedure ULObjBeforeEdit(var Msg: TMessage);
      procedure ULObjAfterEdit(var Msg: TMessage);
    procedure PeaksShow;
    procedure PeaksHide;
    {procedure PeaksDefineAbort;}
      {procedure ClosePeaksDefineForm;}

    function StartCreateBaseLine(X,Y:integer):boolean;
      { Called upon mouse down (if DefiningBaseLine). Returns false,
        if baseline interval can not be created in at given pos }
    function StartMoveBaseLine(X: integer): boolean;
    function StartSizeBaseLine(X: integer): boolean;
    function IsInBaseLine(X:integer; var Index:integer): boolean;
      { Is given X screen position inside any baseline interval? }
    function IsInBaseLineEdge(var X: integer; Y:integer; var Index: integer): boolean;
      { returns true if X is inside the circle drawn around the intersection of
        baseline section with the curve, adjusts X to the intersection X }
    procedure FinishBaseLine(X,Y:integer);{called upon mouse up ..}
    {function PeakStarted:boolean;{true during mouse down ..}
      procedure CreateBaseLine(const AStartPoint, AStopPoint:TPoint);
      procedure MoveBaseLine(OldStartX, NewStartX:integer);
      procedure SizeBaseLine(OldStopX, NewStopX:integer; Right: boolean);


    function StartCreatePeak(X,Y:integer):boolean;
      { Called upon mouse down (if DefiningPeaks). Returns false,
        if peak can not be created in at given pos }
    function StartMovePeak(X: integer): boolean;
    function StartSizePeak(X: integer): boolean;

    function IsPeakStart(X: integer): boolean;
    function IsPeakStop(X: integer): boolean;
    function IsInPeak(X:integer; var PeakIndex:integer): boolean;
      { Is given X screen position inside any peak? }
    function IsInPeakEdge(X,Y: integer; var PeakIndex:integer):boolean;
      { Is given screen coordinates inside edge sign of any peak? }

    procedure FinishPeak(X, Y: integer; Shift: TShiftState);{called upon mouse up ..}
    {function PeakStarted:boolean;{true during mouse down ..}
      procedure CreatePeak(const AStartPoint, AStopPoint:TPoint);
      procedure MovePeak(OldStartX, NewStartX:integer);
      procedure SizePeak(OldStopX, NewStopX:integer; Right: boolean);
      procedure ToggleSelectPeak(X: integer; Shift: TShiftState);
      {..called from FinishPeak}
    procedure PeakEditProperties(PeakIndex: integer);
      { Called if clicked with right mouse button in DefiningPeaks form mode
        inside the peak with PeakIndex. }
    procedure BaseLineEditProperties(PeakIndex: integer);


    procedure DrawPeaks(ACanvas: TCanvas);
      { Called from PaintBoxPaint to draw the peaks. }
    procedure LockDraw;
    procedure UnlockDraw;
    {procedure CountBaseLinePos;
    procedure SetBaseLinePos(APos:integer);}
    procedure CreatePeakReport;
    procedure ShowReport;
    procedure HideReport;
    {procedure UpdateMarginRec(X,Y:integer);}
    {procedure DrawMarginRec(first:boolean);}
    procedure SetScreenSubView(X1,Y1,X2,Y2:integer);
    procedure PopScreenSubView;
    function SpectrumObjectVisible(so:TSpectrumObject):boolean;
    procedure SpectrumObjectShow(so:TSpectrumObject; OnOff:boolean);
    procedure RunPanelShow;
    procedure PortSetDefaults;
    procedure PortOpen;
    procedure PortClose;
    procedure ResetPacketInfo;
    procedure Print;
    function Printing: boolean;
    function PeakStickLen: integer;
    function PeakArrowLen: integer;
    function BaseLineCircleRadius: integer;
    property FileName:String read GetFileName;
    property DefineMode: TDefineMode read FDefineMode write SetDefineMode;
    property DefineModePermanent: boolean read FDefineModePermanent write FDefineModePermanent;
  end;

var
  SpectrumForm: TSpectrumForm;

procedure CreateSpectrumForm(const Name: string; AMode: TOpenMode);

implementation

{$R *.DFM}
uses main, margdial
{$IFDEF DEBUG}
  ,debugfrm
{$ENDIF}{peform wm_syscommand}
;
const
  SpectrumFormCount:integer = 0;
    {current number of opened spectrum windows}
  MaxSpectrumFormCount:integer = 4;
    {max allowed number of spectrum windows}

function CountYOnScreenLine(X: TScreenX; X1: TScreenX; Y1: TScreenY;
  X2: TScreenX; Y2: TScreenY): TScreenY;
begin
  CountYOnScreenLine := Y1 + (Y2 - Y1)* (X - X1) div (X2 - X1) ;
end;

procedure CreateSpectrumForm(const Name: string; AMode: TOpenMode);
var
  sf:TSpectrumForm;
  fn:string;
  i:integer;
  fcreated: boolean;
begin
  if SpectrumFormCount = MaxSpectrumFormCount then
    exit;
  if Name = '' then begin
    AMode := omCreate;
    i := StrToInt(copy(CurPortName, 4, 2));
    {repeat}
      fn := 'NONAME' + IntToStr(i) + ULFExt;
    {inc(i);
    until (not FileExists(fn)) or (i > 100);}
  end else begin
    fn := Name;
    AMode := omRead;
  end;
  if OverlayMode and (AMode = omRead) then begin
    sf := nil;
    if (MainForm.ActiveMDIChild <> nil) and
       (MainForm.ActiveMDIChild is TSpectrumForm) then
    begin
      sf := TSpectrumForm(MainForm.ActiveMDIChild);
    end;
    if sf = nil then begin
      sf := TSpectrumForm.Create(Application);
      fcreated := true;
    end else begin
      fcreated := false;
    end;
    try
      if fcreated then
        sf.SetDataFile(fn, AMode)
      else
        sf.AddDataFile(fn);
    except
      if fcreated then
        sf.Free;
    end;
  end else begin
    sf := TSpectrumForm.Create(Application);
    try
      sf.SetDataFile(fn, AMode);
    except
      sf.Free;
    end;
  end;
{  sf.Show;}
end;

procedure TSpectrumForm.FormCreate(Sender: TObject);
var
  li:TListInfo;
  i: integer;
begin
  {set def values}
  AngleText := TAngleText.Create(90);
  DataList := TList.Create;
  DeviceMode := CurDeviceMode;
  PortName:= CurPortName;
  UVDetAddr:= DefUVDetAddr;
  ChangingView := false;
  UserLimitStack := nil;
  FDefineMode := dmNone;
  {FDefiningBaseLine := false;
  FDefiningMargins := false;}

  MarginML := TMouseLine.Create(PaintBox.Canvas);
  MarginML.Mode := mmRectangle;
  PeakML := TMouseLine.Create(PaintBox.Canvas);
  PeakML.Mode := mmVerticalColumn;
  BaseLineML := TMouseLine.Create(PaintBox.Canvas);
  BaseLineML.Mode := mmVerticalColumn;
  {PeakML.ObjType := omVerticalColumn;
  PeakML.ObjPos :=}
  {MarginStartPoint.X := -1;}
  {ReportPanelDragStart.X := -1;}
  PeakDefineMode := pdNone;
  BaseLineDefineMode := pdNone;
  ReportFrm := nil;
  Data := nil;
  Spect := nil;
  OutDisp := @ScreenDisp;
  FillChar(ScrBuf, sizeof(ScrBuf), 0);
  {DrawPos := 0;}
  for i := 0 to MaxDataCountInForm - 1 do begin
    ScrBuf[i].LastRec.X := -1;
  end;

  DrawLocked := 0;
  DrawWanted := false;
  {BaseLineDragStart :=-1;}
  {BaseLinePos := 0;}
  PeakStartPoint.X := -1;{indicates that no peak was manually started}
  BaseLineStartPoint.X := -1;
  IsInTimer := false;
  IsInReceive := false;
  IsInPaint := false;
  ZeroTime := mstime;
  ZeroValue := 0;{55;}
  RunningState := rsStopped;
  AxisPlotting := nil;
  CommPort := nil;
  LogPackets := true;
  {v1.05}
  UserViewLimit := CurUserViewLimit;{ulanglob}
  {/v1.05
  UserViewLimit.Min.X := 0;
  UserViewLimit.Max.X := 20;
  UserViewLimit.Min.Y := -0.1;
  UserViewLimit.Max.Y := 0.1;  }

  OrigUserViewLimit := UserViewLimit;
  ViewLimit.Min.X := 0;
  ViewLimit.Max.X := 1200;
  ViewLimit.Min.Y := -2;
  ViewLimit.Max.Y := 2;
  Limit.Min.X := 0;
  Limit.Max.X := 1200;
  Limit.Min.Y := -2;
  Limit.Max.Y := 2;

  {/set def values}
  DefineBaseLineSpeedButton.Tag := longint(dmBaseLine);
  DefinePeaksSpeedButton.Tag := longint(dmPeaks);
  DefineMarginsSpeedButton.Tag := longint(dmMargins);

  CommPort := TComm.Create(Self);
  PortSetDefaults;

  MainForm.ComPort := CommPort;
  { just for debugging }


  {AxisItem.Checked := true;}
{  PostMessage(Handle, WM_APPMESSAGE, cmSpectrumObjectShow + soAxis,
    longint(true));
  PostMessage(Handle, WM_APPMESSAGE, cmSpectrumObjectShow + soBaseLine,
    longint(true));
}
  ReadFromIniFile;
  DeviceModeCheck(DeviceMode);
  FillChar(li, sizeof(li), 0);
  case DeviceMode of
    dmUlan: begin
      li.RecordSize := sizeof(TApexPacketInfo);
    end;
    dmApex: li.RecordSize := sizeof(TApexPacketInfo);
    dmGHLab: li.RecordSize := sizeof(TGHLabPacketInfo);
  else
    raise Exception.Create('Invalid DeviceMode');
  end;
  li.Capacity := 100;
  if not ListInit(ltRecords or ltAutoDestroy, @li, PacketFifo) then
    raise Exception.Create('SpecForm ListInit PacketFifo failed.');
  UpdateViewLimit;
  ResetPacketInfo;
  inc(SpectrumFormCount);
  UpdateScreenDisp;
  SetPacketLogging(false);
  LogMenuItem.Visible := DebugToolsAllowed;{globals}
  Stop;
end;

procedure TSpectrumForm.UpdateViewLimit;
var
  ind, cnt: integer;
begin
  UserViewRecToExpViewRec(UserViewLimit, ViewLimit);
  if Data <> nil then begin
    ind := 0;
    cnt := DataList.Count;
    repeat
      if cnt > 1 then begin
        DataSetCurrent(ind);
      end;
      Data.SetViewLimit(ViewLimit);
      {Data.SetUserLimit(UserViewLimit);}
      Data.SetLimit(Limit);
      {CountBaseLinePos;}
      inc(ind);
    until (ind >= cnt);
    SetToRedraw(trAll);
    Redraw;
  end;
end;

procedure TSpectrumForm.UpdateScreenDisp;
var tw,th:integer;
begin
  tw := Paintbox.Canvas.TextWidth('M');
  th := PaintBox.Canvas.TextHeight('M');
  ScreenDisp.Height := PaintBox.Height - 4 * th;
  ScreenDisp.Width := PaintBox.Width - 8 * tw;
  ScreenDisp.Left := 7 * tw;
  ScreenDisp.Top := 2 * th;
  PeakML.SetLimits(ScreenDisp.Left, ScreenDisp.Top, ScreenDisp.Width, ScreenDisp.Height);
  MarginML.SetLimits(ScreenDisp.Left, ScreenDisp.Top, ScreenDisp.Width, ScreenDisp.Height);
  if Data <> nil then begin
    {CountBaseLinePos;}
    SetToRedraw(trAll);
    Redraw;
  end;
end;

procedure TSpectrumForm.ReadFromIniFile;
begin
{  ConfigReadWriteValue(rwRead, SpecSection, 'DevMode', @DeviceMode, ptByte);
  ConfigReadWriteValue(rwRead, SpecSection, 'UVDetAddr', @UVDetAddr, ptLongint);}
end;

procedure TSpectrumForm.WriteToIniFile;
begin
{  ConfigReadWriteValue(rwWrite, SpecSection, 'DevMode', @DeviceMode, ptByte);
  ConfigReadWriteValue(rwWrite, SpecSection, 'UVDetAddr', @UVDetAddr, ptLongint);}
end;

procedure TSpectrumForm.UpdateViewOptionsFromDataFile;
begin
  SpectrumObjectShow(soAxis, Data.ULVO.ShowAxis);
  SpectrumObjectShow(soBaseline, Data.ULVO.ShowBaseLine);
  SpectrumObjectShow(soData, Data.ULVO.ShowData);
  SpectrumObjectShow(soHeader, Data.ULVO.ShowHeader);
  SpectrumObjectShow(soPeaks, Data.ULVO.ShowPeaks);
  SpectrumObjectShow(soReport, Data.ULVO.ShowReport);
  SpectrumObjectShow(soXY, Data.ULVO.ShowXY);
end;

procedure TSpectrumForm.UpdateViewLimitRecFromDataFile(force: boolean);
var
  dy: TYValue;
  dx: TXValue;
begin
  if Data.Mode = omRead then begin
    if Data.ULVL.FixedView or force then begin
      with UserViewLimit do begin
        Min.X := Data.ULVL.MinX;
        Min.Y := Data.ULVL.MinY;
        Max.X := Data.ULVL.MaxX;
        Max.Y := Data.ULVL.MaxY;
      end;
    end else begin
      with UserViewLimit do begin
        Data.ExpToUser(Data.SpectrumOpt.Extreme.Max, Max);
        Data.ExpToUser(Data.SpectrumOpt.Extreme.Min, Min);
        dy := Max.Y - Min.Y;
        dx := Max.X - Min.X;
        Max.Y := Min.Y + (dy / 100) * 120;
        Min.Y := Min.Y - (dy / 100) * 10;
        Max.X := Max.X + (dx / 100) * 5;
      end;
    end;
  end else begin
    UserViewLimit := NewUserViewLimit;
  end;
end;

procedure TSpectrumForm.UpdateViewLimitRecToDataFile(force:boolean);
begin
  if Data.ULVL.FixedView or force then begin
    with UserViewLimit do begin
      Data.ULVL.MinX := Min.X;
      Data.ULVL.MinY := Min.Y;
      Data.ULVL.MaxX := Max.X;
      Data.ULVL.MaxY := Max.Y;
    end;
  end;
end;

procedure TSpectrumForm.SetDataFile(const AFileName:string; AMode: TOpenMode);
begin
  {if AMode = omCreate then begin
    if not FExists(AFileName) then
      CreateFile(AFileName);
  end;}
  DataListClear;
  Data := TAcqData.Create(AFileName, AMode);
  DataList.Add(Data);
  DataIndex := DataList.IndexOf(Data);

  Spect.Free;
  Spect := TSpectrum.Create(Data);

  UpdateViewLimitRecFromDataFile(false);
  UpdateViewOptionsFromDataFile;
  
  LockDraw;
  UpdateScreenDisp;
  UpdateViewLimit;
  UpdateCaption;
  UnlockDraw;
end;

procedure TSpectrumForm.AddDataFile(const AFileName:string);
begin
  Data := TAcqData.Create(AFileName, omRead);
  DataList.Add(Data);
  DataIndex := DataList.IndexOf(Data);
  Spect.SetData(Data);

  LockDraw;
  UpdateScreenDisp;
  UpdateViewLimit;
  UpdateCaption;
  UnlockDraw;
end;

procedure TSpectrumForm.UserViewRecToExpViewRec(const AUserViewLimit:TUserViewLimit;
      var AViewLimit:TExpViewLimit);
begin
  AViewLimit.Min.X := round(AUserViewLimit.Min.X * 60);
  AViewLimit.Max.X := round(AUserViewLimit.Max.X * 60);
  if AViewLimit.Max.X = AViewLimit.Min.X then
    AViewLimit.Max.X := AViewLimit.Min.X + 0.001;
  AViewLimit.Min.Y := {round(}UserViewLimit.Min.Y {* YConst)};
  AViewLimit.Max.Y := {round(}UserViewLimit.Max.Y {* YConst)};
  if AViewLimit.Max.Y = AViewLimit.Min.Y then
    AViewLimit.Max.Y := AViewLimit.Min.Y + 0.0001;
end;

procedure TSpectrumForm.DoApexChar(CommChar:char);

  procedure HandlePacket(var ApexPktInfo:TApexPacketInfo);
  begin
    case ApexPktInfo.Pkt.Data[ApexEventIDPos] of {apextype}
      eiMark: begin
        if RunningState =  rsReadyToRun then
          Run;
      end;
      eiData: begin
        if RunningState = rsRunning then
          ListRecAdd(PacketFifo, ApexPktInfo);
      end;
    else
      begin
      end;
    end;
  end;

begin
  with ApexPktInfo do begin
    if (CurPos < 4) and (CommChar <> #0) then begin
      CurPos := 0;
      EndTime := mstime;
    end else begin
      Pkt.Data[CurPos] := ord(CommChar);
      if CurPos = 0 then
        Time := EndTime;
      inc(CurPos);
      if CurPos = ApexPacketSize{sizeof(TApexPacket)} then begin
        CurPos := 0;
        {ApexPktInfo.}EndTime := mstime;
        if {ApexPktInfo.}Pkt.Data[ApexEventIDPos] <> eiData then begin
          {ApexPktInfo.}CurPos := 0;{just for breakpoints}
        end;
        HandlePacket(ApexPktInfo);
      end;
    end;
  end;
end;


procedure TSpectrumForm.DoGHLabChar(CommChar:char);

  procedure HandlePacket(var gi:TGHLabPacketInfo);
  begin
  end;
var
  b:byte absolute CommChar;
begin
  with GHLabPktInfo do begin {apextype}
    if (b and  $80) <> 0 then begin
      CurVal := word(b and $70) shl 3
    end else begin
      CurVal := CurVal or b;
      if CurPos = 0 then
        Time := EndTime;
      Pkt[CurPos] := CurVal;
      inc(CurPos);
      if CurPos = GHLabPacketValueCount then begin
        CurPos := 0;
        EndTime := mstime;
        if RunningState = rsRunning then
          ListRecAdd(PacketFifo, GHLabPktInfo);
      end;
    end;
  end;
end;

procedure TSpectrumForm.DoInChar(CommChar:char);
begin
  case DeviceMode of
    dmApex: DoApexChar(CommChar);
    {dmUlan: DoUlanChar(CommChar);}
    dmGHLab: DoGHLabChar(CommChar);
  end;
end;

procedure TSpectrumForm.ComPortReceive(Sender: TObject
  {$IFDEF WIN32}
  ;Count: Integer
  {$ELSE}
  ;Count: Word
  {$ENDIF}
);
var
  CommChar:Char;
  i:Word;
  b:word;

begin
  if RunningState = rsStopped then
    exit;
  if IsInReceive then
    exit;
  if Count = 0 then
    exit;
  try
    IsInReceive := true;
    repeat
      if Count <= sizeof(RcvBuf) then begin
        b := Count;
      end else begin
        b := sizeof(RcvBuf);
      end;
      dec(Count, b);
      CommPort.Read(RcvBuf, b);
      for i := 0 to b - 1 do begin
        CommChar := RcvBuf[i];
        {CommPort.Read(@CommChar,SizeOf(CommChar));}
       {PostMessage(Memo1.Handle,WM_CHAR,Word(CommChar),0);}
        DoInChar(CommChar);
      end;
    until Count = 0;
  finally
    IsInReceive := false;
  end;
end;


procedure TSpectrumForm.Timer1Timer(Sender: TObject);
var
  ai:TApexPacketInfo;
  gi:TGHLabPacketInfo;
begin
  if RunningState = rsStopped then
    exit;
  if IsInTimer then
    exit;
  IsInTimer := true;
  try
    if PacketFifo <> nil then begin

      case DeviceMode of
        dmApex: begin
          while ListRecGet(PacketFifo, ai) do begin
            DoApexPacket(ai);
          end;
        end;

        dmUlan: begin
          if SII <> nil then begin
            RcvRun(SII);
            while RcvGetPktInfo(SII, ai) do begin
              case ai.Pkt.Data[ApexEventIDPos] of
                eiMark: begin
                  if RunningState =  rsReadyToRun then
                    Run;
                end;
              else
                DoApexPacket(ai);
              end;
            end;
          end;
        end;

        dmGHLab: begin
          while ListRecGet(PacketFifo, gi) do begin
            DoGHLabPacket(gi);
          end;
        end;
      else
        raise Exception.Create('Invalid DeviceMode');
      end;
    end;
  finally
    IsInTimer := false;
  end;
end;

procedure TSpectrumForm.DoApexPacket(var ai:TApexPacketInfo);
var
  dr:TExpPoint;sr:TScreenPoint;
  var i:integer;
  values:PApexValues;

  function MakeLogLine(var ai:TApexPacketInfo):string;
  var
    s:string;
    l:single;
    b:array[0..3]of byte absolute l;

  begin
    s := '';{binhex}
    s := RecToHex(ai.Pkt.Data[ApexSourceIDPos], 3) + ' ' +
      RecToHex(ai.Pkt.Data[ApexFootPos], 3) + ' ' +
      RecToHex(ai.pkt.Data[ApexValuesPos], 4) + ' ';
    {l := ai.pkt.Values[0];
    {
    s := s + itos(l, 12) + ' w:' + itos(LongRec(l).lo, 5) +
      ' ' + itos(LongRec(l).hi, 5) + ' b:' + itos(b[0],3) + ' ' +
        itos(b[1],5) + ' ' +itos(b[2],5) + ' '+ itos(b[3],5) + ' ';
     }
     s := s + bin(b[0]) + ' ' + bin(b[1]) + ' ' +bin(b[2])+ ' ' +bin(b[3]);
    MakeLogLine := s;
  end;

begin
  if LogPackets then begin
    SpectrumMemo.Lines.Add(MakeLogLine(ai));
  end;
  if Data <> nil then begin
    if not ai.ScanningValues then
      values := @ai.Pkt.Data[ApexValuesPos]
    else
      values := @ai.Pkt.Values;
    for i := 0 to ApexPacketValueCount - 1 do begin
      dr.X := ai.Time + round((ai.EndTime - ai.Time)/ ApexPacketValueCount * i) - ZeroTime;
      dr.X := dr.X / 1000;
      dr.Y := (values^[i]) - ZeroValue;
      Data.AddPoint(dr);
      if ScrBuf[DataIndex].Points <> nil then begin
        if (dr.X >= ViewLimit.Min.X) and (dr.X <= ViewLimit.Max.X) then
        begin
          Data.ExpToScreen(dr, OutDisp^, sr);
          ScrBuf[DataIndex].Points.AddPoint(sr.x,sr.y);
        end;
      end;
    end;
  end;
  DrawPoints(PaintBox.Canvas);
end;

procedure TSpectrumForm.DoGHLabPacket(var gi:TGHLabPacketInfo);
var
  dr:TExpPoint;
  sr:TScreenPoint;
  var i:integer;

  function MakeLogLine(var gi:TGHLabPacketInfo):string;
  var
    s:string;
    {i:integer;}
    l:single;
    b:array[0..3]of byte absolute l;
  begin
    s := IntToStr(gi.Pkt[0]);
    {s := RecToHex(ai.Pkt.Data[ApexSourceIDPos], 3) + ' ' +
      RecToHex(ai.Pkt.Data[ApexFootPos], 3) + ' ' +
      RecToHex(ai.pkt.Data[ApexValuesPos], 4) + ' ';
     s := s + bin(b[0]) + ' ' + bin(b[1]) + ' ' +bin(b[2])+ ' ' +bin(b[3]);}
    MakeLogLine := s;
  end;

begin
  if LogPackets then begin
    SpectrumMemo.Lines.Add(MakeLogLine(gi));
  end;
  if Data <> nil then begin
    for i := 0 to GHLabPacketValueCount - 1 do begin
      dr.X := gi.Time + round((gi.EndTime - gi.Time){1000 }/ GHLabPacketValueCount * i) - ZeroTime;
      dr.Y := 2 * (gi.Pkt[i]) / 1024 - ZeroValue;
      Data.AddPoint(dr);{Data.Write(dr, sizeof(dr));}
      if ScrBuf[DataIndex].Points <> nil then begin
        if (dr.X >= ViewLimit.Min.X) and (dr.X <= ViewLimit.Max.X) then
        begin
          Data.ExpToScreen(dr, OutDisp^, sr);
          ScrBuf[DataIndex].Points.AddPoint(sr.x,sr.y);
        end;
      end;
    end;
  end;
  DrawPoints(PaintBox.Canvas);
end;

procedure TSpectrumForm.PaintBoxPaint(Sender: TObject);
begin
  if Printing then
    exit;
  if IsInPaint then
    exit;
  if DrawLocked > 0 then
    exit;
  if Data = nil then
    exit;
  IsInPaint := true;
  try
    {DrawPos := 0;
    LastScreenRec.X := -1;}
    if  SpectrumObjectVisible(soData) then
      DrawPoints(PaintBox.Canvas);
    if SpectrumObjectVisible(soAxis) then
      DrawAxis(PaintBox.Canvas);
    if SpectrumObjectVisible(soPeaks) then
      DrawPeaks(PaintBox.Canvas);
    if SpectrumObjectVisible(soBaseLine) then
      DrawBaseLine(PaintBox.Canvas);
    if SpectrumObjectVisible(soHeader) then
      DrawHeader(PaintBox.Canvas);
  finally
    DrawWanted := false;
    IsInPaint := false;
  end;
end;

function TSpectrumForm.ApexRecToScreenRec(const AApexRec:TExpPoint;
  var AScreenRec:TScreenPoint):boolean;
{$IFDEF DEBUG}
{var ap:TExpPoint;}
{$ENDIF}
begin
  ApexRecToScreenRec := false;
  if Data = nil then
    exit;
  if Data.ExpToScreen(AApexRec, OutDisp^, AScreenRec) <> 0 then
    exit;
  {$IFDEF DEBUG}
  {Data.ScreenToApex(AScreenRec, ap);
  if AApexRec.X <> ap.X then begin
    DebugFormLog('SpecForm.ApexRecToScreenRec dif: X=' +
      IntToStr(AApexRec.X) + 'x' + IntToStr(ap.X));
  end;}
  {$ENDIF}
  ApexRecToScreenRec := true;
end;

function TSpectrumForm.ScreenPointToIndexPoint(const AScreenPoint:TPoint;
      var AIndexPoint:TIndexPoint):boolean;
var ap:TExpPoint; {index:longint;}
begin
  ScreenPointToIndexPoint := false;
  if Data = nil then
    exit;
  if not Data.ScreenToExp(TScreenPoint(AScreenPoint), OutDisp^, ap) then
    exit;
  if not Data.FindDataPoint(ap, AIndexPoint.Point, AIndexPoint.Index) then
    exit;
  ScreenPointToIndexPoint := true;
end;

procedure TSpectrumForm.DataSetCurrent(Index: integer);
begin
  Data := TAcqData(DataList.Items[Index]);
  DataIndex := Index;
  Spect.SetData(Data);
end;

procedure TSpectrumForm.DrawPoints(ACanvas: TCanvas);

var
  ind, cnt: integer;
  ar:TExpPoint;
  sr:TScreenPoint;
  {ss:longint;}

  r: TRect;
  bc: TColor;

begin
  ind := 0;
  cnt := DataList.Count;
  with ACanvas do begin
    r.Left := OutDisp^.Left;
    r.Top := OutDisp^.Top;
    r.Right := OutDisp^.Left + OutDisp^.Width;
    r.Bottom := OutDisp^.Top + OutDisp^.Height;
    bc := Brush.Color;
    Brush.Color := clWhite;
    FillRect(r);
    Brush.Color := bc;
  end;

  repeat
    if cnt > 1 then begin
      DataSetCurrent(ind);
    end;
    with ACanvas do begin
      if ScrBuf[DataIndex].Points = nil then begin
        if ScrBuf[DataIndex].DrawPos = 0 then begin
          ScrBuf[DataIndex].Points := TScreenPoints.Create;
        end;
        if Data <> nil then begin
          {ss := Data.GetSize;}
          {v1.05}
          Data.SeekPoint(ScrBuf[DataIndex].DrawPos);
          {/v1.05 Data.Seek(DrawPos);}
          {i := 0;}
          if ScrBuf[DataIndex].LastRec.X > 0 then begin
            MoveTo(ScrBuf[DataIndex].LastRec.X, ScrBuf[DataIndex].LastRec.Y);
            {inc(i);}
          end;
          repeat
            if Data.ReadPoint(ar) then begin
              {v1.05}
              inc(ScrBuf[DataIndex].DrawPos);
              {/v1.05
              inc(DrawPos, sizeof(ar));}

              if  ar.x > ViewLimit.Max.X then
                break;
              if (ar.x >= ViewLimit.Min.X) then begin
                if ApexRecToScreenRec(ar, sr) then begin
                  if (ScrBuf[DataIndex].LastRec.X <> sr.x) or
                    (ScrBuf[DataIndex].LastRec.y <> sr.y) then
                  begin
                    {v1.05}{/v1.05
                    if i = 0 then begin
                      Canvas.MoveTo(sr.X, sr.Y)
                    end else begin
                      Canvas.LineTo(sr.X, sr.Y);
                    end;}
                    if ScrBuf[DataIndex].Points <> nil then
                      ScrBuf[DataIndex].Points.AddPoint(sr.X, sr.Y);
                    ScrBuf[DataIndex].LastRec := sr;
                  end;
                end;
                {inc(i);}
              end;
            end else begin
              Data.Reset;
              break;
            end;
          until false;
          {v1.05}
          ScrBuf[DataIndex].DrawPos := Data.GetPointCount;
          {/v1.05
          DrawPos := Data.GetSize;}
          {v1.05}DrawScreenPoints(ACanvas);{/v1.05}
        end;
      end else begin
        DrawScreenPoints(ACanvas);
      end;
    end;

    inc(ind);
  until ind >= cnt;
end;

procedure TSpectrumForm.DrawScreenPoints(ACanvas: TCanvas);{draw the points from buffer}
var
  i: integer;
  spi: TScreenPointInfo;
  pc: TColor;
begin
  if (ScrBuf[DataIndex].Points = nil) or (ScrBuf[DataIndex].Points.Count = 0) then
    exit;
  with ACanvas do begin
    {
    r.Left := OutDisp^.Left;
    r.Top := OutDisp^.Top;
    r.Right := OutDisp^.Left + OutDisp^.Width;
    r.Bottom := OutDisp^.Top + OutDisp^.Height;
    bc := Canvas.Brush.Color;
    Canvas.Brush.Color := clWhite;
    PaintBox.Canvas.FillRect(r);
    Canvas.Brush.Color := bc; textout logbrush logpen
    }
    pc := Pen.Color;
    Pen.Color := clBlue;
    for i := 0 to ScrBuf[DataIndex].Points.Count - 1 do begin
      spi := TScreenPointInfo(ScrBuf[DataIndex].Points.Items[i]);
      if i = 0 then begin
        MoveTo(spi.X, spi.Y1);
      end else begin
        LineTo(spi.X, spi.Y1);
      end;
      if spi.Y1 <> spi.Y2 then
        LineTo(spi.X, spi.Y2);
    end;
    Pen.Color := pc;
  end;
end;

procedure TSpectrumForm.LockDraw;
begin
  inc(DrawLocked);
end;

procedure TSpectrumForm.UnlockDraw;
begin
  if DrawLocked = 0 then begin
    ShowMessage('Uneven UnlockDraw',smError,0);
    exit;
  end;
  dec(DrawLocked);
  if (DrawLocked = 0) and DrawWanted then
    Redraw;
end;

procedure TSpectrumForm.PlottingToCanvas(var APlot:TPlotting; ACanvas:TCanvas);
var pr:TPlotRecord;{plotu}
begin
  APlot.Reset;
  while APlot.Read(pr) do begin
    case pr.pc of
      pcMoveTo: ACanvas.MoveTo(pr.X, pr.Y);
      pcLineTo: ACanvas.LineTo(pr.X, pr.Y);
      pcTextOut: ACanvas.TextOut(pr.X, pr.Y, GetString(PString(pr.Info)));
    end;
  end;
end;

procedure TSpectrumForm.DrawAxis(ACanvas: TCanvas);
begin
  if Data = nil then
    exit;

  if AxisPlotting = nil then begin
    AxisPlotting := TPlotting.Create(ACanvas, 100);{plotu}
    if AxisPlotting = nil then
      exit;
    {AxisPlotting.SetCharWidth(ACanvas.TextWidth('M'));
    AxisPlotting.SetCharHeight(ACanvas.TextHeight('M'));}
  end else
    AxisPlotting.Canvas := ACanvas;

  if CreateAxisPlotting(Data, UserViewLimit, OutDisp^, AxisPlotting) then begin
    PlottingToCanvas(AxisPlotting, ACanvas);
  end;
end;

procedure TSpectrumForm.DrawBaseLine(ACanvas: TCanvas);
var
  b: TULBRObj;
  c, i: integer;
  e1, e2: TExpPoint;
  s1, s2: TScreenPoint;
  os1, os2: integer;
  lineOn: boolean;

  ps: TPenStyle;
  pm: TPenMode;
{  co: TColor;}
  ind, cnt: integer;
begin
  with ACanvas do begin
    c := Data.ULB.ChildCount;
    if c = 0 then
      exit;
    ps := Pen.Style;
    pm := Pen.Mode;

    Pen.Mode := pmCopy;{pmNotXor;}
    {Pen.Style := psDot;}
    cnt := DataList.Count;
    ind := 0;
    repeat
      if cnt > 1 then
        DataSetCurrent(ind);
      for i := 0 to c - 1 do begin
        b := TULBRObj(Data.ULB.Childs[i]);
        e1.x := b.X1;
        e1.y := b.Y1;
        e2.x := b.X2;
        e2.y := b.Y2;
        os1 := Data.ExpToScreen(e1, OutDisp^, s1);
        os2 := Data.ExpToScreen(e2, OutDisp^, s2);
        lineOn := false;
        if (os1 = 0) then begin
          Ellipse(s1.x - BaseLineCircleRadius, s1.y - BaseLineCircleRadius,
            s1.x + BaseLineCircleRadius, s1.y + BaseLineCircleRadius);
          lineOn := true;
        end else begin
          if ((os1 and opLeft) <> 0) and
             ((os2 = 0) or ((os2 and opRight) <> 0)) then
          begin
            s1.Y := CountYOnScreenLine(OutDisp^.Left, s1.X, s1.Y, s2.X, s2.Y);
            s1.X := OutDisp^.Left;
            lineOn := true;
          end;
        end;

        if (os2 = 0) then begin
          Ellipse(s2.x - BaseLineCircleRadius, s2.y - BaseLineCircleRadius,
            s2.x + BaseLineCircleRadius, s2.y + BaseLineCircleRadius);
          lineOn := true;
        end else begin
          if lineOn then begin
            s2.Y := CountYOnScreenLine(OutDisp^.Left + OutDisp^.Width, s1.X, s1.Y,
              s2.X, s2.Y);
            s2.X := OutDisp^.Left + OutDisp^.Width;
          end;
        end;

        if lineOn then begin
          Pen.Style := psDot;
          MoveTo(s1.x, s1.y);
          LineTo(s2.x, s2.y);
        end;
      end;
      inc(ind);
    until (ind >= cnt);
    Pen.Style := ps;
    Pen.Mode := pm;
  end;
end;

procedure TSpectrumForm.DrawPeaks(ACanvas: TCanvas);
var
  i: integer;
  p: TULPRObj;{PPeak;}
  sp1, sp2, sp3: TScreenPoint;
  sb1, sb2: TScreenPoint;
  p1, p2, p3, b1, b2: TExpPoint;
  u: TUserPoint;
  ind, cnt:integer;
  bc, pc: TColor;
  pm: TPenMode;
  curColor: TColor;
  {bs: TBrushStyle;
  r: TRect;}
  s: string;
begin
  if (Data = nil) then
    exit;
  ind := 0;
  cnt := DataList.Count;

  bc := ACanvas.Brush.Color;
  pm := ACanvas.Pen.Mode;
  pc := ACanvas.Pen.Color;

  try
    with ACanvas do begin
      Brush.Color := clWhite;
      Pen.Mode := pmCopy;
      repeat
        if cnt > 1 then
          DataSetCurrent(ind);
        for i := 0 to Spect.Peaks.ChildCount - 1 do begin
          p := TULPRObj(Spect.Peaks.Childs[i]);
          p1.x := p.X1;
          p1.y := p.Y1;
          p2.x := p.X2;
          p2.y := p.Y2;
          p3.x := p.X;
          p3.y := p.Height;
          b1.x := p.X1;
          b1.y := p.BaseY1;
          b2.x := p.X2;
          b2.y := p.BaseY2;

          if p.IsFlagSet(rfSelected) then begin
            curColor := clRed;
          end else begin
            curColor := clBlack;
          end;
          Pen.Color := curColor;

          if ApexRecToScreenRec(p1, sp1) then begin
            if not ApexRecToScreenRec(b1, sb1) then begin
            end;
            MoveTo(sp1.X, sp1.Y - PeakStickLen);
            LineTo(sp1.X, sb1.Y + PeakStickLen);
            LineTo(sp1.X + PeakArrowLen, sb1.Y + PeakStickLen);
            LineTo(sp1.X + PeakArrowLen div 2, sb1.Y + PeakStickLen - PeakStickLen div 4);
            MoveTo(sp1.X + PeakArrowLen, sb1.Y + PeakStickLen);
            LineTo(sp1.X + PeakArrowLen div 2, sb1.Y + PeakStickLen + PeakStickLen div 4 + 1);
          end;

          if ApexRecToScreenRec(p2, sp2) then begin
            if not ApexRecToScreenRec(b2, sb2) then begin
            end;
            MoveTo(sp2.X, sp2.Y - PeakStickLen);
            LineTo(sp2.X, sb2.Y + PeakStickLen);
            LineTo(sp2.X - PeakArrowLen, sb2.Y + PeakStickLen);
            LineTo(sp2.X - PeakArrowLen div 2, sb2.Y + PeakStickLen - PeakStickLen div 4);
            MoveTo(sp2.X - PeakArrowLen, sb2.Y + PeakStickLen);
            LineTo(sp2.X - PeakArrowLen div 2, sb2.Y + PeakStickLen + PeakStickLen div 4 + 1);
          end;

          if ApexRecToScreenRec(p3, sp3) then begin
            Data.ExpToUser(p3, u);
            s := p.PeakName + ' ' + FloatToRoundStr(u.X, 3, 0); {+ ret.time}
            AngleText.TextOut(Printing, ACanvas, curColor,
              sp3.X - TextHeight(s) div 2, OutDisp^.Top + TextWidth('M') div 4 + TextWidth(s), s);
          end;

        end;
        inc(ind);
      until (ind >= cnt);
    end;{/with ACanvas}
  finally
    ACanvas.Brush.Color := bc;
    ACanvas.Pen.Mode := pm;
    ACanvas.Pen.Color := pc;
  end;
end;

procedure TSpectrumForm.Redraw;
begin
  DrawWanted := true;
  if DrawLocked > 0 then
    exit;
  Invalidate;
end;

procedure TSpectrumForm.FormDestroy(Sender: TObject);
begin
  {if (PeaksDefineForm <> nil) and (PeaksDefineForm.ConnectedForm = Self) then
  begin
  end;}
  MarginML.Free;
  PeakML.Free;
  if MainForm.ComPort = CommPort then
    MainForm.ComPort := nil;
{  Data.Free;}
  Spect.Free;
  ListDone(UserLimitStack);
  ListDone(PacketFifo);
  dec(SpectrumFormCount);
  DataListClear;
  CurUserViewLimit := UserViewLimit;
    { CurUserViewLimit will be saved to INI as default for new chromatograms }
  DataList.Free;
  AngleText.Free;
end;

procedure TSpectrumForm.DataListClear;
var i: integer;
begin
  for i := 0 to DataList.Count - 1 do begin
    Data := TAcqData(DataList.Items[i]);

    UpdateViewLimitRecToDataFile(true);
    ScrBuf[i].Points.Free;
    Data.Free;
  end;
  Data := nil;
end;

procedure TSpectrumForm.SetPacketLogging(onOff:boolean);
begin
  if OnOff then begin
    SpectrumMemo.Visible := true;
  end else begin
    SpectrumMemo.Visible := false;
  end;
  LogPackets := OnOff;
  SetToRedraw(trAll);
  Redraw;
end;

procedure TSpectrumForm.LogMenuItemClick(Sender: TObject);
begin
  LogMenuItem.Checked := not LogMenuItem.Checked;
  SetPacketLogging(LogMenuItem.Checked);
end;

procedure TSpectrumForm.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  Action := caFree;
  {ClosePeaksDefineForm;}
  if ReportFrm <> nil then
    PostMessage(ReportFrm.Handle, WM_APPMESSAGE,
      cmSpectrumFormClosed, longint(Self));
  Stop;
  WriteToIniFile;
  MainForm.ChromatogramButton.Enabled := false;
end;

procedure TSpectrumForm.MarginsItemClick(Sender: TObject);
begin
  Data.ULVL.Edit;
  {
  if ExecuteMarginsDialog(UserViewLimit) = mrOK then begin
    UpdateViewLimit;
    SetToRedraw(trAll);
    Redraw;
  end;
  }
end;

procedure TSpectrumForm.PopupMenuPopup(Sender: TObject);
begin
  if (Data <> nil) and (Data.Mode = omRead) then begin
    RunStopItem.Visible := false;
  end else begin
    RunStopItem.Visible := true;
    if RunningState <> rsStopped then
      RunStopItem.Caption := '&Stop'
    else
      RunStopItem.Caption := '&Run';
  end;
end;

procedure TSpectrumForm.RunStopItemClick(Sender: TObject);
begin
  if RunningState <> rsStopped then
    Stop
  else
    Run;
end;

procedure TSpectrumForm.RunPanelShow;
begin
  RunPanel.Left := (Width div 2) - (RunPanel.Width div 2);
  RunPanel.Top := (PaintBox.Height div 2) - (RunPanel.Height div 2);
  RunPanel.Show;

end;

procedure TSpectrumForm.PortSetDefaults;
begin
  {$IFDEF WIN32}
  {commint}
  with CommPort do begin
    AfterOpenState := aoSpecified;
    BaudRate := br9600;
    DataBits := da8;
    DeviceName := 'COM2';
    FlowControl := fcDefault;
    MonitorEvents := [evRxChar];
    Options := [];
    Parity := paSpace;
    ReadBufSize := 4096;
    ReadTimeout := 1000;
    StopBits := sb10;
    WriteBufSize := 2048;
    WriteTimeout := 1000;
  end;
  {$ELSE}
  {comm}
  with CommPort do begin
    BaudRate := tbr9600;
    DataBits := tdbEight;
    Parity := tpSpace;
    ReadBufferSize := 2048;
    Stopbits := tsbOne;
    TxLowCount := 1024;
    WriteBufferSize := 1024;
    Events := [tceRxChar];
  end;
  {$ENDIF}
end;

procedure TSpectrumForm.PortOpen;
begin
  case DeviceMode of
    dmUlan: begin
      RcvInit(SII, UVDetAddr);
    end;
  else
    {CommPort := MainForm.ComPort;}
    {$IFDEF WIN32}
    CommPort.OnRxChar := ComPortReceive;
    CommPort.DeviceName := PortName;{'COM' + IntToStr(ComPortNumber);}
    ReadWriteComConfig(rwRead, CommPort);
    case DeviceMode of
      dmGHLab: begin
        CommPort.DTROnOpen := esOn;
        CommPort.RTSOnOpen := esOff;
      end;
    end;
    if CommPort = MainForm.ComPort then
      MainForm.ComPort := nil;
    CommPort.Open;
    {$ELSE}
    CommPort.OnReceive := ComPortReceive;
    CommPort.Port := TPort(ComPortNumber);
    {$ENDIF}
  end;
end;

procedure TSpectrumForm.PortClose;
begin
  case DeviceMode of
    dmUlan: begin
      RcvDone(SII);
    end;
  else
    {$IFDEF WIN32}
    CommPort.Close;
    CommPort.OnRxChar := nil;
    ReadWriteComConfig(rwWrite, CommPort);
    if MainForm.ComPort = nil then
      MainForm.ComPort := CommPort;
    {$ELSE}
    CommPort.Port := tptNone;
    CommPort.OnReceive := nil;
    CommPort := nil;
    {$ENDIF}
  end;
end;

procedure TSpectrumForm.ResetPacketInfo;
begin
  FillChar(ApexPktInfo, sizeof(ApexPktInfo), 0);
  FillChar(GHLabPktInfo, sizeof(GHLabPktInfo), 0);
end;

procedure TSpectrumForm.Run;
begin
  if RunningState = rsStopped then begin
    if SendMessage({HWND_BROADCAST}MainForm.Handle, WM_APPMESSAGE, cmQueryRunning,
      longint(@PortName)) = 1 then
    begin
      ShowMsg.ShowMessage('Acquisition is already running', smError,0);
      exit;
    end;
    if (Data <> nil) and (Data.ULAD.Data.Size <> 0) then begin
      if ShowMessage('Discard already acquired data?', smNoYes, 0) <> cmYes then
        exit;
    end;
    ResetPacketInfo;
    PortOpen;
    RunningState := rsReadyToRun;
    RunPanelShow;
  end else begin
    ClearData;
    ResetPacketInfo;
    ZeroTime := mstime;
    ApexPktInfo.EndTime := ZeroTime;
    GHLabPktInfo.EndTime := ZeroTime;
    case DeviceMode of
      dmUlan: RcvSetProp(SII, rpZeroTime, @ZeroTime);
    end;
    RunningState := rsRunning;
    RunPanel.Hide;
  end;
  UpdateCaption;
end;

procedure TSpectrumForm.SetToRedraw(tr:TToRedraw);
var i: integer;
begin
  if (tr and trData) <> 0 then begin
    for i := 0 to DataList.Count - 1 do begin
      ScrBuf[i].DrawPos := 0;
      ScrBuf[i].LastRec.X := -1;
      ScrBuf[i].Points.Free;
      ScrBuf[i].Points := nil;
    end;
  end;
end;

procedure TSpectrumForm.ClearData;
begin
  if Data <> nil then begin
    Data.Clear;
    SetToRedraw(trData);
    Redraw;
  end;
end;

procedure TSpectrumForm.Stop;
begin
  if RunningState <> rsStopped then begin
    RunningState := rsStopped;
    PortClose;
    RunPanel.Hide;
  end;
  UpdateCaption;
end;

function TSpectrumForm.GetFileName;
begin
  if Data <> nil then
    GetFileName := Data.ULF.FileName
  else
    GetFileName := '';
end;

procedure TSpectrumForm.UpdateCaption;
begin
  if (Data <> nil) and (Data.Mode = omRead) then begin
    Caption := FileName;
  end else begin
    if RunningState = rsStopped then begin
      Caption := 'Stopped ' + FileName;
    end else if RunningState = rsReadyToRun then begin
      Caption := 'Waiting for mark ' + FileName;
    end else begin
      Caption := 'Running ' + FileName;
    end;
  end;
end;

procedure TSpectrumForm.FormResize(Sender: TObject);
begin
  UpdateScreenDisp;
end;

procedure TSpectrumForm.AxisItemClick(Sender: TObject);
begin
{  SpectrumObjectShow(soAxis, not AxisItem.Checked);}
end;

function TSpectrumForm.DoSaveTo:boolean;
var fn, ext: string;
begin
  if SaveDialog.Execute then begin
    fn := SaveDialog.FileName;
    ext := GetExtFromFileDialogFilter(SaveDialog.Filter, SaveDialog.FilterIndex);
      {winutl}
    fn := ReplaceExt(fn, ext, false);
    SaveTo(fn);
    DoSaveTo := true;
  end else begin
    DoSaveTo := false;
  end;
end;

procedure TSpectrumForm.SaveTo(AFileName:string);
begin
  if Data <> nil then begin
    Data.SaveTo(ReplaceExt(AFileName, UlfExt, false));
    UpdateCaption;
  end;
end;

procedure TSpectrumForm.WMAppMessage(var Msg:TMessage);
var x,y:integer;

  procedure ClipCopy;
  begin
    if ActiveControl = ReportMemo then begin
      ReportMemo.CopyToClipboard;
    end;
  end;

  procedure ClipPaste;
  begin
    if ActiveControl = ReportMemo then begin
      ReportMemo.PasteFromClipboard;
    end;
  end;

  procedure ClipCut;
  begin
    if ActiveControl = ReportMemo then begin
      ReportMemo.CutToClipboard;
    end;
  end;
type
  pshortstring = ^shortstring;

begin
  case Msg.WParam of
    cmQueryRunning:  begin
      if (RunningState <> rsStopped) and (pshortstring(Msg.LParam)^ = PortName) then begin
        Msg.Result := 1;
        exit;
      end;
    end;

    cmLocalMenu: begin
      x := Left + Width div 2;
      y := Top + Height div 4;
      PopupMenu.Popup(x, y);
    end;

    cmDefineModeSet: DefineMode := TDefineMode(Msg.LParam);
    {cmPeaksDefineStart: PeaksDefineStart;
    cmPeaksDefineStop: PeaksDefineStop;
    cmMarginsDefineStart: MarginsDefineStart;
    cmMarginsDefineStop: MarginsDefineStop;
    cmBaseLineDefineStart: BaseLineDefineStart;
    cmBaseLineDefineStop: BaseLineDefineStop;
    }
    cmClipCopy : ClipCopy;
    cmClipCut: ClipCut;
    cmClipPaste :ClipPaste;
    cmSpectrumObjectShow..cmSpectrumObjectShow + SpectrumObjectCount: begin
      SpectrumObjectShow(Msg.WParam - cmSpectrumObjectShow,
        boolean(Msg.LParam));
    end;
    {
    cmGHLabDataChanged : begin
      if pointer(Msg.LParam) = Channel then
        SetPoints(PChannel(Channel)^.Data);
    end;
    cmChannelStarted, cmChannelPaused,
    cmChannelResumed, cmChannelStopped: begin
    end;
    cmChannelOptionsChanged, cmSolventRecoverySet:begin
      if (pointer(Msg.LParam) = Channel) then
        UpdateRecoveryLevelShape;
    end;
{      UpdateChannelCommands(Msg.WParam, word(Msg.LParam));}
    cmULObjBeforeEdit: ULObjBeforeEdit(Msg);
    cmULObjAfterEdit: ULObjAfterEdit(Msg);
  end;
  inherited;
end;

procedure TSpectrumForm.ULObjBeforeEdit(var Msg: TMessage);
var o: TULObj;
begin
  o := TULObj(Msg.lParam);
  if o.RecID = ULVLID then begin
    UpdateViewLimitRecToDataFile(true);
    CurUserViewLimit := UserViewLimit;
  end;
end;

procedure TSpectrumForm.ULObjAfterEdit(var Msg: TMessage);
var o: TULObj;
begin
  o := TULObj(Msg.lParam);
  case o.RecID of
    ULVLID: begin
      UpdateViewLimitRecFromDataFile(true);
      UpdateViewLimit;
    end;
    ULPRID: begin
      SetToRedraw(trPeaks);
      Redraw;
    end;
    ULVOID: begin
      UpdateViewOptionsFromDataFile;
    end;
  end;
end;


procedure TSpectrumForm.FormActivate(Sender: TObject);
begin
  MainForm.ChromatogramButton.Enabled := true;
end;

procedure TSpectrumForm.FormDeactivate(Sender: TObject);
begin
  MainForm.ChromatogramButton.Enabled := false;
end;

procedure TSpectrumForm.PeaksClearMenuItemClick(Sender: TObject);
begin
  if (Spect <> nil) then begin
    Spect.Peaks.Clear;
    SetToRedraw(trPeaks);
    Redraw;
  end;
end;

procedure TSpectrumForm.PeaksShow;
begin
{  if not PeaksMenuItem.Checked then begin}
{    PeaksMenuItem.Checked := true;}
  Data.ULVO.ShowPeaks := true;
  PeaksCheckBox.Checked := true;
  SetToRedraw(trPeaks);
  Redraw;
{  end;}
end;

procedure TSpectrumForm.PeaksHide;
begin
{  if PeaksMenuItem.Checked then begin
    PeaksMenuItem.Checked := false;}
  Data.ULVO.ShowPeaks := false;
  PeaksCheckBox.Checked := false;
  if DefineMode = dmPeaks then
    DefineMode := dmNone;{PeaksDefineStop;}
  SetToRedraw(trPeaks);
  Redraw;
{  end;}
end;

procedure TSpectrumForm.PeaksDefineStart;
begin
  DefinePeaksSpeedButton.Down := true;
  PeaksDefineItem.Checked := true;
  PeakDefineMode := pdReady;
  PeaksShow;
end;

procedure TSpectrumForm.PeaksDefineStop;
begin
  DefinePeaksSpeedButton.Down := false;
  PeaksDefineItem.Checked := false;
  PeakDefineMode := pdNone;
end;

procedure TSpectrumForm.SetDefineMode(ADefineMode: TDefineMode);
begin
  PeaksDefineStop;
  BaseLineDefineStop;
  MarginsDefineStop;
  case ADefineMode of
    dmPeaks: PeaksDefineStart;
    dmBaseLine: BaseLineDefineStart;
    dmMargins: MarginsDefineStart;
  end;
  FDefineMode := ADefineMode;
end;

procedure TSpectrumForm.PaintBoxMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  p: TPoint;
  i: integer;
  editedProp: boolean;

  started:boolean;{some mouse action?}
begin
  if Button = mbLeft then begin
    started := false;

    case FDefineMode of

      dmPeaks: begin
        if IsInPeak(X, i) or (not StartCreatePeak(X, Y)) then
         exit;
        Screen.Cursor := crHSplit;
        started := true;
      end;


      dmBaseLine: begin
        if IsInBaseLine(X, i) or (not StartCreateBaseLine(X, Y)) then
          exit;
        started := true;
        {
        if IsInBaseLine(X, i) then begin
          if ssShift in Shift then begin
            if not StartMoveBaseLine(X) then
              exit;
          end else begin
            if not StartSizeBaseLine(X) then
              exit;
          end;
        end else begin
          if not StartCreateBaseLine(X, Y) then
            exit;
        end;
        }
      end;

      dmMargins: begin
        {end else if DefiningMargins then begin}
        MarginML.Start(X, Y);
        started := true;
      end;
    end;

    if not started then begin
      if IsInPeakEdge(X, Y, i) and StartSizePeak(X) then begin
        Screen.Cursor := crHSplit;
      end else if IsInBaseLineEdge(X,Y, i) and StartSizeBaseLine(X) then begin
        Screen.Cursor := crHSplit;
      end else if (Y < ScreenDisp.Top + PaintBox.Canvas.TextWidth('MMMMM'))
        and IsInPeak(X, i)
      then begin
        ToggleSelectPeak(X, Shift);
        PeakEditProperties(i);
      end;
    end;

  end else if Button = mbRight then begin

    editedProp := false;
    {
    case FDefineMode of
      dmPeaks: begin
        if IsInPeak(X, i) then begin
          PeakEditProperties(i);
          editedProp := true;
        end;
      end;
      dmBaseLine: begin
        if IsInBaseLine(X, i) then begin
          BaseLineEditProperties(i);
          editedProp := true;
        end;
      end;
    end;
    }
    if not editedProp then begin
      p.X := X;
      p.Y := Y;
      p := PaintBox.ClientToScreen(p);
      PopupMenu.Popup(p.X, p.Y);
    end;

  end;

end;

procedure TSpectrumForm.PaintBoxMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
   {if BaseLineDragStart >= 0 then begin
     Screen.Cursor := crVSplit;
     UndrawBaseLine;
     BaseLinePos := Y;
     DrawBaseLine;
   end else }
   case FDefineMode of

     dmMargins: begin
       if MarginML.IsOn then
         MarginML.Update(X, Y);
     end;

     dmPeaks: begin
       if PeakML.IsOn then
         PeakML.Update(X,Y);
     end;

     dmBaseLine: begin
       if BaseLineML.IsOn then
         BaseLineML.Update(X,Y);
     end;

   end;
   if SpectrumObjectVisible(soXY) then begin
     XYEdit.Text := IntToStr(X) + ',' + IntToStr(Y);
   end;
end;

procedure TSpectrumForm.PaintBoxMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  sp, ep: TPoint;
begin
  if PeakML.IsOn then begin
    FinishPeak(X, Y, Shift);
    Screen.Cursor := crDefault;
  end else if BaseLineML.IsOn then begin
    FinishBaseLine(X, Y);
    Screen.Cursor := crDefault;
  end else begin
    case FDefineMode of
      (*
      dmPeaks: begin
        if PeakML.IsOn then begin
          FinishPeak(X, Y, Shift);
          Screen.Cursor := crDefault;
        end;
      end;

      dmBaseLine: begin
        if BaseLineML.IsOn then begin
          FinishBaseLine(X, Y);
          Screen.Cursor := crDefault;
        end;
      end;
      *)
      dmMargins: begin
        if MarginML.IsOn then begin
          MarginML.Stop(X, Y);
          MarginML.GetResult(sp, ep);
          SetScreenSubView(sp.X, sp.Y, ep.X, ep.Y);
        end;
        if not DefineModePermanent then begin
          DefineMode := dmNone;
        end;
      end;

    end;
  end;
end;

procedure TSpectrumForm.SetScreenSubView(X1,Y1,X2,Y2:integer);
var sc1,{sc,}sc2:TScreenPoint;ap1,ap2:TExpPoint;
  up1,up2:TUserPoint;
  ou:TUserViewLimit;
  li:TListInfo;
begin
  sc1.X := X1;
  sc1.Y := Y1;
  sc2.X := X2;
  sc2.Y := Y2;
  ou:= UserViewLimit;
  if Data = nil then
    exit;
  if not Data.ScreenToExp(sc1, OutDisp^, ap1) then
    exit;
  if not Data.ScreenToExp(sc2, OutDisp^, ap2) then
    exit;
  if abs(ap1.x - ap2.x) <= 0.001 then
    exit;
  if abs(ap1.y - ap2.y) <= 0.0001 then
    exit;
  if not Data.ExpToUser(ap1, up1) then
    exit;
  if not Data.ExpToUser(ap2, up2) then
    exit;
  DebLog('SetScrSubView: ' + FloatToStr(ap1.x)
    + ',' + FloatToStr(ap1.y) + ' - ' +
    FloatToStr(ap2.x)
    + ',' + FloatToStr(ap2.y));
  if up1.X < up2.X then begin
    UserViewLimit.Min.X := up1.X;
    UserViewLimit.Max.X := up2.X;
  end else if up1.X > up2.X then begin
    UserViewLimit.Min.X := up2.X;
    UserViewLimit.Max.X := up1.X;
  end else
    exit;
  if up1.Y < up2.Y then begin
    UserViewLimit.Min.Y := up1.Y;
    UserViewLimit.Max.Y := up2.Y;
  end else if up1.Y > up2.Y then begin
    UserViewLimit.Min.Y := up2.Y;
    UserViewLimit.Max.Y := up1.Y;
  end else
    exit;
  if UserLimitStack = nil then begin
    FillChar(li, sizeof(li), 0);
    li.RecordSize := sizeof(TUserViewLimit);
    li.Capacity := 100;
    ListInit(ltRecords or ltAutoDestroy, @li, UserLimitStack);
  end;
  if UserLimitStack <> nil then
    ListRecAdd(UserLimitStack, ou);
  UpdateViewLimit;
end;

procedure TSpectrumForm.PopScreenSubView;
begin
  if UserLimitStack = nil then
    exit;
  if ListRecPop(UserLimitStack, UserViewLimit) then
    UpdateViewLimit;
end;

function TSpectrumForm.SpectrumObjectVisible(so:TSpectrumObject):boolean;
var r:boolean;
begin
  r := false;
  if Data <> nil then begin
  case so of
    soAxis: r := Data.ULVO.ShowAxis;
    soPeaks: r := Data.ULVO.ShowPeaks;
    soBaseLine: r := Data.ULVO.ShowBaseline;
    soXY: r := Data.ULVO.ShowXY;
    soHeader: r := Data.ULVO.ShowHeader;
    soReport: r := Data.ULVO.ShowReport;
    soData: r := Data.ULVO.ShowData;
  end;
  end;
  SpectrumObjectVisible := r;
end;

procedure TSpectrumForm.SpectrumObjectShow(so:TSpectrumObject; OnOff:boolean);
begin
  ChangingView := true;
  try
    case so of
      soData: begin
        Data.ULVO.ShowData := OnOff;
      end;
      soBaseLine: begin
        {BaseLineMenuItem.Checked := OnOff;}
        BaseLineCheckBox.Checked := OnOff;
        Data.ULVO.ShowBaseLine := OnOff;
        SetToRedraw(trBaseLine);
        Redraw;
      end;
      soAxis: begin
        Data.ULVO.ShowAxis := OnOff;
        {AxisItem.Checked := OnOff;}
        AxisCheckBox.Checked := OnOff;
        SetToRedraw(trAxis);
        Redraw;
      end;
      soReport: begin
        Data.ULVO.ShowReport := OnOff;
        if OnOff then
          ShowReport
        else
          HideReport;
        {ReportMenuItem.Checked := OnOff;}
        ReportCheckBox.Checked := OnOff;
      end;
      soPeaks: begin
        Data.ULVO.ShowPeaks := OnOff;
        if OnOff then
          PeaksShow
        else
          PeaksHide;
      end;
      soXY: begin
        Data.ULVO.ShowXY := OnOff;
        if OnOff then begin
          {ViewXYItem.Checked := true;}
          XYEdit.Visible := true;
        end else begin
          {ViewXYItem.Checked := false;}
          XYEdit.Visible := false;
        end;
      end;
      soHeader: begin
        Data.ULVO.ShowHeader := OnOff;
        if OnOff then begin
          {ViewHeaderItem.Checked := true;}
        end else begin
          {ViewHeaderItem.Checked := false;}
        end;
        SetToRedraw(trHeader);
        Redraw;

      end;
    end;
  finally
    ChangingView := false;
  end;
end;

function TSpectrumForm.StartCreateBaseLine(X,Y:integer): boolean;
var
  pp,cp,np: TScreenPeak;
  l, w: integer;
begin
  Result := true;
  Spect.GetScreenBaseLineRec(X, OutDisp^, pp, cp, np);
  if cp.p1.X >= 0 then begin
    Result := false;
    exit;
  end;

  BaseLineStartPoint.X := X;
  BaseLineStartPoint.Y := Y;
  BaseLineDefineMode := pdCreate;

  l := X;
  w := OutDisp^.Width - (l - OutDisp^.Left);
  if np.p1.X >= 0 then begin
    w := w - (OutDisp^.Width - (np.p1.X - OutDisp^.Left));
  end;
  BaseLineML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);
  BaseLineML.Mode := mmVerticalColumn;
  BaseLineML.Start(X, Y);
end;

function TSpectrumForm.StartMoveBaseLine(X: integer): boolean;
var
  pp,cp,np: TScreenPeak;
  l,w:integer;
  start, size:TPoint;
begin
  Result := true;
  BaseLineStartPoint.X := X;
  BaseLineDefineMode := pdMove;

  Spect.GetScreenBaseLineRec(X, OutDisp^, pp, cp, np);
  if cp.P1.X < 0 then begin
    Result := false;
    exit;
  end;
  l := OutDisp^.Left;
  if pp.p2.X >= 0 then
    l := pp.p2.X;
  w := OutDisp^.Width - (l - OutDisp^.Left);
  if np.p1.X >= 0 then begin
    w := w - (OutDisp^.Width + OutDisp^.Left - np.p1.X);
  end;
  BaseLineML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);

  BaseLineML.Mode := mmGraphObject;
  start.X := cp.p1.X;
  start.Y := OutDisp^.Top;
  size.X := (cp.p2.X - cp.p1.X);
  size.Y := OutDisp^.Height;
  BaseLineML.SetObj(otVerticalColumn, start, size);
  BaseLineML.Start(X, OutDisp^.Top);
end;

function TSpectrumForm.StartSizeBaseLine(X:integer): boolean;
var
  pp,cp,np: TScreenPeak;{previous peek, current peak, nextpeak}
  l,w:integer;
begin
  Result := true;
  BaseLineStartPoint.X := X;
  Spect.GetScreenBaseLineRec(X, OutDisp^, pp, cp, np);
  if cp.P1.X < 0 then begin
    Result := false;
    exit;
  end;
  if (X - cp.P1.X) > (cp.P2.X - X) then begin
    BaseLineDefineMode := pdSizeRight;
    l := cp.P1.X;
    w := OutDisp^.Width - (l - OutDisp^.Left);
    if np.p1.X >= 0 then begin
      w := w - (OutDisp^.Width + OutDisp^.Left - np.p1.X);
    end;
    BaseLineML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);
    BaseLineML.Mode := mmVerticalColumn;
    BaseLineML.Start(cp.p1.X, cp.p1.Y);
  end else begin
    BaseLineDefineMode := pdSizeLeft;
    l := OutDisp^.Left;
    if pp.p2.X >= 0 then begin
      l := pp.P2.X;
    end;
    w := OutDisp^.Width - (l - OutDisp^.Left) -
         (OutDisp^.Left + OutDisp^.Width - cp.p2.X);
    BaseLineML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);
    BaseLineML.Mode := mmVerticalColumn;
    BaseLineML.Start(cp.p2.X, cp.p2.Y);
  end;
end;

function TSpectrumForm.IsInBaseLine(X: integer; var Index: integer): boolean;
begin
  IsInBaseLine := (Spect <> nil) and
    (Spect.IsScreenXInBaseLine(X, OutDisp^, Index));
end;

function TSpectrumForm.IsInBaseLineEdge(var X: integer; Y: integer; var Index: integer): boolean;
begin
  IsInBaseLineEdge := Spect.IsScreenPointInBaseLineEdge(X,Y, OutDisp^, Index);
end;


procedure TSpectrumForm.FinishBaseLine(X,Y:integer);
var p, start,stop:TPoint;
begin
  if BaseLineStartPoint.X >= 0 then begin
    BaseLineML.Stop(X, Y);
    BaseLineML.GetResult(p, BaseLineStopPoint);
    case BaseLineDefineMode of
      pdCreate: begin
        CreateBaseLine(BaseLineStartPoint, BaseLineStopPoint);
      end;
      pdMove: begin
        BaseLineML.GetObj(start, p, stop);
        MoveBaseLine(start.X, stop.X);
      end;
      pdSizeRight: begin
        SizeBaseLine(BaseLineStartPoint.X, BaseLineStopPoint.X, true);
      end;
      pdSizeLeft: begin
        SizeBaseLine(BaseLineStartPoint.X, BaseLineStopPoint.X, false);
      end;
    end;
    CreatePeakReport;
    SetToRedraw(trBaseLine);
    Redraw;
  end;
  if not DefineModePermanent then begin
    if DefineMode = dmBaseLine then
      DefineMode := dmNone;
  end else begin
    BaseLineDefineMode:= pdReady;
    BaseLineStartPoint.X := -1;
  end;
end;

procedure TSpectrumForm.MoveBaseLine(OldStartX, NewStartX:integer);
var p:integer;
begin
  Spect.MoveScreenBaseLine(OldStartX,NewStartX, OutDisp^, p);
end;

procedure TSpectrumForm.SizeBaseLine(OldStopX, NewStopX:integer; Right: boolean);
var
  p:integer;
begin
  Spect.SizeScreenBaseLine(OldStopX,NewStopX, OutDisp^, p, right);
end;

procedure TSpectrumForm.CreateBaseLine(const AStartPoint, AStopPoint:TPoint);
var ip1,ip2:TIndexPoint;
begin
  if AStartPoint.X >= AStopPoint.X then
    exit;
  if abs(AStartPoint.X - AStopPoint.X) < MousePointArea then
    exit;
  if ScreenPointToIndexPoint(AStartPoint, ip1) and
     ScreenPointToIndexPoint(AStopPoint, ip2)
  then begin
    Spect.CreateBaseLine(ip1, ip2);
  end;
end;

function TSpectrumForm.StartCreatePeak(X,Y:integer): boolean;
var
  pp,cp,np: TScreenPeak;
  l, w: integer;
begin
  Result := true;
  Spect.GetScreenPeaks(X, OutDisp^, pp, cp, np);
  if cp.p1.X >= 0 then begin
    Result := false;
    exit;
  end;

  PeakStartPoint.X := X;
  PeakStartPoint.Y := Y;
  PeakDefineMode := pdCreate;

  l := X;
  w := OutDisp^.Width - (l - OutDisp^.Left);
  if np.p1.X >= 0 then begin
    w := w - (OutDisp^.Width - (np.p1.X - OutDisp^.Left));
  end;
  PeakML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);
  PeakML.Mode := mmVerticalColumn;
  PeakML.Start(X, Y);
end;

function TSpectrumForm.IsPeakStart(X: integer): boolean;
var p:integer;
begin
  IsPeakStart := (Spect <> nil) and
    (Spect.IsScreenPeakStart(X, OutDisp^, p));
end;

function TSpectrumForm.IsInPeak(X: integer; var PeakIndex: integer): boolean;
begin
  IsInPeak := (Spect <> nil) and
    (Spect.IsScreenXInPeak(X, OutDisp^, PeakIndex));
end;

function TSpectrumForm.IsInPeakEdge(X,Y: integer; var PeakIndex:integer):boolean;
      { Is given screen coordinates inside edge sign of any peak? }
begin
  IsInPeakEdge := Spect.IsScreenPointInPeakEdge(X, Y, OutDisp^, PeakIndex);
end;


function TSpectrumForm.IsPeakStop(X: integer): boolean;
var p:integer;
begin
  IsPeakStop := (Spect <> nil) and
    (Spect.IsScreenPeakStop(X, OutDisp^, p));
end;

function TSpectrumForm.StartMovePeak(X: integer): boolean;
var
  pp,cp,np: TScreenPeak;
  l,w:integer;
  start, size:TPoint;
begin
  Result := true;
  PeakStartPoint.X := X;
  PeakDefineMode := pdMove;

  Spect.GetScreenPeaks(X, OutDisp^, pp, cp, np);
  if cp.P1.X < 0 then begin
    Result := false;
    exit;
  end;
  l := OutDisp^.Left;
  if pp.p2.X >= 0 then
    l := pp.p2.X;
  w := OutDisp^.Width - (l - OutDisp^.Left);
  if np.p1.X >= 0 then begin
    w := w - (OutDisp^.Width + OutDisp^.Left - np.p1.X);
  end;
  PeakML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);

  PeakML.Mode := mmGraphObject;
  start.X := cp.p1.X;
  start.Y := OutDisp^.Top;
  size.X := (cp.p2.X - cp.p1.X);
  size.Y := OutDisp^.Height;
  PeakML.SetObj(otVerticalColumn, start, size);
  PeakML.Start(X, OutDisp^.Top);
end;

function TSpectrumForm.StartSizePeak(X:integer): boolean;
var
  pp,cp,np: TScreenPeak;{previous peek, current peak, nextpeak}
  l,w:integer;
begin
  Result := true;
  PeakStartPoint.X := X;
{  PeakDefineMode := pdSize;}
  Spect.GetScreenPeaks(X, OutDisp^, pp, cp, np);
  if cp.P1.X < 0 then begin
    Result := false;
    exit;
  end;
  if (X - cp.P1.X) > (cp.P2.X - X) then begin
    PeakDefineMode := pdSizeRight;
    l := cp.P1.X;
    w := OutDisp^.Width - (l - OutDisp^.Left);
    if np.p1.X >= 0 then begin
      w := w - (OutDisp^.Width + OutDisp^.Left - np.p1.X);
    end;
    PeakML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);
    PeakML.Mode := mmVerticalColumn;
    PeakML.Start(cp.p1.X, cp.p1.Y);
  end else begin
    PeakDefineMode := pdSizeLeft;
    l := OutDisp^.Left;
    if pp.p2.X >= 0 then begin
      l := pp.P2.X;
    end;
    w := OutDisp^.Width - (l - OutDisp^.Left) -
         (OutDisp^.Left + OutDisp^.Width - cp.p2.X);
    PeakML.SetLimits(l, OutDisp^.Top, w, OutDisp^.Height);
    PeakML.Mode := mmVerticalColumn;
    PeakML.Start(cp.p2.X, cp.p2.Y);
  end;
end;

procedure TSpectrumForm.MovePeak(OldStartX, NewStartX:integer);
var p:integer;
begin
  Spect.MoveScreenPeak(OldStartX,NewStartX, OutDisp^, p);
end;

procedure TSpectrumForm.SizePeak(OldStopX, NewStopX:integer; Right: boolean);
var
  p:integer;
begin
  Spect.SizeScreenPeak(OldStopX,NewStopX, OutDisp^, p, right);
end;

procedure TSpectrumForm.ToggleSelectPeak(X: integer; Shift: TShiftState);
begin
  Spect.ToggleSelectScreenPeak(X, OutDisp^, Shift);
end;

procedure TSpectrumForm.FinishPeak(X, Y: integer; Shift: TShiftState);
var p, start,stop:TPoint;
begin
  if PeakStartPoint.X >= 0 then begin
    PeakML.Stop(X, Y);
    PeakML.GetResult(p, PeakStopPoint);
    if PeakStartPoint.X = PeakStopPoint.X then begin
      ToggleSelectPeak(PeakStartPoint.X, Shift);
    end else begin
      case PeakDefineMode of
        pdCreate: begin
          CreatePeak(PeakStartPoint, PeakStopPoint);
        end;
        pdMove: begin
          PeakML.GetObj(start, p, stop);
          MovePeak(start.X, stop.X);
        end;
        pdSizeRight: begin
          SizePeak(PeakStartPoint.X, PeakStopPoint.X, true);
        end;
        pdSizeLeft: begin
          SizePeak(PeakStartPoint.X, PeakStopPoint.X, false);
        end;
      end;
      CreatePeakReport;
    end;
    SetToRedraw(trPeaks);
    Redraw;
  end;
  if not DefineModePermanent then begin
    if DefineMode = dmPeaks then
      DefineMode := dmNone;
  end else begin
    PeakDefineMode:= pdReady;
    PeakStartPoint.X := -1;
  end;
end;

procedure TSpectrumForm.CreatePeak(const AStartPoint, AStopPoint:TPoint);
var ip1,ip2:TIndexPoint;
begin
  if AStartPoint.X >= AStopPoint.X then
    exit;
  if abs(AStartPoint.X - AStopPoint.X) < MousePointArea then
    exit;
  if ScreenPointToIndexPoint(AStartPoint, ip1) and
     ScreenPointToIndexPoint(AStopPoint, ip2)
  then begin
    Spect.CreatePeak(ip1, ip2);
  end;
end;

procedure TSpectrumForm.PeakEditProperties(PeakIndex: integer);
begin
  Spect.Peaks.Childs[PeakIndex].Edit;
end;

procedure TSpectrumForm.BaseLineEditProperties(PeakIndex: integer);
begin
  Spect.BaseLine.Childs[PeakIndex].Edit;
end;

procedure TSpectrumForm.BaseLineMenuItemClick(Sender: TObject);
begin
{  SpectrumObjectShow(soBaseLine, not BaseLineMenuItem.Checked);}
end;

procedure TSpectrumForm.PeaksReportMenuItemClick(Sender: TObject);
begin
{  SpectrumObjectShow(soReport, not ReportMenuItem.Checked);}
end;

procedure TSpectrumForm.ShowReport;
begin
  ReportPanel.Show;
  CreatePeakReport;
  Data.ULVO.ShowReport := true;
{  ReportMenuItem.Checked := true;}
end;

procedure TSpectrumForm.HideReport;
begin
  ReportPanel.Hide;
  Data.ULVO.ShowReport := false;
{  ReportMenuItem.Checked := false;}
end;

procedure TSpectrumForm.CreatePeakReport;

  procedure StartReport;
  begin
    ReportMemo.Lines.Add('File: ' + GetFileNamePart(fpBaseName, Data.ULF.FileName));
    ReportMemo.Lines.Add('Time[min.] Area[%]')
  end;

  procedure AddPeak(p:TULPRObj);
  var
    up:TUserPoint;
    ap:TExpPoint;
  begin
    ap.X := p.X;
    ap.Y := p.Height;
    Data.ExpToUser(ap, up);
    ReportMemo.Lines.Add(RealToString(up.X, 10, 2) + RealToString(p.Ratio * 100, 7, 2));
  end;

  procedure FinishReport;
  begin
  end;

var
  i:integer;

begin
  Spect.RecalculatePeaks;

  if not ReportPanel.Visible then
    exit;

  ReportMemo.Lines.Clear;
  {if (Data = nil) or
     (Spect = nil) or
     (Spect.Peaks = nil) or
     (Spect.Peaks.ChildCount = 0)
  then
    exit;
  }
  StartReport;
  for i := 0 to Spect.Peaks.ChildCount - 1 do
    AddPeak(TULPRObj(Spect.Peaks.Childs[i]));
  FinishReport;
end;

procedure TSpectrumForm.PeaksMenuItemClick(Sender: TObject);
begin
{  if PeaksMenuItem.Checked then
    PeaksHide
  else
    PeaksShow;}
end;

procedure TSpectrumForm.DefineSpeedButtonClick(Sender: TObject);
var dm: TDefineMode;
begin
  dm := TDefineMode(TSpeedButton(Sender).Tag);
  if DefineMode = dm then
    PostMessage(Handle, WM_APPMESSAGE, cmDefineModeSet, longint(dmNone))
  else
    PostMessage(Handle, WM_APPMESSAGE, cmDefineModeSet, longint(dm));
end;

procedure TSpectrumForm.MarginsDefineStart;
begin
  DefineMarginsSpeedButton.Down := true;
end;

procedure TSpectrumForm.MarginsDefineStop;
begin
  DefineMarginsSpeedButton.Down := false;
end;

procedure TSpectrumForm.BaseLineDefineStart;
begin
  DefineBaseLineSpeedButton.Down := true;
  BaseLineDefineItem.Checked := true;

  SpectrumObjectShow(soBaseline, true);
{  BaseLineMenuItem.Checked := true;
  BaseLineCheckBox.Checked := true;
  SetToRedraw(trBaseLine);
  Redraw;}
end;

procedure TSpectrumForm.BaseLineDefineStop;
begin
  DefineBaseLineSpeedButton.Down := false;
  {SpectrumObjectShow(soBaseline, false);}
{  BaseLineDefineItem.Checked := false;
  SetToRedraw(trBaseLine);
  Redraw;}
end;

procedure TSpectrumForm.ReportPanelMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
const
  SC_DragMove = $F012;
begin
  ReleaseCapture;
  ReportPanel.Perform(WM_SysCommand, SC_DragMove, 0);
end;


procedure TSpectrumForm.MarginBackSpeedButtonClick(Sender: TObject);
begin
  PopScreenSubView;
end;

procedure TSpectrumForm.StopButtonClick(Sender: TObject);
begin
  Stop;
end;

procedure TSpectrumForm.RunButtonClick(Sender: TObject);
begin
  Run;
end;

procedure TSpectrumForm.BaseLineCheckBoxMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  PostMessage(Handle, WM_APPMESSAGE, cmSpectrumObjectShow + soBaseLine,
    longint(not Data.ULVO.ShowBaseLine{BaseLineCheckBox.Checked}));
end;

procedure TSpectrumForm.AxisCheckBoxMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  PostMessage(Handle, WM_APPMESSAGE, cmSpectrumObjectShow + soAxis,
    longint(not Data.ULVO.ShowAxis{AxisCheckBox.Checked}));
end;

procedure TSpectrumForm.PeaksCheckBoxMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  PostMessage(Handle, WM_APPMESSAGE, cmSpectrumObjectShow + soPeaks,
    longint(not Data.ULVO.ShowPeaks{PeaksCheckBox.Checked}));
end;

procedure TSpectrumForm.ReportCheckBoxMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  PostMessage(Handle, WM_APPMESSAGE, cmSpectrumObjectShow + soReport,
    longint(not Data.ULVO.ShowReport{ReportCheckBox.Checked}));
end;

procedure TSpectrumForm.FilterMenuItemClick(Sender: TObject);
begin
  if Data.ULMF.Edit = mrOK then
    Data.FilterUpdate;
{
  GetFilterPars(fp);
  FilterParsForm.ParamsToControls(fp);
  if FilterParsForm.ShowModal = mrOK then begin
    FilterParsForm.ControlsToParams(fp);
    Data.SetFilterPars(fp);
    SetToRedraw(trData);
    Redraw;
  end;
  }
end;

procedure TSpectrumForm.HeaderItemClick(Sender: TObject);
begin
  Data.ULA.Edit;
end;

procedure TSpectrumForm.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
  if not VerifyAbort then
    exit;
  if RunningState <> rsStopped then begin
    if ShowMessage('Abort acquisition?', smNoYes, 0) <> cmYes then begin
      CanClose := false;
      exit;
    end;
    Stop;
  end;
  if (Data <> nil) and (Data.ULF <> nil)
     and (pos('NONAME', Data.ULF.FileName) <> 0) then
  begin
    if Data.ULAD.Data.Size > 0 then begin
      if not DoSaveTo then begin
        if ShowMessage('Discard data?', smNoYes, 0) <> cmYes then begin
          CanClose := false;
        end;
      end;
    end;
  end;
end;

procedure TSpectrumForm.PeaksDeleteLastItemClick(Sender: TObject);
var c: TComponent;
begin
  if Spect.Peaks.ChildCount > 0 then begin
    c := Spect.Peaks.Components[Spect.Peaks.ComponentCount-1];
    c.Free;
    SetToRedraw(trPeaks);
    Redraw;
  end;
end;

procedure TSpectrumForm.Autodetect1Click(Sender: TObject);
begin
  Spect.Autodetect;
  SpectrumObjectShow(soPeaks, true);
  SpectrumObjectShow(soBaseLine, true);
  SetToRedraw(trPeaks);
  Redraw;
end;

procedure TSpectrumForm.PeaksBrowseItemClick(Sender: TObject);
begin
  Spect.Peaks.Browse;
end;

procedure TSpectrumForm.BaseLineDefineItemClick(Sender: TObject);
begin
  if DefineMode <> dmBaseLine then
    DefineMode := dmBaseLine
  else
    DefineMode := dmNone;
end;

procedure TSpectrumForm.BaseLineBrowseItemClick(Sender: TObject);
begin
  Spect.BaseLine.Browse;
end;

procedure TSpectrumForm.PeaksDefineItemClick(Sender: TObject);
begin
  if DefineMode = dmPeaks then
    DefineMode := dmNone
  else
    DefineMode := dmPeaks;
end;

procedure TSpectrumForm.UpdatePrinterDisp(APrinter:TPrinter);
var tw, th: integer; {prnutl}
begin
  tw := APrinter.Canvas.TextWidth('M');
  th := APrinter.Canvas.TextHeight(' ');
  APrinter.Orientation := poLandscape;
  PrinterDisp.Height := APrinter.PageHeight - 12 * th;
  PrinterDisp.Width := APrinter.PageWidth - 30 * tw;
  PrinterDisp.Left := 20 * tw;
  PrinterDisp.Top := 4 * th;
  if Data <> nil then begin
    SetToRedraw(trAll);
  end;
end;

procedure TSpectrumForm.DrawHeader(ACanvas: TCanvas);
var
  cw,ch, hd, wd:integer;
  x,y:integer;
{  s: string;}
begin
  with ACanvas do begin
    cw := TextWidth('M');
    ch := TextHeight('M');
    wd := cw;
    hd := ch div 4;
    x := OutDisp^.Left + hd;
    y := OutDisp^.Top + wd;
    MoveTo(x, y);
    TextOut(x,y, DateTimeToStr(Now) + ' ' + Data.ULA.SampleName);
    inc(y, hd + ch);
    TextOut(x,y, Data.ULA.SampleDesc);
  end;
end;

function TSpectrumForm.Printing: boolean;
begin
  Printing := (FDataPrinter <> nil);
end;

procedure TSpectrumForm.Print;
var prn: TPrinter;
begin
  OutDisp := @PrinterDisp;
  FDataPrinter := TDataPrinter.Create;
  try
    prn := FDataPrinter.Prn;
    UpdatePrinterDisp(prn);
    with prn do begin
      BeginDoc;
      DrawPoints(prn.Canvas);
      if SpectrumObjectVisible(soAxis) then
        DrawAxis(prn.Canvas);
      if SpectrumObjectVisible(soPeaks) then
        DrawPeaks(prn.Canvas);
      if SpectrumObjectVisible(soBaseLine) then
        DrawBaseLine(prn.Canvas);
      if SpectrumObjectVisible(soHeader) then
        DrawHeader(prn.Canvas);
      EndDoc;
    end;
  finally
    FDataPrinter.Free;
    OutDisp := @ScreenDisp;
  end;
end;

procedure TSpectrumForm.PrintItemClick(Sender: TObject);
begin
  Print;
end;

procedure TSpectrumForm.ViewXYItemClick(Sender: TObject);
begin
{  SpectrumObjectShow(soXY, not ViewXYItem.Checked);}
end;

procedure TSpectrumForm.PeaksDeleteSelectedItemClick(Sender: TObject);
var
  i: integer;
  p: TULPRObj;
begin
  i := 0;
  while i < Spect.Peaks.ChildCount do begin
    p := TULPRObj(Spect.Peaks.Childs[i]);
    if p.IsFlagSet(rfSelected) and p.CanDestroy then
      p.Free
    else
      inc(i);
  end;
  SetToRedraw(trPeaks);
  Redraw;
end;

procedure TSpectrumForm.ViewHeaderItemClick(Sender: TObject);
begin
{  SpectrumObjectShow(soHeader, not ViewHeaderItem.Checked);}
end;

procedure TSpectrumForm.ViewItemClick(Sender: TObject);
begin
  Data.ULVO.Edit;
end;

procedure TSpectrumForm.MethodEditItemClick(Sender: TObject);
begin
  Data.ULM.Edit;
end;

procedure TSpectrumForm.MethodPeaksClearItemClick(Sender: TObject);
begin
  Data.ULM_ULP.Clear;
end;

procedure TSpectrumForm.MethodPeaksBrowseItemClick(Sender: TObject);
begin
  Data.ULM_ULP.Browse;
end;

procedure TSpectrumForm.PeaksToMethodItemClick(Sender: TObject);
begin
  Spect.CopySelectedPeaksToMethod;
end;

function TSpectrumForm.PeakStickLen: integer;
begin
  if Printing then begin
    PeakStickLen := round(MMPeakStickLen / MMPerInch * FDataPrinter.PPIY)
  end else begin
    PeakStickLen := PointsPeakStickLen;
  end;
end;

function TSpectrumForm.PeakArrowLen: integer;
begin
  if Printing then begin
    PeakArrowLen := round(MMPeakArrowLen /MMPerInch * FDataPrinter.PPIX)
  end else begin
    PeakArrowLen := PointsPeakArrowLen;
  end;
end;

function TSpectrumForm.BaseLineCircleRadius: integer;
begin
  if Printing then begin
    BaseLineCircleRadius := round(MMBaseLineCircleRadius /MMPerInch * FDataPrinter.PPIY)
  end else begin
    BaseLineCircleRadius := PointsBaseLineCircleRadius;
  end;
end;

end.
