home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / image144.sit / Edit.p < prev    next >
Encoding:
Text File  |  1992-03-30  |  61.8 KB  |  2,382 lines

  1. unit Edit;
  2.  
  3. {Editing routines used by the Image program}
  4.  
  5. interface
  6.  
  7.     uses
  8.         QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, Camera, analysis, file1, functions, stacks, Lut;
  9.  
  10.  
  11.     procedure FlipOrRotate (DoWhat: FlipRotateType);
  12.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  13.     procedure Rotate (DoWhat: FlipRotateType);
  14.     procedure DoCopy;
  15.     procedure DoCut;
  16.     procedure DoPaste;
  17.     procedure DoClear;
  18.     procedure SetPasteMode (item: integer);
  19.     procedure DoMouseDownInPasteControl (loc: point);
  20.     procedure ShowPasteControl;
  21.     procedure DrawPasteControl;
  22.     procedure ShowClipboard;
  23.     procedure DoObject (obj: ObjectType; event: EventRecord);
  24.     procedure DoAirBrush;
  25.     procedure DoBrush (event: EventRecord);
  26.     procedure DoText (loc: point);
  27.     procedure SetAirbrushSize;
  28.     procedure SetBrushSize;
  29.     procedure UpdateEditMenu;
  30.     procedure ConvertClipboard;
  31.     procedure ZoomOut;
  32.     procedure ZoomIn (event: EventRecord);
  33.     procedure Scroll (event: EventRecord);
  34.     procedure DoFill (event: EventRecord);
  35.     procedure DoGrow (WhichWindow: WindowPtr; event: EventRecord);
  36.     procedure DrawCharacter (ch: char);
  37.     procedure ConvertSystemClipboard;
  38.     procedure SetupOperation (item: integer);
  39.     procedure PastePicture;
  40.     procedure DoUndo;
  41.     procedure FindWhatToCopy;
  42.     procedure DoMath;
  43.     procedure CopyResults;
  44.  
  45.  
  46. implementation
  47.  
  48.  
  49.     procedure PivotSelection (var SelectionRect: rect; WindowRect: rect);
  50.         var
  51.             OldWidth, NewWidth, OldHeight, NewHeight, hCenter, vCenter, NewLeft, NewTop: integer;
  52.     begin
  53.         with SelectionRect do begin
  54.                 OldWidth := right - left;
  55.                 OldHeight := bottom - top;
  56.                 hCenter := left + OldWidth div 2;
  57.                 vCenter := top + OldHeight div 2;
  58.             end;
  59.         NewWidth := OldHeight;
  60.         NewHeight := OldWidth;
  61.         NewLeft := hCenter - NewWidth div 2;
  62.         NewTop := vCenter - NewHeight div 2;
  63.         with WindowRect do begin
  64.                 if (NewLeft + NewWidth) > right then
  65.                     NewLeft := right - NewWidth;
  66.                 if (NewTop + NewHeight) > bottom then
  67.                     NewTop := bottom - NewHeight;
  68.                 if NewLeft < 0 then
  69.                     NewLeft := 0;
  70.                 if NewTop < 0 then
  71.                     NewTop := 0;
  72.             end;
  73.         with SelectionRect do begin
  74.                 left := NewLeft;
  75.                 top := NewTop;
  76.                 right := NewLeft + NewWidth;
  77.                 bottom := NewTop + NewHeight;
  78.             end;
  79.     end;
  80.  
  81.  
  82.     procedure FlipLine (var LineBuf: LineType; width: integer);
  83.         var
  84.             TempLine: LineType;
  85.             i, WidthLessOne: integer;
  86.     begin
  87.         TempLine := LineBuf;
  88.         WidthLessOne := width - 1;
  89.         for i := 0 to width - 1 do
  90.             LineBuf[i] := TempLine[WidthLessOne - i];
  91.     end;
  92.  
  93.  
  94.     procedure ScreenToOffscreenRect (var r: rect);
  95.         var
  96.             p1, p2: point;
  97.     begin
  98.         with r do begin
  99.                 p1.h := left;
  100.                 p1.v := top;
  101.                 p2.h := right;
  102.                 p2.v := bottom;
  103.                 ScreenToOffscreen(p1);
  104.                 ScreenToOffscreen(p2);
  105.                 Pt2Rect(p1, p2, r);
  106.             end;
  107.     end;
  108.  
  109.  
  110.     procedure FlipOrRotate; {(DoWhat: FlipRotateType)}
  111.         var
  112.             SaveInfo: InfoPtr;
  113.             width, height, hDst, vSrc, vDst, hSrc, i, inc: integer;
  114.             LineBuf: LineType;
  115.             srect, drect, MaskRect: rect;
  116.             PixelCount: LongInt;
  117.             AutoSelectAll: boolean;
  118.  
  119.     begin
  120.         if NotRectangular or NotInBounds or NoUndo then
  121.             exit(FlipOrRotate);
  122.         AutoSelectAll := not Info^.RoiShowing;
  123.         if AutoSelectAll then
  124.             SelectAll(true);
  125.         if TooWide then
  126.             exit(FlipOrRotate);
  127.         ShowWatch;
  128.         SetupUndoFromClip;
  129.         SetupUndo;
  130.         if (DoWhat = RotateLeft) or (DoWhat = RotateRight) then
  131.             WhatToUndo := UndoRotate
  132.         else
  133.             WhatToUndo := UndoFlip;
  134.         SetupUndoInfoRec;
  135.         SaveInfo := Info;
  136.         srect := info^.RoiRect;
  137.         PixelCount := 0;
  138.         case DoWhat of
  139.  
  140.             RotateLeft, RotateRight: 
  141.                 with srect do begin
  142.                         if OptionKeyWasDown then
  143.                             DoOperation(EraseOp);
  144.                         drect := srect;
  145.                         with info^ do begin
  146.                                 PivotSelection(drect, PicRect);
  147.                                 MaskRect := drect;
  148.                                 RoiRect := drect;
  149.                                 RectRgn(roiRgn, RoiRect);
  150.                             end;
  151.                         width := right - left;
  152.                         if DoWhat = RotateLeft then begin
  153.                                 hDst := drect.left;
  154.                                 inc := 1
  155.                             end
  156.                         else begin
  157.                                 hDst := drect.right - 1;
  158.                                 inc := -1
  159.                             end;
  160.                         for vSrc := top to bottom - 1 do begin
  161.                                 Info := UndoInfo;
  162.                                 GetLine(left, vSrc, width, LineBuf);
  163.                                 if DoWhat = RotateLeft then
  164.                                     FlipLine(LineBuf, width);
  165.                                 Info := SaveInfo;
  166.                                 PutColumn(hDst, drect.top, width, LineBuf);
  167.                                 hDst := hDst + inc;
  168.                                 PixelCount := PixelCount + width;
  169.                                 if PixelCount > 10000 then begin
  170.                                         UpdateScreen(MaskRect);
  171.                                         PixelCount := 0;
  172.                                     end;
  173.                             end;
  174.                     end;
  175.  
  176.             FlipVertical: 
  177.                 with srect do begin
  178.                         MaskRect := srect;
  179.                         width := right - left;
  180.                         vDst := bottom;
  181.                         for vSrc := top to bottom - 1 do begin
  182.                                 Info := UndoInfo;
  183.                                 GetLine(left, vSrc, width, LineBuf);
  184.                                 Info := SaveInfo;
  185.                                 vDst := vDst - 1;
  186.                                 PutLine(left, vDst, width, LineBuf);
  187.                             end;
  188.                     end;
  189.  
  190.             FlipHorizontal: 
  191.                 with srect do begin
  192.                         MaskRect := srect;
  193.                         width := right - left;
  194.                         for vSrc := top to bottom - 1 do begin
  195.                                 Info := UndoInfo;
  196.                                 GetLine(left, vSrc, width, LineBuf);
  197.                                 FlipLine(LineBuf, width);
  198.                                 Info := SaveInfo;
  199.                                 PutLine(left, vSrc, width, LineBuf);
  200.                                 PixelCount := PixelCount + width;
  201.                                 if PixelCount > 10000 then begin
  202.                                         UpdateScreen(MaskRect);
  203.                                         PixelCount := 0;
  204.                                     end;
  205.                             end;
  206.                     end;
  207.  
  208.         end; {case}
  209.         Info := SaveInfo;
  210.         with info^ do begin
  211.                 UpdatePicWindow;
  212.                 changes := true;
  213.             end;
  214.         SetupRoiRect;
  215.         if AutoSelectAll then
  216.             KillRoi;
  217.     end;
  218.  
  219.  
  220.  
  221.     procedure RotateToNewWindow (DoWhat: FlipRotateType);
  222.         var
  223.             SrcInfo, DstInfo: InfoPtr;
  224.             Srcwidth, DstWidth, DstHeight, hDst, vSrc, vDst, hSrc, i, inc, ignore: integer;
  225.             LineBuf: LineType;
  226.             SourceRect, DstRect: rect;
  227.             PixelCount: LongInt;
  228.             AutoSelectAll: boolean;
  229.  
  230.     begin
  231.         if NotRectangular or NotInBounds then
  232.             exit(RotateToNewWindow);
  233.         AutoSelectAll := not Info^.RoiShowing;
  234.         if AutoSelectAll then
  235.             SelectAll(true);
  236.         if TooWide then
  237.             exit(RotateToNewWindow);
  238.         ShowWatch;
  239.         SrcInfo := info;
  240.         with info^, info^.RoiRect do begin
  241.                 SourceRect := RoiRect;
  242.                 SrcWidth := right - left;
  243.                 DstWidth := bottom - top;
  244.                 DstHeight := right - left;
  245.                 if not NewPicWindow(title, DstWidth, DstHeight) then begin
  246.                         KillRoi;
  247.                         if macro then
  248.                             macro := false;
  249.                         exit(RotateToNewWindow)
  250.                     end;
  251.                 DstInfo := info;
  252.                 DstRect := info^.PicRect;
  253.             end;
  254.         PixelCount := 0;
  255.         if DoWhat = RotateLeft then begin
  256.                 hDst := 0;
  257.                 inc := 1
  258.             end
  259.         else begin
  260.                 hDst := DstWidth - 1;
  261.                 inc := -1
  262.             end;
  263.         with SourceRect do
  264.             for vSrc := top to bottom - 1 do begin
  265.                     Info := SrcInfo;
  266.                     GetLine(left, vSrc, SrcWidth, LineBuf);
  267.                     if DoWhat = RotateLeft then
  268.                         FlipLine(LineBuf, SrcWidth);
  269.                     Info := DstInfo;
  270.                     PutColumn(hDst, 0, SrcWidth, LineBuf);
  271.                     hDst := hDst + inc;
  272.                     PixelCount := PixelCount + SrcWidth;
  273.                     if PixelCount > 20000 then begin
  274.                             UpdatePicWindow;
  275.                             PixelCount := 0;
  276.                         end;
  277.                 end;
  278.         UpdatePicWindow;
  279.         info^.changes := true;
  280.         if AutoSelectAll then
  281.             with SrcInfo^ do begin
  282.                     Changes := false;
  283.                     ignore := CloseAWindow(wptr);
  284.                     info := DstInfo;
  285.                 end;
  286.     end;
  287.  
  288.  
  289.     procedure Rotate; {(DoWhat: FlipRotateType)}
  290.         const
  291.             NewWindowID = 3;
  292.         var
  293.             mylog: DialogPtr;
  294.             item: integer;
  295.             NewWindow: boolean;
  296.     begin
  297.         with info^, info^.RoiRect do
  298.             if RoiShowing then
  299.                 NewWindow := ((right - left) > PicRect.bottom) or ((bottom - top) > PicRect.right)
  300.             else begin
  301.                     RotateToNewWindow(DoWhat);
  302.                     exit(Rotate);
  303.                 end;
  304.         InitCursor;
  305.         mylog := GetNewDialog(120, nil, pointer(-1));
  306.         SetDialogItem(mylog, NewWindowID, ord(NewWindow));
  307.         OutlineButton(MyLog, ok, 16);
  308.         repeat
  309.             if item = NewWindowID then begin
  310.                     NewWindow := not NewWindow;
  311.                     SetDialogItem(mylog, NewWindowID, ord(NewWindow));
  312.                 end;
  313.             ModalDialog(nil, item);
  314.         until (item = ok) or (item = cancel);
  315.         DisposDialog(mylog);
  316.         if NewWindow then
  317.             RotateToNewWindow(DoWhat)
  318.         else
  319.             FlipOrRotate(DoWhat);
  320.     end;
  321.  
  322.  
  323.     procedure CopyImage;
  324.         var
  325.             err: LongInt;
  326.             line: integer;
  327.     begin
  328.         with info^ do begin
  329.                 if NoUndo then begin
  330.                         WhatsOnClip := Nothing;
  331.                         exit(CopyImage)
  332.                     end;
  333.                 SetupUndo;
  334.                 BlockMove(PicBaseAddr, ClipBuf, PixMapSize);
  335.             end;
  336.         with ClipBufInfo^ do begin
  337.                 PixelsPerLine := info^.PixelsPerLine;
  338.                 BytesPerRow := info^.BytesPerRow;
  339.                 nLines := Info^.nLines;
  340.                 RoiRect := info^.RoiRect;
  341.                 roiType := Info^.roiType;
  342.                 PicRect := Info^.PicRect;
  343.                 with osPort^.portPixMap^^ do begin
  344.                         RowBytes := BitOr(BytesPerRow, $8000);
  345.                         bounds := PicRect;
  346.                     end;
  347.                 with osPort^ do begin
  348.                         PortRect := PicRect;
  349.                         RectRgn(visRgn, PicRect);
  350.                     end;
  351.                 if RoiType = RectRoi then begin
  352.                         if info^.PictureType = QuickCaptureType then
  353.                             WhatsOnClip := CameraPic
  354.                         else
  355.                             WhatsOnClip := RectPic
  356.                     end
  357.                 else
  358.                     WhatsOnClip := NonRectPic;
  359.                 CopyRgn(info^.roiRgn, roiRgn);
  360.                 ctable := info^.ctable;
  361.             end;
  362.     end;
  363.  
  364.  
  365.     procedure CopyWindow;
  366.         var
  367.             tPort: GrafPtr;
  368.             WindowSize: LongInt;
  369.             WindowRect: rect;
  370.             WhichWindow: WindowPtr;
  371.             kind, ignore: integer;
  372.             HidingPasteControl: boolean;
  373.     begin
  374.         WhichWindow := FrontWindow;
  375.         WindowRect := WhichWindow^.PortRect;
  376.         kind := WindowPeek(WhichWindow)^.WindowKind;
  377.         HidingPasteControl := false;
  378.         with WindowRect do
  379.             WindowSize := LongInt(right) * bottom;
  380.         if kind = LUTKind then
  381.             WindowRect.bottom := 256;
  382.         case kind of
  383.             ProfilePlotKind:  begin
  384.                     ConvertPlotToText;
  385.                     ClipTextInBuffer := true;
  386.                 end;
  387.             CalibrationPlotKind:  begin
  388.                     ConvertCalibrationCurveToText;
  389.                     ClipTextInBuffer := true;
  390.                 end;
  391.             HistoKind, LUTKind, MapKind, ToolKind:  begin
  392.                     if PasteControl <> nil then begin
  393.                             ignore := CloseAWindow(PasteControl);
  394.                             HidingPasteControl := true;
  395.                         end;
  396.                     case kind of
  397.                         HistoKind:  begin
  398.                                 ConvertHistoToText;
  399.                                 ClipTextInBuffer := true;
  400.                                 DrawHistogram;
  401.                             end;
  402.                         MapKind: 
  403.                             DrawMap;
  404.                         LUTKind: 
  405.                             DrawLUT;
  406.                         ToolKind: 
  407.                             DrawTools;
  408.                     end; {case}
  409.                 end;
  410.             otherwise
  411.         end; {case}
  412.         if NoUndo then begin
  413.                 WhatsOnClip := Nothing;
  414.                 exit(CopyWindow)
  415.             end;
  416.         ClipboardConverted := false;
  417.         with ClipBufInfo^ do begin
  418.                 RoiType := RectRoi;
  419.                 RoiRect := WindowRect;
  420.                 RectRgn(roiRgn, RoiRect);
  421.                 PicRect := WindowRect;
  422.                 PixelsPerLine := WindowRect.right;
  423.                 BytesPerRow := PixelsPerLine;
  424.                 if odd(BytesPerRow) then
  425.                     BytesPerRow := BytesPerRow + 1;
  426.                 nLines := WindowRect.bottom;
  427.                 with osPort^.portPixMap^^ do begin
  428.                         RowBytes := BitOr(BytesPerRow, $8000);
  429.                         bounds := WindowRect;
  430.                     end;
  431.                 with osPort^ do begin
  432.                         PortRect := PicRect;
  433.                         RectRgn(visRgn, PicRect);
  434.                         SetRectRgn(ClipRgn, 0, 0, 30000, 30000);
  435.                     end;
  436.                 WhatsOnClip := RectPic;
  437.                 GetPort(tPort);
  438.                 SetPort(GrafPtr(osPort));
  439.                 RGBForeColor(BlackRGB);
  440.                 RGBBackColor(WhiteRGB);
  441.                 if (kind = ProfilePlotKind) or (kind = CalibrationPlotKind) then begin
  442.                         EraseRect(osPort^.portRect);
  443.                         DrawPlot
  444.                     end
  445.                 else begin
  446.                         hlock(handle(osPort^.portPixMap));
  447.                         CopyBits(WhichWindow^.PortBits, BitMapHandle(osPort^.portPixMap)^^, WindowRect, WindowRect, SrcCopy, nil);
  448.                         hunlock(handle(osPort^.portPixMap));
  449.                     end;
  450.                 SetPort(tPort);
  451.             end; {with}
  452.         if HidingPasteControl then
  453.             ShowPasteControl;
  454.     end;
  455.  
  456.  
  457.     procedure CopyResults;
  458.     begin
  459.         CopyResultsToBuffer(1, mCount, ShowHeadings);
  460.         ClipTextInBuffer := true;
  461.         WhatsOnClip := TextOnClip;
  462.         UnsavedResults := false;
  463.     end;
  464.  
  465.  
  466.     procedure DoCopy;
  467.         var
  468.             err: OSErr;
  469.     begin
  470.         err := ZeroScrap;
  471.         OldScrapCount := GetScrapCount;
  472.         case WhatToCopy of
  473.             CopyColor: 
  474.                 DoCopyColor;
  475.             CopySelection:  begin
  476.                     CopyImage;
  477.                     ClipTextInBuffer := false;
  478.                     ClipboardConverted := false;
  479.                 end;
  480.             CopyHistogram, CopyPlot, CopyCalibrationPlot, CopyCLUT, CopyGrayMap, CopyTools: 
  481.                 CopyWindow;
  482.             CopyMeasurements: 
  483.                 CopyResults;
  484.             otherwise
  485.                 beep;
  486.         end;
  487.     end;
  488.  
  489.  
  490.     procedure DoCut;
  491.     begin
  492.         WhatToCopy := CopySelection;
  493.         DoCopy;
  494.         DoClear;
  495.     end;
  496.  
  497.  
  498.     procedure CenterRect (inRect, outRect: rect; var ResultRect: rect);
  499. {Creates a new rectangle(ResultsRect) that is the same size as inRect, but centered within outRect.}
  500.         var
  501.             width, height, hcenter, vcenter: integer;
  502.     begin
  503.         with inRect do begin
  504.                 width := right - left;
  505.                 height := bottom - top;
  506.             end;
  507.         with outRect do begin
  508.                 hcenter := left + (right - left) div 2;
  509.                 vcenter := top + (bottom - top) div 2;
  510.             end;
  511.         with ResultRect do begin
  512.                 left := hcenter - width div 2;
  513.                 top := vcenter - height div 2;
  514.                 right := left + width;
  515.                 bottom := top + height;
  516.             end;
  517.     end;
  518.  
  519.  
  520.     procedure PastePicture;
  521.         var
  522.             loc: point;
  523.             SrcWidth, SrcHeight, DstHeight, DstWidth, dh, dv: integer;
  524.             DestRect: rect;
  525.             WindowNotResized: boolean;
  526.     begin
  527.         if LivePasteMode or (PasteTransferMode <> SrcCopy) then begin
  528.                 LivePasteMode := false;
  529.                 PasteTransferMode := SrcCopy;
  530.                 if PasteControl <> nil then
  531.                     DrawPasteControl
  532.             end;
  533.         with info^ do begin
  534.                 SetupUndo;
  535.                 WhatToUndo := UndoPaste;
  536.                 if RoiShowing then
  537.                     with RoiRect do {Pasting back into selection of same size?}
  538.                         if ((right - left) = (ClipBufInfo^.RoiRect.right - ClipBufInfo^.RoiRect.left)) and ((bottom - top) = (ClipBufInfo^.RoiRect.bottom - ClipBufInfo^.RoiRect.top)) and (ClipBufInfo^.RoiType = RoiType) then begin
  539.                                 OpPending := true;
  540.                                 CurrentOp := PasteOp;
  541.                                 exit(PastePicture)
  542.                             end;
  543.                 with ClipBufInfo^.RoiRect do {Pasting into same size window?}
  544.                     if (PicRect.right = right - left) and (PicRect.bottom = (bottom - top)) and (ClipBufInfo^.RoiType = RectRoi) then begin
  545.                             SelectAll(true);
  546.                             WhatToUndo := UndoPaste;
  547.                             OpPending := true;
  548.                             CurrentOp := PasteOp;
  549.                             exit(PastePicture)
  550.                         end;
  551.                 if RoiShowing or (roiType <> NoRoi) then
  552.                     KillRoi;
  553.                 with ClipBufInfo^.RoiRect do begin
  554.                         SrcWidth := right - left;
  555.                         SrcHeight := bottom - top;
  556.                     end;
  557.                 with SrcRect do begin
  558.                         DstWidth := right - left;
  559.                         DstHeight := bottom - top;
  560.                     end;
  561.                 with initwrect do
  562.                     WindowNotResized := (DstWidth = (right - left)) and (DstHeight = (bottom - top));
  563.                 if ((SrcWidth > DstWidth) or (SrcHeight > DstHeight)) and WindowNotResized then
  564.                     DestRect := PicRect
  565.                 else
  566.                     DestRect := SrcRect;
  567.                 CenterRect(ClipBufInfo^.RoiRect, DestRect, RoiRect);
  568.                 roiType := ClipBufInfo^.roiType;
  569.                 CopyRgn(ClipBufInfo^.roiRgn, roiRgn);
  570.                 dh := RoiRect.left - roiRgn^^.rgnbbox.left;
  571.                 dv := RoiRect.top - roiRgn^^.rgnbbox.top;
  572.                 OffsetRgn(roiRgn, dh, dv);
  573.                 RoiShowing := true;
  574.                 OpPending := true;
  575.                 CurrentOp := PasteOp;
  576.                 BinaryPic := false;
  577.             end;{with}
  578.     end;
  579.  
  580.  
  581.     procedure ConvertSystemClipboard;
  582.   {Converts system scrape to local scrape.}
  583.         var
  584.             phandle: handle;
  585.             offset, length, size: LongInt;
  586.             pframe: rect;
  587.             width, height: integer;
  588.             tPort: GrafPtr;
  589.             ScrapInfo: PScrapStuff;
  590.     begin
  591.         ScrapInfo := InfoScrap;
  592.         if ScrapInfo^.ScrapSize <= 0 then
  593.             exit(ConvertSystemClipboard);
  594.         phandle := NewHandle(0);
  595.         length := GetScrap(phandle, 'PICT', offset);
  596.         if length > 0 then begin
  597.                 ShowWatch;
  598.                 pframe := PicHandle(phandle)^^.PicFrame;
  599.                 with pframe do begin
  600.                         width := right - left;
  601.                         height := bottom - top;
  602.                         size := LongInt(width) * height;
  603.                         if size > ClipBufSize then begin
  604.                                 PutMessage('Sorry, but this image is too large to paste.');
  605.                                 DisposHandle(phandle);
  606.                                 exit(ConvertSystemClipboard)
  607.                             end;
  608.                     end;
  609.                 with ClipBufInfo^ do begin
  610.                         PixelsPerLine := width;
  611.                         nlines := height;
  612.                         SetRect(PicRect, 0, 0, width, height);
  613.                         RoiRect := PicRect;
  614.                         RectRgn(roiRgn, RoiRect);
  615.                         RoiType := Rectroi;
  616.                         GetPort(tPort);
  617.                         SetPort(GrafPtr(osPort));
  618.                         BytesPerRow := PixelsPerLine;
  619.                         if odd(BytesPerRow) then
  620.                             BytesPerRow := BytesPerRow + 1;
  621.                         with osPort^.portPixMap^^ do begin
  622.                                 RowBytes := BitOr(BytesPerRow, $8000);
  623.                                 bounds := PicRect;
  624.                             end;
  625.                         with CGrafPort(osPort^) do begin
  626.                                 PortRect := PicRect;
  627.                                 RectRgn(visRgn, PicRect);
  628.                                 SetRectRgn(ClipRgn, 0, 0, 30000, 30000);
  629.                             end;
  630.                         RGBForecolor(WhiteRGB);
  631.                         PaintRect(PicRect);
  632.                         DrawPicture(PicHandle(phandle), PicRect);
  633.                         SetPort(tPort);
  634.                     end; {with}
  635.                 WhatsOnClip := ImportedPic;
  636.             end
  637.         else begin
  638.                 length := GetScrap(phandle, 'TEXT', offset);
  639.                 if (length > 0) and (length < MaxTextBufSize) then begin
  640.                         hlock(phandle);
  641.                         BlockMove(phandle^, ptr(TextBufP), length);
  642.                         hunlock(phandle);
  643.                         TextBufSize := length;
  644.                         WhatsOnClip := TextOnClip;
  645.                     end;
  646.             end;
  647.         DisposHandle(phandle);
  648.     end;
  649.  
  650.  
  651.     procedure PasteText;
  652.         var
  653.             nTextLines, LineWidth, MaxLineWidth, MaxRectWidth, MaxRectHeight: integer;
  654.             LineStart, LineEnd, height: integer;
  655.     begin
  656.         if TextBufSize > 5000 then begin
  657.                 PutMessage('The maximum number of characters that can be pasted is 5000.');
  658.                 exit(PasteText);
  659.             end;
  660.         if NoUndo then
  661.             exit(PasteText);
  662.         with ClipBufInfo^ do begin
  663.                 SetPort(GrafPtr(osPort));
  664.                 RGBForeColor(BlackRGB);
  665.                 RGBBackColor(WhiteRGB);
  666.                 TextFont(CurrentFontID);
  667.                 TextFace(CurrentStyle);
  668.                 TextSize(CurrentSize);
  669.             end;
  670.         with info^ do begin
  671.                 if (not RoiShowing) or (RoiShowing and (RoiType <> RectRoi)) then begin
  672.                         KillRoi;
  673.                         nTextLines := 1;
  674.                         MaxLineWidth := 10;
  675.                         LineStart := 1;
  676.                         LineEnd := 0;
  677.                         repeat
  678.                             LineEnd := LineEnd + 1;
  679.                             if TextBufP^[LineEnd] = CR then begin
  680.                                     nTextLines := nTextLines + 1;
  681.                                     LineWidth := TextWidth(ptr(TextBufP), LineStart - 1, LineEnd - LineStart);
  682.                                     if LineWidth > MaxLineWidth then
  683.                                         MaxLineWidth := LineWidth;
  684.                                     LineStart := LineEnd;
  685.                                 end;
  686.                         until LineEnd >= TextBufSize;
  687.                         if LineEnd > LineStart then begin
  688.                                 LineWidth := TextWidth(ptr(TextBufP), LineStart - 1, LineEnd - LineStart);
  689.                                 if LineWidth > MaxLineWidth then
  690.                                     MaxLineWidth := LineWidth;
  691.                             end;
  692.                         height := nTextLines * CurrentSize + CurrentSize div 4;
  693.                         MaxRectHeight := (PicRect.bottom * 2) div 3;
  694.                         if height > MaxRectHeight then
  695.                             height := MaxRectHeight;
  696.                         MaxLineWidth := MaxLineWidth + CurrentSize div 2;
  697.                         MaxRectWidth := (PicRect.right * 2) div 3;
  698.                         if MaxLineWidth > MaxRectWidth then begin
  699.                                 MaxLineWidth := MaxRectWidth;
  700.                                 height := MaxRectHeight;
  701.                             end;
  702.                         with RoiRect do begin
  703.                                 left := 0;
  704.                                 top := 0;
  705.                                 right := MaxLineWidth;
  706.                                 bottom := height;
  707.                             end;
  708.                         RoiType := RectRoi;
  709.                         MakeRegion;
  710.                     end;
  711.                 CopyImage;
  712.                 WhatsOnClip := TextOnClip;
  713.             end;
  714.         SetRectRgn(ClipBufInfo^.osPort^.ClipRgn, 0, 0, 30000, 30000);  {Why is this needed?}
  715.         TextBox(ptr(TextBufP), TextBufSize, ClipBufInfo^.RoiRect, TextJust);
  716.         PastePicture;
  717.     end;
  718.  
  719.  
  720.     procedure DoPaste;
  721.         var
  722.             NewScrapCount: integer;
  723.     begin
  724.         if (info = NoInfo) and (WhatsOnClip <> aColor) then begin
  725.                 PutMessage('You must have an image window open in order to paste.');
  726.                 exit(DoPaste);
  727.             end;
  728.         RoiUpdateTime := 0;
  729.         NewScrapCount := GetScrapCount;
  730.         if NewScrapCount <> OldScrapCount then begin
  731.                 WhatsOnClip := Nothing;
  732.                 OldScrapCount := NewScrapCount;
  733.             end;
  734.         case WhatsOnClip of
  735.             AColor: 
  736.                 PasteColor;
  737.             RectPic, NonRectPic, ImportedPic, CameraPic: 
  738.                 PastePicture;
  739.             TextOnClip: 
  740.                 PasteText;
  741.             Nothing:  begin
  742.                     ConvertSystemClipboard;
  743.                     if WhatsOnClip = ImportedPic then
  744.                         PastePicture
  745.                     else if WhatsOnClip = textOnClip then
  746.                         PasteText
  747.                     else
  748.                         beep;
  749.                 end;
  750.         end;
  751.     end;
  752.  
  753.  
  754.     procedure DoClear;
  755.     begin
  756.         if not NoSelection then begin
  757.                 SetupUndo;
  758.                 WhatToUndo := UndoClear;
  759.                 CurrentOp := EraseOp;
  760.                 OpPending := true;
  761.                 RoiUpdateTime := 0;
  762.             end;
  763.     end;
  764.  
  765.  
  766.     procedure DoMath;
  767.         const
  768.             PixelsPerUpdate = 15000;
  769.         var
  770.             nrows, ncols, hSrcStart, vSrcStart, hDstStart, vDstStart: integer;
  771.             SaveInfo: InfoPtr;
  772.             h, v, vDst, PixelCount, offset: integer;
  773.             Src, Dst: LineType;
  774.             tmp, range, min, max, StartTicks: LongInt;
  775.             x, xmax, xmin, xrange, xscale: extended;
  776.     begin
  777.         if TooWide then
  778.             exit(DoMath);
  779.         ShowWatch;
  780.         OpPending := false;
  781.         WhatToUndo := UndoPaste;
  782.         KillRoi;
  783.         with info^.RoiRect do begin
  784.                 ncols := right - left;
  785.                 nrows := bottom - top;
  786.                 hDstStart := left;
  787.                 vDstStart := top;
  788.             end;
  789.         with ClipBufInfo^.RoiRect do begin
  790.                 hSrcStart := left;
  791.                 vSrcStart := top;
  792.             end;
  793.         if hDstStart < 0 then begin
  794.                 offset := -hDstStart;
  795.                 hDstStart := 0;
  796.                 hSrcStart := hSrcStart + offset;
  797.                 ncols := ncols - offset;
  798.             end;
  799.         if vDstStart < 0 then begin
  800.                 offset := -vDstStart;
  801.                 vDstStart := 0;
  802.                 vSrcStart := vSrcStart + offset;
  803.                 nrows := nrows - offset;
  804.             end;
  805.         with info^.PicRect do begin
  806.                 if hDstStart + ncols > right then
  807.                     ncols := right - hDstStart;
  808.                 if vDstStart + nrows > bottom then
  809.                     nrows := bottom - vDstStart;
  810.             end;
  811.         SaveInfo := info;
  812.         vDst := vDstStart;
  813.         min := 999999;
  814.         max := -999999;
  815.         xmin := 999999.0;
  816.         xmax := -999999.0;
  817.         StartTicks := TickCount;
  818.        {First pass to find result range}
  819.         if ScaleArithmetic then begin
  820.                 for v := vSrcStart to vSrcStart + nRows - 1 do begin
  821.                         Info := ClipBufInfo;
  822.                         GetLine(hSrcStart, v, nCols, Src);
  823.                         Info := SaveInfo;
  824.                         GetLine(hDstStart, vDst, nCols, Dst);
  825.                         case CurrentOp of
  826.                             AddOp:  begin
  827.                                     for h := 0 to nCols - 1 do begin
  828.                                             tmp := Src[h] + Dst[h];
  829.                                             if tmp > max then
  830.                                                 max := tmp;
  831.                                             if tmp < Min then
  832.                                                 min := tmp;
  833.                                         end;
  834.                                 end;
  835.                             SubtractOp:  begin
  836.                                     for h := 0 to nCols - 1 do begin
  837.                                             tmp := Dst[h] - Src[h];
  838.                                             if tmp > max then
  839.                                                 max := tmp;
  840.                                             if tmp < Min then
  841.                                                 min := tmp;
  842.                                         end;
  843.                                 end;
  844.                             MultiplyOp:  begin
  845.                                     for h := 0 to nCols - 1 do begin
  846.                                             tmp := LongInt(Dst[h]) * Src[h];
  847.                                             if tmp > max then
  848.                                                 max := tmp;
  849.                                             if tmp < min then
  850.                                                 min := tmp;
  851.                                         end;
  852.                                 end;
  853.                             DivideOp:  begin
  854.                                     for h := 0 to nCols - 1 do begin
  855.                                             tmp := Src[h];
  856.                                             if tmp = 0 then
  857.                                                 tmp := 1;
  858.                                             x := Dst[h] / tmp;
  859.                                             if x > xmax then begin
  860.                                                     xmax := x;
  861.                                                 end;
  862.                                             if x < xmin then
  863.                                                 xmin := x;
  864.                                         end;
  865.                                 end;
  866.                         end;
  867.                         vDst := vDst + 1;
  868.                     end;
  869.                 vDst := vDstStart;
  870.                 if CurrentOp = DivideOp then begin
  871.                         xrange := xmax - xmin;
  872.                         if xrange <> 0.0 then
  873.                             xscale := 256.0 / xrange
  874.                         else
  875.                             xscale := 1;
  876.                     end
  877.                 else
  878.                     range := max - min;
  879.             end; {if ScaleArithmetic=true}
  880.         PixelCount := 0;
  881.        {Second pass to do arithmetic and scaling}
  882.         for v := vSrcStart to vSrcStart + nRows - 1 do begin
  883.                 Info := ClipBufInfo;
  884.                 GetLine(hSrcStart, v, nCols, Src);
  885.                 Info := SaveInfo;
  886.                 GetLine(hDstStart, vDst, nCols, Dst);
  887.                 case CurrentOp of
  888.                     AddOp: 
  889.                         if ScaleArithmetic then
  890.                             for h := 0 to nCols - 1 do begin
  891.                                     tmp := Dst[h] + Src[h] - min;
  892.                                     if range <> 0 then
  893.                                         tmp := tmp * 256 div range
  894.                                     else
  895.                                         tmp := BackgroundIndex;
  896.                                     if tmp > 255 then
  897.                                         dst[h] := 255
  898.                                     else
  899.                                         dst[h] := tmp;
  900.                                 end
  901.                         else
  902.                             for h := 0 to nCols - 1 do begin
  903.                                     tmp := Dst[h] + Src[h];
  904.                                     if tmp > 255 then
  905.                                         dst[h] := 255
  906.                                     else
  907.                                         dst[h] := tmp;
  908.                                 end;
  909.                     SubtractOp: 
  910.                         if ScaleArithmetic then
  911.                             for h := 0 to nCols - 1 do begin
  912.                                     tmp := Dst[h] - Src[h] - min;
  913.                                     if range <> 0 then
  914.                                         tmp := tmp * 256 div range
  915.                                     else
  916.                                         tmp := BackgroundIndex;
  917.                                     if tmp > 255 then
  918.                                         dst[h] := 255
  919.                                     else
  920.                                         dst[h] := tmp;
  921.                                 end
  922.                         else
  923.                             for h := 0 to nCols - 1 do begin
  924.                                     tmp := Dst[h] - Src[h];
  925.                                     if tmp < 0 then
  926.                                         dst[h] := 0
  927.                                     else
  928.                                         dst[h] := tmp;
  929.                                 end;
  930.                     MultiplyOp: 
  931.                         if ScaleArithmetic then
  932.                             for h := 0 to nCols - 1 do begin
  933.                                     tmp := LongInt(Dst[h]) * Src[h] - min;
  934.                                     if range <> 0 then
  935.                                         tmp := tmp * 256 div range
  936.                                     else
  937.                                         tmp := BackgroundIndex;
  938.                                     if tmp > 255 then
  939.                                         dst[h] := 255
  940.                                     else
  941.                                         dst[h] := tmp;
  942.                                 end
  943.                         else
  944.                             for h := 0 to nCols - 1 do begin
  945.                                     tmp := LongInt(Dst[h]) * Src[h];
  946.                                     if tmp > 255 then
  947.                                         dst[h] := 255
  948.                                     else
  949.                                         dst[h] := tmp;
  950.                                 end;
  951.                     DivideOp: 
  952.                         if ScaleArithmetic then
  953.                             for h := 0 to nCols - 1 do begin
  954.                                     tmp := Src[h];
  955.                                     if tmp = 0 then
  956.                                         tmp := 1;
  957.                                     x := Dst[h] / tmp - xmin;
  958.                                     if xrange <> 0.0 then
  959.                                         tmp := trunc(x * xscale)
  960.                                     else
  961.                                         tmp := BackgroundIndex;
  962.                                     if tmp > 255 then
  963.                                         tmp := 255;
  964.                                     if tmp < 0 then
  965.                                         tmp := 0;
  966.                                     dst[h] := tmp;
  967.                                 end
  968.                         else
  969.                             for h := 0 to nCols - 1 do begin
  970.                                     tmp := Src[h];
  971.                                     if tmp = 0 then
  972.                                         tmp := 1;
  973.                                     dst[h] := Dst[h] div tmp;
  974.                                 end;
  975.                 end;
  976.                 PutLine(hDstStart, vDst, nCols, Dst);
  977.                 vDst := vDst + 1;
  978.                 PixelCount := PixelCount + ncols;
  979.                 if PixelCount > PixelsPerUpdate then begin
  980.                         UpdateScreen(info^.RoiRect);
  981.                         if CommandPeriod then begin
  982.                                 UpdateScreen(info^.RoiRect);
  983.                                 beep;
  984.                                 exit(DoMath)
  985.                             end;
  986.                         PixelCount := 0;
  987.                     end;
  988.             end;
  989.         with info^ do begin
  990.                 ShowTime(StartTicks, RoiRect, '');
  991.                 UpdateScreen(RoiRect);
  992.             end;
  993.     end;
  994.  
  995.  
  996.     procedure SetPasteMode (item: integer);
  997.         var
  998.             SavePort: GrafPtr;
  999.             BlendColor: rgbColor;
  1000.     begin
  1001.         if not macro then begin
  1002.                 SetForegroundColor(BlackIndex);
  1003.                 SetBackGroundColor(WhiteIndex);
  1004.             end;
  1005.         case Item of
  1006.             CopyModeItem: 
  1007.                 PasteTransferMode := SrcCopy;
  1008.             AndItem: 
  1009.                 PasteTransferMode := NotSrcBic; {And}
  1010.             OrItem: 
  1011.                 PasteTransferMode := SrcOr;
  1012.             XorItem: 
  1013.                 PasteTransferMode := SrcXor;
  1014.             ReplaceItem: 
  1015.                 PasteTransferMode := Transparent;
  1016.             BlendItem:  begin
  1017.                     GetPort(SavePort);
  1018.                     with BlendColor do begin
  1019.                             red := 32767;
  1020.                             blue := 32767;
  1021.                             green := 32767;
  1022.                         end;
  1023.                     SetPort(GrafPtr(info^.osPort));
  1024.                     OpColor(BlendColor);
  1025.                     SetPort(SavePort);
  1026.                     PasteTransferMode := Blend;
  1027.                 end;
  1028.         end; {case}
  1029.     end;
  1030.  
  1031.  
  1032.     function GetTransferModeItem: integer;
  1033.     begin
  1034.         case PasteTransferMode of
  1035.             SrcCopy: 
  1036.                 GetTransferModeItem := CopyModeItem;
  1037.             NotSrcBic: 
  1038.                 GetTransferModeItem := AndItem;
  1039.             SrcOr: 
  1040.                 GetTransferModeItem := OrItem;
  1041.             SrcXor: 
  1042.                 GetTransferModeItem := XorItem;
  1043.             Transparent: 
  1044.                 GetTransferModeItem := ReplaceItem;
  1045.             Blend: 
  1046.                 GetTransferModeItem := BlendItem;
  1047.         end;
  1048.     end;
  1049.  
  1050.  
  1051.     procedure DrawPasteControl;
  1052.         const
  1053.             bWidth = 64;
  1054.             bHeight = 14;
  1055.             vinc = 18;
  1056.             bhloc = 114;
  1057.             bvloc = 6;
  1058.         var
  1059.             tPort: GrafPtr;
  1060.             i, hloc, vloc, item: integer;
  1061.             tType: pcItemType;
  1062.             tRect: rect;
  1063.             ItemStr: str255;
  1064.     begin
  1065.         GetPort(tPort);
  1066.         SetPort(PasteControl);
  1067.         with PcItem[1] do begin
  1068.                 SetRect(r, 15, 22, 87, 40);
  1069.                 itype := pcPopupMenu;
  1070.                 str := 'Transfer Mode';
  1071.             end;
  1072.         with pcItem[2] do begin
  1073.                 SetRect(r, 88, 50, 100, 62);
  1074.                 itype := pcCheckBox;
  1075.                 str := 'Scale Math';
  1076.             end;
  1077.         with pcItem[3] do begin
  1078.                 SetRect(r, 88, 65, 100, 77);
  1079.                 itype := pcCheckBox;
  1080.                 str := 'Live Paste';
  1081.             end;
  1082.         hloc := bhloc;
  1083.         vloc := bvloc;
  1084.         tType := pcButton;
  1085.         with pcItem[4] do begin
  1086.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1087.                 itype := tType;
  1088.                 str := 'Add';
  1089.             end;
  1090.         vloc := vloc + vinc;
  1091.         with pcItem[5] do begin
  1092.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1093.                 itype := tType;
  1094.                 str := 'Subtract';
  1095.             end;
  1096.         vloc := vloc + vinc;
  1097.         with pcItem[6] do begin
  1098.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1099.                 itype := tType;
  1100.                 str := 'Multiply';
  1101.             end;
  1102.         vloc := vloc + vinc;
  1103.         with pcItem[7] do begin
  1104.                 SetRect(r, hloc, vloc, hloc + bWidth, vloc + bHeight);
  1105.                 itype := tType;
  1106.                 str := 'Divide';
  1107.             end;
  1108.         TextFont(SystemFont);
  1109.         TextSize(12);
  1110.         for i := 1 to npcItems do
  1111.             with pcItem[i] do
  1112.                 case iType of
  1113.                     pcPopupMenu: 
  1114.                         with r do begin
  1115.                                 MoveTo(r.left - 10, r.top - 4);
  1116.                                 DrawString(str);
  1117.                                 EraseRect(r);
  1118.                                 FrameRect(r);
  1119.                                 MoveTo(left + 2, bottom);
  1120.                                 LineTo(right, bottom);
  1121.                                 MoveTo(right, top + 2);
  1122.                                 LineTo(right, bottom);
  1123.                                 item := GetTransferModeItem;
  1124.                                 GetItem(TransferModeMenuH, item, ItemStr);
  1125.                                 MoveTo(left + 13, bottom - 5);
  1126.                                 DrawString(ItemStr);
  1127.                             end;
  1128.                     pcCheckBox: 
  1129.                         with r do begin
  1130.                                 MoveTo(left - StringWidth(str) - 4, bottom - 2);
  1131.                                 DrawString(str);
  1132.                                 EraseRect(r);
  1133.                                 FrameRect(r);
  1134.                                 if ((i = 2) and ScaleArithmetic) or ((i = 3) and LivePasteMode) then begin
  1135.                                         MoveTo(left, top);
  1136.                                         LineTo(right - 1, bottom - 1);
  1137.                                         MoveTo(left, bottom - 1);
  1138.                                         LineTo(right - 1, top);
  1139.                                     end;
  1140.                             end;
  1141.                     pcButton:  begin
  1142.                             FrameRoundRect(r, 6, 6);
  1143.                             with r do
  1144.                                 MoveTo(left + ((right - left) - StringWidth(str)) div 2, bottom - 3);
  1145.                             DrawString(str);
  1146.                         end;
  1147.                 end; {case}
  1148.         SetPort(tPort);
  1149.     end;
  1150.  
  1151.  
  1152.     procedure DoMouseDownInPasteControl; {(loc:point)}
  1153.         var
  1154.             nItem, i, MenuItem: integer;
  1155.             PopupResult: LongInt;
  1156.             MenuLoc: point;
  1157.             tr: rect;
  1158.     begin
  1159.         if not (OpPending and (CurrentOp = PasteOp)) then begin
  1160.                 PutMessage('Paste Control is only available during paste operations.');
  1161.                 exit(DoMouseDownInPasteControl);
  1162.             end;
  1163.         SetPort(PasteControl);
  1164.         GlobalToLocal(loc);
  1165.         nItem := 0;
  1166.         for i := 1 to npcItems do
  1167.             if PtInRect(loc, pcItem[i].r) then
  1168.                 nitem := i;
  1169.         if nItem > 0 then begin
  1170.                 case pcItem[nItem].itype of
  1171.                     pcPopUpMenu: 
  1172.                         with pcItem[1].r, MenuLoc do begin
  1173.                                 MenuLoc.h := left;
  1174.                                 MenuLoc.v := top;
  1175.                                 LocalToGlobal(MenuLoc);
  1176.                                 PopUpResult := PopupMenuSelect(TransferModeMenuH, v, h, GetTransferModeItem);
  1177.                                 MenuItem := LoWord(PopUpResult);
  1178.                                 SetPasteMode(MenuItem);
  1179.                             end;
  1180.                     pcCheckBox:  begin
  1181.                             tr := pcItem[nItem].r;
  1182.                             InsetRect(tr, 1, 1);
  1183.                             FrameRect(tr);
  1184.                             if nitem = 2 then
  1185.                                 ScaleArithmetic := not ScaleArithmetic;
  1186.                             if nitem = 3 then
  1187.                                 LivePasteMode := not LivePasteMode;
  1188.                         end;
  1189.                     pcButton:  begin
  1190.                             InvertRoundRect(pcItem[nitem].r, 6, 6);
  1191.                             while Button and (nitem > 0) do begin
  1192.                                     GetMouse(loc);
  1193.                                     if not PtInRect(loc, pcItem[nitem].r) then begin
  1194.                                             InvertRoundRect(pcItem[nitem].r, 6, 6);
  1195.                                             nItem := 0;
  1196.                                         end;
  1197.                                 end;
  1198.                         end;
  1199.                 end; {case}
  1200.                 repeat
  1201.                 until not button;
  1202.                 if nItem > 0 then
  1203.                     with pcItem[nitem] do begin
  1204.                             case itype of
  1205.                                 pcPopupMenu: 
  1206.                                     ;
  1207.                                 pcCheckBox:  begin
  1208.                                     end;
  1209.                                 pcButton:  begin
  1210.                                         InvertRoundRect(pcItem[nitem].r, 6, 6);
  1211.                                         if info^.RoiType = RectRoi then begin
  1212.                                                 case nitem of
  1213.                                                     4: 
  1214.                                                         CurrentOp := AddOp;
  1215.                                                     5: 
  1216.                                                         CurrentOp := SubtractOp;
  1217.                                                     6: 
  1218.                                                         CurrentOp := MultiplyOp;
  1219.                                                     7: 
  1220.                                                         CurrentOp := DivideOp;
  1221.                                                 end;
  1222.                                                 DoMath;
  1223.                                             end; {if}
  1224.                                     end; {pcButton}
  1225.                             end; {case}
  1226.                         end; {with}
  1227.             end; {if nitem>0}
  1228.         if LivePasteMode and ((WhatsOnClip <> CameraPic) or (QuickCaptureInfo = nil)) then begin
  1229.                 PutMessage('"Live Paste" requires that a rectangular selection be first copied from the Camera window to the Clipboard.');
  1230.                 LivePasteMode := false;
  1231.             end;
  1232.         if LivePasteMode and (info^.PictureType = QuickCaptureType) then begin
  1233.                 PutMessage('Live pasting into the Camera window is not supported.');
  1234.                 LivePasteMode := false;
  1235.             end;
  1236.         DrawPasteControl;
  1237.     end;
  1238.  
  1239.  
  1240.     procedure ShowPasteControl;
  1241.         var
  1242.             tPort: GrafPtr;
  1243.             trect: rect;
  1244.             wp: ^WindowPtr;
  1245.     begin
  1246.         SetRect(trect, PasteControlLeft, PasteControlTop, PasteControlLeft + pcwidth, PasteControlTop + pcheight);
  1247.         PasteControl := NewWindow(nil, trect, 'Paste Control', true, rDocProc, nil, true, 0);
  1248.         WindowPeek(PasteControl)^.WindowKind := PasteControlKind;
  1249.         wp := pointer(GhostWindow);
  1250.         wp^ := PasteControl;
  1251.         PasteTransferMode := SrcCopy;
  1252.         LivePasteMode := false;
  1253.     end;
  1254.  
  1255.  
  1256.     procedure ShowClipboard;
  1257.         var
  1258.             width, height, hstart, vstart, i, NewScrapCount: integer;
  1259.     begin
  1260.         NewScrapCount := GetScrapCount;
  1261.         if NewScrapCount <> OldScrapCount then begin
  1262.                 WhatsOnClip := Nothing;
  1263.                 OldScrapCount := NewScrapCount;
  1264.             end;
  1265.         if WhatsOnClip = Nothing then
  1266.             ConvertSystemClipboard;
  1267.         if (WhatsOnClip = RectPic) or (WhatsOnClip = NonRectPic) or (WhatsOnClip = ImportedPic) or (WhatsOnClip = CameraPic) then
  1268.             with ClipBufinfo^.RoiRect do begin
  1269.                     width := right - left;
  1270.                     if odd(width) then
  1271.                         width := Width - 1;
  1272.                     height := bottom - top;
  1273.                     if NewPicWindow('Clipboard', width, height) then begin
  1274.                             PastePicture;
  1275.                             KillRoi;
  1276.                             SetupUndo;
  1277.                             info^.changes := false;
  1278.                         end;
  1279.                 end;
  1280.     end;
  1281.  
  1282.  
  1283.     procedure DoSelection (obj: ObjectType; start, finish: point);
  1284.         var
  1285.             tRect: rect;
  1286.             temp: integer;
  1287.             TempRgn: RgnHandle;
  1288.     begin
  1289.         WhatToUndo := NothingToUndo;
  1290.         Info^.RoiShowing := false;
  1291.         RoiUpdateTime := 0;
  1292.         if (start.h = finish.h) or (start.v = finish.v) then
  1293.             exit(DoSelection);
  1294.         if start.h > finish.h then begin
  1295.                 temp := start.h;
  1296.                 start.h := finish.h;
  1297.                 finish.h := temp;
  1298.             end;
  1299.         if start.v > finish.v then begin
  1300.                 temp := start.v;
  1301.                 start.v := finish.v;
  1302.                 finish.v := temp;
  1303.             end;
  1304.         Pt2Rect(start, finish, tRect);
  1305.         ScreenToOffscreenRect(tRect);
  1306.         with info^ do begin
  1307.                 RoiShowing := true;
  1308.                 if SelectionMode <> NewSelection then
  1309.                     TempRgn := NewRgn;
  1310.                 OpenRgn;
  1311.                 case obj of
  1312.                     SelectionOval:  begin
  1313.                             FrameOval(tRect);
  1314.                             roiType := OvalRoi;
  1315.                         end;
  1316.                     SelectionRect:  begin
  1317.                             FrameRect(tRect);
  1318.                             roiType := RectRoi;
  1319.                         end;
  1320.                 end;
  1321.                 if SelectionMode = NewSelection then
  1322.                     CloseRgn(roiRgn)
  1323.                 else begin
  1324.                         CloseRgn(TempRgn);
  1325.                         if RgnNotTooBig(roiRgn, TempRgn) then begin
  1326.                                 if SelectionMode = AddSelection then
  1327.                                     UnionRgn(roiRgn, TempRgn, roiRgn)
  1328.                                 else begin
  1329.                                         DiffRgn(roiRgn, TempRgn, roiRgn);
  1330.                                         UpdatePicWindow;
  1331.                                     end;
  1332.                             end;
  1333.                         DisposeRgn(TempRgn);
  1334.                         if GetHandleSize(handle(roiRgn)) = 10 then
  1335.                             roiType := RectRoi
  1336.                         else
  1337.                             roiType := RgnRoi;
  1338.                     end;
  1339.                 RoiRect := roiRgn^^.rgnBBox;
  1340.                 uLength := 0.0;
  1341.                 cLength := 0.0;
  1342.             end;{with}
  1343.         measuring := false;
  1344.     end;
  1345.  
  1346.  
  1347.     function ScreenToPixmapH (hloc: integer): real;
  1348.     begin
  1349.         with info^ do
  1350.             ScreenToPixmapH := SrcRect.left + hloc / magnification;
  1351.     end;
  1352.  
  1353.     function ScreenToPixmapV (vloc: integer): real;
  1354.     begin
  1355.         with info^ do
  1356.             ScreenToPixmapV := SrcRect.top + vloc / magnification;
  1357.     end;
  1358.  
  1359.  
  1360.     procedure DoObject; {(obj: ObjectType; event: EventRecord)}
  1361.         var
  1362.             Start, Finish, ScreenStart, ScreenFinish, osStart, osFinish: point;
  1363.             r: rect;
  1364.             ff, DeltaX, DeltaY, switch, imag: integer;
  1365.             Constrain: boolean;
  1366.             StartH, StartV: real;
  1367.     begin
  1368.         SetPort(info^.wptr);
  1369.         if (obj = PlotLine) or (obj = LineObj) then
  1370.             DrawLabels('DX:', 'DY:', 'Length:')
  1371.         else
  1372.             DrawLabels('Width:', 'Height:', '');
  1373.         start := event.where;
  1374.         StartH := ScreenToPixmapH(start.h);
  1375.         StartV := ScreenToPixmapV(start.v);
  1376.         osStart := start;
  1377.         ScreenToOffscreen(osStart);
  1378.         finish := start;
  1379.         osFinish := finish;
  1380.         ScreenToOffscreen(osFinish);
  1381.         PenNormal;
  1382.         PenMode(PatXor);
  1383.         with info^ do begin
  1384.                 imag := trunc(magnification + 0.5);
  1385.                 ff := imag div 2;
  1386.                 if (obj = SelectionRect) or (obj = SelectionOval) then
  1387.                     PenSize(imag, imag)
  1388.                 else
  1389.                     PenSize(imag * LineWidth, imag * LineWidth);
  1390.                 if (CurrentTool = LineTool) and (LineWidth = 1) then begin
  1391.                         PenSize(1, 1);
  1392.                         ff := 0;
  1393.                     end;
  1394.             end;
  1395.         while button do begin
  1396.                 GetMouse(finish);
  1397.                 with finish, Info^ do begin
  1398.                         if h > wrect.right then
  1399.                             h := wrect.right;
  1400.                         if v > wrect.bottom then
  1401.                             v := wrect.bottom;
  1402.                         if h < 0 then
  1403.                             h := 0;
  1404.                         if v < 0 then
  1405.                             v := 0;
  1406.                     end;
  1407.                 if ShiftKeyDown then begin
  1408.                         DeltaX := finish.h - start.h;
  1409.                         DeltaY := finish.v - start.v;
  1410.                         if (obj = lineObj) or (obj = PlotLine) then begin
  1411.                                 if abs(DeltaX) > abs(DeltaY) then
  1412.                                     finish.v := start.v
  1413.                                 else
  1414.                                     finish.h := start.h
  1415.                             end
  1416.                         else begin
  1417.                                 if ((DeltaX > 0) and (DeltaY < 0)) or ((DeltaX < 0) and (DeltaY > 0)) then
  1418.                                     switch := -1
  1419.                                 else
  1420.                                     switch := 1;
  1421.                                 if abs(DeltaX) > abs(DeltaY) then
  1422.                                     finish.h := start.h + switch * DeltaY
  1423.                                 else
  1424.                                     finish.v := start.v + switch * DeltaX;
  1425.                             end;
  1426.                     end;
  1427.                 osFinish := finish;
  1428.                 ScreenToOffscreen(osfinish);
  1429.                 case obj of
  1430.                     LineObj, PlotLine:  begin
  1431.                             MoveTo(start.h - ff, start.v - ff);
  1432.                             LineTo(finish.h - ff, finish.v - ff);
  1433.                             ShowDxDy(abs(ScreenToPixMapH(finish.h) - StartH), abs(ScreenToPixMapV(finish.v) - StartV));
  1434.                             MoveTo(start.h - ff, start.v - ff);
  1435.                             LineTo(finish.h - ff, finish.v - ff);
  1436.                         end;
  1437.                     Rectangle, SelectionRect:  begin
  1438.                             if obj = SelectionRect then begin
  1439.                                     PatIndex := (PatIndex + 1) mod 8;
  1440.                                     PenPat(pat[PatIndex]);
  1441.                                 end;
  1442.                             Pt2Rect(start, finish, r);
  1443.                             OffsetRect(r, -ff, -ff);
  1444.                             FrameRect(r);
  1445.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  1446.                             Pt2Rect(start, finish, r);
  1447.                             OffsetRect(r, -ff, -ff);
  1448.                             FrameRect(r);
  1449.                         end;
  1450.                     SelectionOval:  begin
  1451.                             PatIndex := (PatIndex + 1) mod 8;
  1452.                             PenPat(pat[PatIndex]);
  1453.                             Pt2Rect(start, finish, r);
  1454.                             OffsetRect(r, -ff, -ff);
  1455.                             FrameOval(r);
  1456.                             Show3Values(osfinish.h - osstart.h, osfinish.v - osstart.v, -1);
  1457.                             Pt2Rect(start, finish, r);
  1458.                             OffsetRect(r, -ff, -ff);
  1459.                             FrameOval(r);
  1460.                         end;
  1461.                 end; {case}
  1462.             end;  {while button}
  1463.         if (obj = SelectionRect) or (obj = SelectionOval) then begin
  1464.                 DoSelection(obj, start, finish);
  1465.                 exit(DoObject);
  1466.             end;
  1467.         if (obj = LineObj) and (CurrentTool = LineTool) then begin
  1468.                 MoveTo(start.h - ff, start.v - ff);
  1469.                 LineTo(finish.h - ff, finish.v - ff);
  1470.                 with info^ do begin
  1471.                         LX1 := StartH;
  1472.                         LY1 := StartV;
  1473.                         LX2 := ScreenToPixmapH(finish.h);
  1474.                         LY2 := ScreenToPixmapV(finish.v);
  1475.                     end;
  1476.                 exit(DoObject);
  1477.             end;
  1478.         if obj = PlotLine then begin
  1479.                 DoProfilePlot(osStart, osFinish);
  1480.                 exit(DoObject)
  1481.             end;
  1482.         DrawObject(obj, start, finish);
  1483.     end;
  1484.  
  1485.  
  1486.     procedure DrawAirBrush (xcenter, ycenter: integer);
  1487.         var
  1488.             i, xoffset, yoffset, nDots: integer;
  1489.     begin
  1490.         nDots := AirBrushDiameter div 4;
  1491.         if nDots < 15 then
  1492.             nDots := 15;
  1493.         for i := 1 to nDots do begin
  1494.                 repeat
  1495.                     xoffset := random mod AirBrushRadius;
  1496.                     yoffset := random mod AirBrushRadius;
  1497.                 until xoffset * xoffset + yoffset * yoffset <= AirBrushRadius2;
  1498.                 PutPixel(xcenter + xoffset, ycenter + yoffset, ForegroundIndex);
  1499.             end;
  1500.     end;
  1501.  
  1502.  
  1503.     procedure DoAirBrush;
  1504.   {Reference: "Spaying and Smudging", Dick Pountain, Byte, November 1987}
  1505.         var
  1506.             xcenter, ycenter, off: integer;
  1507.             MaskRect: rect;
  1508.             pt: point;
  1509.     begin
  1510.         info^.changes := true;
  1511.         off := AirbrushRadius;
  1512.         repeat
  1513.             GetMouse(pt);
  1514.             ScreenToOffscreen(pt);
  1515.             with MaskRect, pt do begin
  1516.                     left := h - off;
  1517.                     top := v - off;
  1518.                     right := h + off;
  1519.                     bottom := v + off;
  1520.                 end;
  1521.             with pt do begin
  1522.                     xcenter := h;
  1523.                     ycenter := v
  1524.                 end;
  1525.             DrawAirbrush(xcenter, ycenter);
  1526.             UpdateScreen(MaskRect);
  1527.         until not button;
  1528.         WhatToUndo := UndoEdit;
  1529.     end;
  1530.  
  1531.  
  1532.     procedure DoBrush; {(event: EventRecord)}
  1533.         var
  1534.             r, ScreenRect: rect;
  1535.             p1, p2, p2x, start: point;
  1536.             WhichWindow: WindowPtr;
  1537.             SaveLineWidth, SaveForegroundColor: integer;
  1538.             Constrained, MoreHorizontal, FirstTime: boolean;
  1539.             offset, width: integer;
  1540.     begin
  1541.         SaveLineWidth := LineWidth;
  1542.         p1 := event.where;
  1543.         start := p1;
  1544.         if OptionKeyDown then begin
  1545.                 case CurrentTool of
  1546.                     Brush, Pencil: 
  1547.                         GetForegroundColor(event);
  1548.                     Eraser: 
  1549.                         GetBackgroundColor(event);
  1550.                 end;
  1551.                 if (CurrentTool = Brush) or (CurrentTool = Eraser) then
  1552.                     exit(DoBrush);
  1553.             end;
  1554.         case CurrentTool of
  1555.             Pencil: 
  1556.                 LineWidth := 1;
  1557.             Brush, Eraser:  begin
  1558.                     if CurrentTool = Brush then
  1559.                         width := BrushWidth
  1560.                     else
  1561.                         width := 16;
  1562.                     LineWidth := round(width / info^.magnification);
  1563.                     if LineWidth < 1 then
  1564.                         LineWidth := 1;
  1565.                 end;
  1566.         end;
  1567.         with info^ do
  1568.             offset := round((LineWidth - 1) * info^.magnification / 2.0);
  1569.         if CurrentTool <> Pencil then
  1570.             with p1 do begin
  1571.                     h := h - offset;
  1572.                     v := v - offset
  1573.                 end;
  1574.         Constrained := ShiftKeyDown;
  1575.         FirstTime := true;
  1576.         if CurrentTool = eraser then begin
  1577.                 SaveForegroundColor := ForegroundIndex;
  1578.                 SetForegroundColor(BackgroundIndex)
  1579.             end;
  1580.         repeat
  1581.             GetMouse(p2);
  1582.             if CurrentTool <> Pencil then
  1583.                 with p2 do begin
  1584.                         h := h - offset;
  1585.                         v := v - offset
  1586.                     end;
  1587.             if FirstTime then
  1588.                 if not EqualPt(p1, p2) then begin
  1589.                         MoreHorizontal := abs(p2.h - p1.h) >= abs(p2.v - p1.v);
  1590.                         FirstTime := false;
  1591.                     end;
  1592.             if Constrained then
  1593.                 if MoreHorizontal then
  1594.                     p2.v := p1.v
  1595.                 else
  1596.                     p2.h := p1.h;
  1597.             if CurrentTool = brush then
  1598.                 DrawObject(BrushObj, p1, p2)
  1599.             else
  1600.                 DrawObject(LineObj, p1, p2);
  1601.             p1 := p2;
  1602.         until not button;
  1603.         if CurrentTool = Eraser then
  1604.             SetForegroundColor(SaveForegroundColor);
  1605.         LineWidth := SaveLineWidth;
  1606.         WhatToUndo := UndoEdit;
  1607.     end;
  1608.  
  1609.  
  1610.     procedure DrawCharacter; {(ch: char)}
  1611.         var
  1612.             str: str255;
  1613.     begin
  1614.         if Info = NoInfo then begin
  1615.                 beep;
  1616.                 exit(DrawCharacter)
  1617.             end;
  1618.         if ch = cr then
  1619.             with InsertionPoint do begin
  1620.                     h := TextStart.h;
  1621.                     v := v + CurrentSize;
  1622.                     SetupUndo;
  1623.                     TextStr := '';
  1624.                     TextStart := InsertionPoint;
  1625.                     exit(DrawCharacter)
  1626.                 end;
  1627.         if ch = BackSpace then
  1628.             with InsertionPoint do begin
  1629.                     if length(TextStr) > 0 then begin
  1630.                             delete(TextStr, length(TextStr), 1);
  1631.                             DisplayText(true);
  1632.                         end;
  1633.                     exit(DrawCharacter)
  1634.                 end;
  1635.         str := ' '; {Needed for MPW}
  1636.         str[1] := ch;
  1637.         TextStr := Concat(TextStr, str);
  1638.         DisplayText(true);
  1639.     end;
  1640.  
  1641.  
  1642.     procedure DoText; {(loc: point)}
  1643.   {Handles text tool mouse clicks.}
  1644.         var
  1645.             value: extended;
  1646.             str: str255;
  1647.             isValue: boolean;
  1648.     begin
  1649.         ScreenToOffscreen(loc);
  1650.         with loc do begin
  1651.                 InsertionPoint.h := h;
  1652.                 InsertionPoint.v := v + 4;
  1653.             end;
  1654.         IsInsertionPoint := true;
  1655.         TextStart := InsertionPoint;
  1656.         TextStr := '';
  1657.         if OptionKeyDown then
  1658.             with info^ do begin
  1659.                     isValue := true;
  1660.                     if (PreviousTool = LineTool) and (nLengths > 0) then
  1661.                         value := plength^[mCount2]
  1662.                     else if (PreviousTool = AngleTool) and (nAngles > 0) then
  1663.                         value := orientation^[mCount2]
  1664.                     else if mCount > 0 then
  1665.                         if AreaM in Measurements then
  1666.                             value := mArea^[mCount2]
  1667.                         else if MeanM in Measurements then
  1668.                             value := mean^[mCount2]
  1669.                         else
  1670.                             isValue := false;
  1671.                     if isValue then begin
  1672.                             RealToString(value, 1, precision, str);
  1673.                             if mCount2 > 0 then
  1674.                                 mCount2 := mCount2 - 1;
  1675.                             DrawTextString(str, TextStart, TextJust);
  1676.                         end;
  1677.                 end;
  1678.         WhatToUndo := UndoEdit;
  1679.     end;
  1680.  
  1681.  
  1682.     procedure DoFill (event: EventRecord);
  1683.         var
  1684.             loc: point;
  1685.             MaskBits: BitMap;
  1686.             BitMapSize: LongInt;
  1687.             tPort: GrafPtr;
  1688.             trect: rect;
  1689.     begin
  1690.         ShowWatch;
  1691.         loc := event.where;
  1692.         ScreenToOffscreen(loc);
  1693.         with info^ do begin
  1694.                 tRect := PicRect;
  1695.                 with tRect do
  1696.                     if (right mod 16 <> 0) and not Has32BitQuickDraw then
  1697.                         right := (right div 16) * 16 + 16;  {Workaround for SeedCFill bug that results in  garbage along right edge.}
  1698.                 with MaskBits do begin
  1699.                         RowBytes := PixelsPerLine div 8 + 1;
  1700.                         if odd(RowBytes) then
  1701.                             RowBytes := RowBytes + 1;
  1702.                         bounds := tRect;
  1703.                         BitMapSize := LongInt(rowBytes) * nLines;
  1704.                         baseAddr := NewPtr(BitMapSize);
  1705.                         if baseAddr = nil then begin
  1706.                                 beep;
  1707.                                 exit(DoFill)
  1708.                             end;
  1709.                     end;
  1710.                 GetPort(tPort);
  1711.                 SetPort(GrafPtr(osPort));
  1712.                 SeedCFill(BitMapHandle(osPort^.PortPixMap)^^, MaskBits, tRect, tRect, loc.h, loc.v, nil, 0);
  1713.                 CopyBits(MaskBits, BitMapHandle(osPort^.PortPixMap)^^, tRect, tRect, SrcOr, nil);
  1714.                 DisposPtr(MaskBits.baseAddr);
  1715.                 changes := true;
  1716.             end; {with}
  1717.         SetPort(tPort);
  1718.         UpdatePicWindow;
  1719.         WhatToUndo := UndoEdit;
  1720.     end;
  1721.  
  1722.  
  1723.     procedure SetAirbrushSize;
  1724.         var
  1725.             TempSize: integer;
  1726.             Canceled: boolean;
  1727.     begin
  1728.         TempSize := GetInt('Airbrush diameter in pixels(2-362):', AirbrushDiameter, Canceled);
  1729.         if Canceled then
  1730.             exit(SetAirBrushSize);
  1731.         if (TempSize > 1) and (TempSize <= 362) then begin
  1732.                 AirbrushDiameter := TempSize;
  1733.                 AirbrushRadius := AirbrushDiameter div 2;
  1734.                 AirbrushRadius2 := AirbrushRadius * AirBrushRadius
  1735.             end
  1736.         else
  1737.             beep;
  1738.     end;
  1739.  
  1740.  
  1741.     procedure SetBrushSize;
  1742.         var
  1743.             TempSize: integer;
  1744.             Canceled: boolean;
  1745.     begin
  1746.         TempSize := GetInt('Brush Size in pixels(1..99):', BrushWidth, Canceled);
  1747.         if Canceled then
  1748.             exit(SetBrushSize);
  1749.         if (TempSize > 0) and (TempSize < 100) then begin
  1750.                 BrushWidth := TempSize;
  1751.                 BrushHeight := BrushWidth
  1752.             end
  1753.         else
  1754.             beep;
  1755.     end;
  1756.  
  1757.  
  1758.     procedure FindWhatToCopy;
  1759.         var
  1760.             kind: integer;
  1761.             WhichWindow: WindowPtr;
  1762.     begin
  1763.         WhatToCopy := NothingToCopy;
  1764.         if CurrentTool = PickerTool then
  1765.             WhatToCopy := CopyColor
  1766.         else begin
  1767.                 WhichWindow := FrontWindow;
  1768.                 kind := WindowPeek(WhichWindow)^.WindowKind;
  1769.                 if (kind = PicKind) and measuring then
  1770.                     kind := ValuesKind;
  1771.                 case kind of
  1772.                     PicKind: 
  1773.                         with info^, info^.RoiRect do
  1774.                             if RoiShowing and (left >= 0) and (top >= 0) and (right <= PicRect.right) and (bottom <= PicRect.bottom) then
  1775.                                 WhatToCopy := CopySelection;
  1776.                     HistoKind: 
  1777.                         WhatToCopy := CopyHistogram;
  1778.                     ProfilePlotKind: 
  1779.                         WhatToCopy := CopyPlot;
  1780.                     CalibrationPlotKind: 
  1781.                         WhatToCopy := CopyCalibrationPlot;
  1782.                     LUTKind: 
  1783.                         if info <> NoInfo then
  1784.                             WhatToCopy := CopyCLUT;
  1785.                     MapKind: 
  1786.                         if info <> NoInfo then
  1787.                             WhatToCopy := CopyGrayMap;
  1788.                     ToolKind: 
  1789.                         WhatToCopy := CopyTools;
  1790.                     ValuesKind, ResultsKind: 
  1791.                         WhatToCopy := CopyMeasurements;
  1792.                     otherwise
  1793.                 end;
  1794.             end;
  1795.     end;
  1796.  
  1797.  
  1798.     procedure UpdateEditMenu;
  1799.         var
  1800.             DimUndo, ShowItems: boolean;
  1801.             str: str255;
  1802.             kind, i: integer;
  1803.             WhichWindow: WindowPtr;
  1804.     begin
  1805.         with info^ do begin
  1806.                 WhichWindow := FrontWindow;
  1807.                 kind := WindowPeek(WhichWindow)^.WindowKind;
  1808.                 if kind < 0 then begin   {DA is active, so activate Edit menu.}
  1809.                         SetItem(EditMenuH, UndoItem, 'Undo');
  1810.                         SetItem(EditMenuH, CutItem, 'Cut');
  1811.                         SetItem(EditMenuH, CopyItem, 'Copy');
  1812.                         SetMenuItem(EditMenuH, UndoItem, true);
  1813.                         for i := CutItem to ClearItem do
  1814.                             SetMenuItem(EditMenuH, i, true);
  1815.                         exit(UpdateEditMenu);
  1816.                     end;
  1817.                 if (info = NoInfo) and (WhatToUndo <> UndoLUT) then
  1818.                     WhatToUndo := NothingToUndo;
  1819.                 DimUndo := WhatToUndo = NothingToUndo;
  1820.                 SetMenuItem(EditMenuH, UndoItem, not DimUndo);
  1821.                 if DimUndo then
  1822.                     SetItem(EditMenuH, UndoItem, 'Undo');
  1823.                 case WhatToUndo of
  1824.                     UndoEdit: 
  1825.                         str := 'Editing';
  1826.                     UndoFlip: 
  1827.                         str := 'Flip';
  1828.                     UndoRotate: 
  1829.                         str := 'Rotate';
  1830.                     UndoFilter: 
  1831.                         str := 'Filtering';
  1832.                     UndoPaste: 
  1833.                         str := 'Paste';
  1834.                     UndoMeasurement, UndoPoint: 
  1835.                         str := 'Measurement';
  1836.                     UndoTransform: 
  1837.                         str := 'Transformation';
  1838.                     UndoClear: 
  1839.                         str := 'Clear';
  1840.                     UndoZoom: 
  1841.                         str := 'Zoom';
  1842.                     UndoOutline: 
  1843.                         str := 'Outline';
  1844.                     UndoSliceDelete, UndoFirstSliceDelete: 
  1845.                         str := 'Delete Slice';
  1846.                     UndoLUT: 
  1847.                         str := 'LUT Change';
  1848.                     otherwise
  1849.                         str := '';
  1850.                 end;
  1851.                 SetItem(EditMenuH, UndoItem, concat('Undo ', str));
  1852.                 FindWhatToCopy;
  1853.                 if WhatToCopy = CopySelection then
  1854.                     str := 'Cut Selection'
  1855.                 else
  1856.                     str := 'Cut';
  1857.                 SetItem(EditMenuH, CutItem, str);
  1858.                 SetMenuItem(EditMenuH, CutItem, RoiShowing);
  1859.                 case WhatToCopy of
  1860.                     NothingToCopy: 
  1861.                         str := '';
  1862.                     CopySelection: 
  1863.                         str := 'Selection';
  1864.                     CopyCLUT: 
  1865.                         str := 'LUT';
  1866.                     CopyGrayMap: 
  1867.                         str := 'Gray Map';
  1868.                     CopyTools: 
  1869.                         str := 'Tools';
  1870.                     CopyPlot: 
  1871.                         str := 'Plot';
  1872.                     CopyCalibrationPlot: 
  1873.                         str := 'Calibration Plot';
  1874.                     CopyHistogram: 
  1875.                         str := 'Histogram';
  1876.                     CopyMeasurements: 
  1877.                         str := 'Measurements';
  1878.                     CopyColor: 
  1879.                         str := 'Color';
  1880.                 end;
  1881.                 SetItem(EditMenuH, CopyItem, concat('Copy ', str));
  1882.                 SetMenuItem(EditMenuH, CopyItem, WhatToCopy <> NothingToCopy);
  1883.                 SetMenuItem(EditMenuH, ClearItem, RoiShowing);
  1884.                 ShowItems := (WhatsOnClip <> nothing) or (OldScrapCount <> GetScrapCount);
  1885.                 SetMenuItem(EditMenuH, PasteItem, ShowItems);
  1886.                 SetMenuItem(EditMenuH, ShowClipboardItem, ShowItems and (WhatsOnClip <> TextOnClip));
  1887.                 ShowItems := info <> NoInfo;
  1888.                 for i := FillItem to DrawScaleItem do
  1889.                     SetMenuItem(EditMenuH, i, ShowItems);
  1890.                 if RoiShowing and EqualRect(RoiRect, PicRect) then
  1891.                     SetItem(EditMenuH, SelectAllItem, 'Deselect All')
  1892.                 else
  1893.                     SetItem(EditMenuH, SelectAllItem, 'Select All');
  1894.                 for i := SelectAllItem to ScaleAndRotateItem do
  1895.                     SetMenuItem(EditMenuH, i, ShowItems);
  1896.                 for i := RotateLeftItem to FlipHorizontalItem do
  1897.                     SetMenuItem(EditMenuH, i, ShowItems);
  1898.                 SetMenuItem(EditMenuH, UnZoomItem, ShowItems and ((magnification <> 1.0) or ScaleToFitWindow));
  1899.             end; {with}
  1900.     end;
  1901.  
  1902.  
  1903.     procedure ZoomOut;
  1904.         var
  1905.             Width, Height, divisor, NewWidth, NewHeight: integer;
  1906.             OldMagnification, xratio, yratio: extended;
  1907.     begin
  1908.         with Info^ do begin
  1909.                 if magnification < 2.0 then begin
  1910.                         beep;
  1911.                         exit(ZoomOut)
  1912.                     end;
  1913.                 OldMagnification := magnification;
  1914.                 if magnification = 2.0 then begin
  1915.                         magnification := 1.0;
  1916.                         divisor := 4
  1917.                     end
  1918.                 else if magnification = 3.0 then begin
  1919.                         magnification := 2.0;
  1920.                         divisor := 6
  1921.                     end
  1922.                 else if magnification = 4.0 then begin
  1923.                         magnification := 3.0;
  1924.                         divisor := 8
  1925.                     end
  1926.                 else begin
  1927.                         magnification := magnification / 2.0;
  1928.                         divisor := 4
  1929.                     end;
  1930.                 if EqualRect(SrcRect, PicRect) then begin {Make window smaller}
  1931.                         NewWidth := trunc(PicRect.right * magnification);
  1932.                         NewHeight := trunc(PicRect.bottom * magnification);
  1933.                         SizeWindow(wptr, NewWidth, NewHeight, true);
  1934.                         wrect.right := NewWidth;
  1935.                         wrect.bottom := NewHeight;
  1936.                         SrcRect := PicRect;
  1937.                         UpdateTitleBar;
  1938.                         UpdatePicWindow;
  1939.                         DrawMyGrowIcon(wptr);
  1940.                         exit(ZoomOut);
  1941.                     end;
  1942.                 if ((wrect.right > PicRect.right) or (wrect.bottom > PicRect.bottom)) then begin
  1943.                         xratio := wrect.right / PicRect.right;
  1944.                         yratio := wrect.bottom / PicRect.bottom;
  1945.                         if (xratio <> yratio) or ((xratio - trunc(xratio)) <> 0.0) then begin
  1946.                                 UnZoom;
  1947.                                 Exit(ZoomOut)
  1948.                             end;
  1949.                         SrcRect := PicRect;
  1950.                         Magnification := xratio;
  1951.                         UpdateTitleBar;
  1952.                         UpdatePicWindow;
  1953.                         DrawMyGrowIcon(wptr);
  1954.                         Exit(ZoomOut)
  1955.                     end;
  1956.             end; {with}
  1957.         with Info^.SrcRect, info^ do begin
  1958.                 if magnification = 1.0 then begin
  1959.                         width := wrect.right;
  1960.                         height := wrect.bottom;
  1961.                     end
  1962.                 else begin
  1963.                         width := round((right - left) * OldMagnification / Magnification);
  1964.                         height := round((bottom - top) * OldMagnification / Magnification);
  1965.                     end;
  1966.                 left := left - (width div divisor);
  1967.                 if left < 0 then
  1968.                     left := 0;
  1969.                 if (left + width) > Info^.PicRect.right then
  1970.                     left := Info^.PicRect.right - round(width);
  1971.                 top := top - (height div divisor);
  1972.                 if top < 0 then
  1973.                     top := 0;
  1974.                 if (top + height) > Info^.PicRect.bottom then
  1975.                     top := Info^.picRect.bottom - round(height);
  1976.                 right := left + width;
  1977.                 bottom := top + height;
  1978.                 RoiShowing := false;
  1979.                 UpdatePicWindow;
  1980.                 DrawMyGrowIcon(wptr);
  1981.                 UpdateTitleBar;
  1982.             end;
  1983.         ShowRoi;
  1984.     end;
  1985.  
  1986.  
  1987.     procedure DoGrow; {(WhichWindow: WindowPtr; event: EventRecord)}
  1988.         var
  1989.             NewSize: LongInt;
  1990.             trect, WinRect: rect;
  1991.             kind: integer;
  1992.             WasDigitizing: boolean;
  1993.             ZoomCenterH, ZoomCenterV, width, height: extended;
  1994.     begin
  1995.         kind := WindowPeek(WhichWindow)^.WindowKind;
  1996.         if (kind = PicKind) and (info^.PictureType = ScionType) then
  1997.             exit(DoGrow);
  1998.         NewSize := GrowWindow(WhichWindow, event.where, ScreenBits.bounds);
  1999.         if newSize = 0 then
  2000.             exit(DoGrow);
  2001.         if WindowPeek(WhichWindow)^.WindowKind = PicKind then
  2002.             with Info^ do begin
  2003.                     SetPort(wptr);
  2004.                     WasDigitizing := digitizing;
  2005.                     StopDigitizing;
  2006.                     InvalRect(wrect);
  2007.                     with trect do begin
  2008.                             top := 0;
  2009.                             left := 0;
  2010.                             right := LoWord(NewSize);
  2011.                             bottom := HiWord(NewSize);
  2012.                         end;
  2013.                     if ScaleToFitWindow then begin
  2014.                             ScaleImageWindow(trect);
  2015.                             wrect := trect;
  2016.                         end
  2017.                     else begin
  2018.                             if trect.right > PicRect.right * magnification then
  2019.                                 trect.right := trunc(PicRect.right * magnification);
  2020.                             if trect.bottom > PicRect.bottom * magnification then
  2021.                                 trect.bottom := trunc(PicRect.bottom * magnification);
  2022.                             wrect := trect;
  2023.                             with SrcRect do begin
  2024.                                     ZoomCenterH := left + (wrect.right / 2.0) / magnification;
  2025.                                     ZoomCenterV := top + (wrect.bottom / 2.0) / magnification;
  2026.                                     width := wrect.right / magnification;
  2027.                                     height := wrect.bottom / magnification;
  2028.                                     left := round(ZoomCenterH - width / 2.0);
  2029.                                     if left < 0 then
  2030.                                         left := 0;
  2031.                                     if (left + width) > PicRect.right then
  2032.                                         left := round(PicRect.right - width);
  2033.                                     top := round(ZoomCenterV - height / 2.0);
  2034.                                     if top < 0 then
  2035.                                         top := 0;
  2036.                                     if (top + height) > PicRect.bottom then
  2037.                                         top := round(picRect.bottom - height);
  2038.                                     right := round(left + width);
  2039.                                     bottom := round(top + height);
  2040.                                     wrect.right := trunc((right - left) * magnification);
  2041.                                     wrect.bottom := trunc((bottom - top) * magnification);
  2042.                                 end;
  2043.                             savewrect := wrect;
  2044.                         end;
  2045.                     SizeWindow(WhichWindow, wrect.right, wrect.bottom, true);
  2046.                     WindowState := NormalWindow;
  2047.                     if WasDigitizing then
  2048.                         StartDigitizing;
  2049.                     exit(DoGrow)
  2050.                 end; {with info^}
  2051.         if WhichWindow = PlotWindow then begin
  2052.                 PlotWidth := LoWord(NewSize);
  2053.                 PlotHeight := hiWord(NewSize);
  2054.                 SetPort(PlotWindow);
  2055.                 SizeWindow(PlotWindow, PlotWidth, Plotheight, true);
  2056.                 InvalRect(PlotWindow^.PortRect);
  2057.                 exit(DoGrow)
  2058.             end;
  2059.         if WhichWindow = ResultsWindow then begin
  2060.                 ResultsWidth := LoWord(NewSize);
  2061.                 ResultsHeight := hiWord(NewSize);
  2062.                 SetPort(ResultsWindow);
  2063.                 with ResultsWindow^.PortRect do
  2064.                     SetRect(tRect, right - 12, bottom - 12, right, bottom);
  2065.                 EraseRect(trect); {Erase Grow Box}
  2066.                 SizeWindow(ResultsWindow, ResultsWidth, ResultsHeight, true);
  2067.                 MoveControl(hScrollBar, -1, ResultsHeight - ScrollBarWidth);
  2068.                 MoveControl(vScrollBar, ResultsWidth - ScrollBarWidth, -1);
  2069.                 SizeControl(hScrollBar, ResultsWidth - 13, ScrollBarWidth + 1);
  2070.                 SizeControl(vScrollBar, ScrollBarWidth + 1, ResultsHeight - 13);
  2071.                 InvalRect(ResultsWindow^.PortRect);
  2072.                 with ListTE^^.viewRect do begin
  2073.                         right := left + ResultsWidth - ScrollBarWidth - 4;
  2074.                         bottom := top + ResultsHeight - ScrollBarWidth;
  2075.                     end;
  2076.                 UpdateScrollBars;
  2077.                 ScrollText;
  2078.             end;
  2079.     end;
  2080.  
  2081.  
  2082.     procedure ZoomIn; {(event: EventRecord)}
  2083.         var
  2084.             width, height, OldMagnification: extended;
  2085.             PicCenterH, PicCenterV, NewWidth, NewHeight: integer;
  2086.             trect: rect;
  2087.     begin
  2088.         if Info = NoInfo then begin
  2089.                 beep;
  2090.                 exit(ZoomIn)
  2091.             end;
  2092.         if Info^.ScaleToFitWindow then begin
  2093.                 PutMessage('The magnifying glass does not work in "Scale to Fit Window" mode.');
  2094.                 exit(ZoomIn)
  2095.             end;
  2096.         if BitAnd(Event.modifiers, OptionKey) = OptionKey then begin
  2097.                 ZoomOut;
  2098.                 WhatToUndo := NothingToUndo;
  2099.                 exit(ZoomIn)
  2100.             end;
  2101.         with Info^ do begin
  2102.                 OldMagnification := magnification;
  2103.                 if magnification = 1.0 then
  2104.                     magnification := 2.0
  2105.                 else if magnification = 2.0 then
  2106.                     magnification := 3.0
  2107.                 else if magnification = 3.0 then
  2108.                     magnification := 4.0
  2109.                 else begin
  2110.                         magnification := magnification * 2.0;
  2111.                         if magnification > 64.0 then begin
  2112.                                 magnification := 64.0;
  2113.                                 exit(ZoomIn)
  2114.                             end;
  2115.                     end;
  2116.                 if (WindowState = NormalWindow) and EqualRect(SrcRect, PicRect) then {Make window bigger?}
  2117.                     with trect do begin
  2118.                             NewWidth := trunc(PicRect.right * magnification);
  2119.                             NewHeight := trunc(PicRect.bottom * magnification);
  2120.                             if NewWidth <= 640 then begin
  2121.                                     GetWindowRect(wptr, trect);
  2122.                                     if ((left + NewWidth) <= ScreenWidth) and ((top + NewHeight) <= ScreenHeight) then begin
  2123.                                             SizeWindow(wptr, NewWidth, NewHeight, true);
  2124.                                             wrect.right := NewWidth;
  2125.                                             wrect.bottom := NewHeight;
  2126.                                         end;
  2127.                                 end;
  2128.                         end;
  2129.             end; {with}
  2130.         with Info^.SrcRect, Info^ do begin
  2131.                 PicCenterH := left + round(event.where.h / OldMagnification);
  2132.                 PicCenterV := top + round(event.where.v / OldMagnification);
  2133.                 width := wrect.right / magnification;
  2134.                 height := wrect.bottom / magnification;
  2135.                 left := PicCenterH - round(width / 2);
  2136.                 if left < 0 then
  2137.                     left := 0;
  2138.                 if (left + width) > PicRect.right then
  2139.                     left := PicRect.right - round(width);
  2140.                 top := PicCenterV - round(height / 2);
  2141.                 if top < 0 then
  2142.                     top := 0;
  2143.                 if (top + height) > PicRect.bottom then
  2144.                     top := picRect.bottom - round(height);
  2145.                 right := left + round(width);
  2146.                 bottom := top + round(height);
  2147.                 wrect.right := trunc((right - left) * magnification);
  2148.                 wrect.bottom := trunc((bottom - top) * magnification);
  2149.                 SizeWindow(wptr, wrect.right, wrect.bottom, true);
  2150.                 RoiShowing := false;
  2151.                 UpdatePicWindow;
  2152.                 DrawMyGrowIcon(wptr);
  2153.                 UpdateTitleBar;
  2154.                 WhatToUndo := UndoZoom;
  2155.                 ShowRoi;
  2156.             end; {with}
  2157.     end;
  2158.  
  2159.  
  2160.     procedure SynchScroll;
  2161.         var
  2162.             n: integer;
  2163.             TempInfo, SaveInfo: InfoPtr;
  2164.     begin
  2165.         SaveInfo := info;
  2166.         if allsamesize then
  2167.             for n := 1 to nPics do begin
  2168.                     TempInfo := pointer(WindowPeek(PicWindow[n])^.RefCon);
  2169.                     TempInfo^.SrcRect := info^.SrcRect;
  2170.                     TempInfo^.magnification := Info^.magnification;
  2171.                     info := TempInfo;
  2172.                     UpdatePicWindow;
  2173.                     Info := SaveInfo;
  2174.                 end
  2175.         else
  2176.             PutMessage('Synchronized scrolling requires all images and all windows to be the same size.');
  2177.     end;
  2178.  
  2179.  
  2180.     procedure Scroll; {(event: EventRecord)}
  2181.         var
  2182.             hstart, vstart, DeltaH, DeltaV, width, height: integer;
  2183.             loc: point;
  2184.             SaveSR: rect;
  2185.             WasDigitizing: boolean;
  2186.     begin
  2187.         with info^ do begin
  2188.                 if ScaleToFitWindow then begin
  2189.                         PutMessage('Scrolling does not work in "Scale to Fit Window" mode.');
  2190.                         exit(Scroll)
  2191.                     end;
  2192.                 WasDigitizing := digitizing;
  2193.                 StopDigitizing;
  2194.                 with event.where do begin
  2195.                         hstart := h;
  2196.                         vstart := v
  2197.                     end;
  2198.                 with SrcRect do begin
  2199.                         width := right - left;
  2200.                         height := bottom - top
  2201.                     end;
  2202.                 SaveSR := SrcRect;
  2203.                 while StillDown do begin
  2204.                         GetMouse(loc);
  2205.                         DeltaH := hstart - loc.h;
  2206.                         DeltaV := vstart - loc.v;
  2207.                         with SrcRect do begin
  2208.                                 left := SaveSR.left + DeltaH;
  2209.                                 if left < 0 then
  2210.                                     left := 0;
  2211.                                 if (left + width) > PicRect.right then
  2212.                                     left := PicRect.right - width;
  2213.                                 right := left + width;
  2214.                                 top := SaveSR.top + DeltaV;
  2215.                                 if top < 0 then
  2216.                                     top := 0;
  2217.                                 if (top + height) > PicRect.bottom then
  2218.                                     top := PicRect.bottom - height;
  2219.                                 bottom := top + height;
  2220.                             end;
  2221.                         UpdatePicWindow;
  2222.                         DrawMyGrowIcon(wptr);
  2223.                     end;
  2224.                 WhatToUndo := NothingToUndo;
  2225.                 ShowRoi;
  2226.                 if OptionKeyDown and (nPics > 1) then
  2227.                     SynchScroll;
  2228.                 if WasDigitizing then
  2229.                     StartDigitizing;
  2230.             end; {with info^}
  2231.     end;
  2232.  
  2233.  
  2234.     procedure ConvertClipboard;
  2235. {Converts local scrape to system scrape when quitting or}
  2236. {switching to other programs or DAs . }
  2237.         var
  2238.             PicH: PicHandle;
  2239.             frect: rect;
  2240.             err: LongInt;
  2241.     begin
  2242.         PicH := nil;
  2243.         if ((WhatsOnClip = RectPic) or (WhatsOnClip = CameraPic)) and (ClipBuf <> nil) and not ClipboardConverted then
  2244.             with ClipBufInfo^ do begin
  2245.                     ShowWatch;
  2246.                     SetPort(GrafPtr(osPort));
  2247.                     with RoiRect do
  2248.                         SetRect(frect, 0, 0, right - left, bottom - top);
  2249.                     ClipRect(frect);
  2250.                     LoadLUT(ctable);  {Switch to original LUT}
  2251.                     RGBForeColor(BlackRGB);
  2252.                     RGBBackColor(WhiteRGB);
  2253.                     PicH := OpenPicture(frect);
  2254.                     with osPort^ do begin
  2255.                             hlock(handle(portPixMap));
  2256.                             CopyBits(BitMapHandle(portPixMap)^^, BitMapHandle(portPixMap)^^, RoiRect, frect, SrcCopy, nil);
  2257.                             hunlock(handle(portPixMap));
  2258.                         end;
  2259.                     ClosePicture;
  2260.                     if info <> NoInfo then
  2261.                         LoadLUT(info^.ctable); {Restore LUT}
  2262.                 end;
  2263.         if (PicH <> nil) and (GetHandleSize(handle(PicH)) <= 10) then
  2264.             beep;
  2265.         if (PicH <> nil) or ClipTextInBuffer then begin
  2266.                 err := ZeroScrap;
  2267.                 if err = NoErr then begin
  2268.                         if PicH <> nil then begin
  2269.                                 hlock(handle(PicH));
  2270.                                 err := PutScrap(GetHandleSize(handle(PicH)), 'PICT', handle(PicH)^);
  2271.                                 hunlock(handle(PicH));
  2272.                                 DisposHandle(handle(PicH));
  2273.                             end;
  2274.                         if ClipTextInBuffer and (err = noErr) then
  2275.                             err := PutScrap(TextBufSize, 'TEXT', ptr(TextBufP));
  2276.                     end;
  2277.             end;
  2278.         ClipboardConverted := true;
  2279.     end;
  2280.  
  2281.  
  2282.     procedure SetupOperation; {(item: integer)}
  2283.         var
  2284.             AutoSelectAll: boolean;
  2285.     begin
  2286.         if NotinBounds then
  2287.             exit(SetupOperation);
  2288.         if (item = 10) then
  2289.             if NoSelection then
  2290.                 exit(SetupOperation);
  2291.         StopDigitizing;
  2292.         AutoSelectAll := not Info^.RoiShowing;
  2293.         if AutoSelectAll then
  2294.             SelectAll(true);
  2295.         SetupUndo;
  2296.         WhatToUndo := UndoEdit;
  2297.         case Item of
  2298.             8:  begin
  2299.                     CurrentOp := PaintOp;
  2300.                     OpPending := true
  2301.                 end;
  2302.             9:  begin
  2303.                     CurrentOp := InvertOp;
  2304.                     OpPending := true
  2305.                 end;
  2306.             10:  begin
  2307.                     CurrentOp := FrameOp;
  2308.                     OpPending := true
  2309.                 end;
  2310.         end;
  2311.         if AutoSelectAll then
  2312.             KillRoi;
  2313.         RoiUpdateTime := 0; {Forces outline to be redrawn in scale-to-fit mode.}
  2314.     end;
  2315.  
  2316.  
  2317.     procedure DoUndo;
  2318.         var
  2319.             aok: boolean;
  2320.     begin
  2321.         case WhatToUndo of
  2322.             UndoMeasurement: 
  2323.                 UndoLastMeasurement(true);
  2324.             UndoPoint:  begin
  2325.                     Undo;
  2326.                     UpdatePicWindow;
  2327.                     UndoLastMeasurement(true);
  2328.                     WhatToUndo := NothingToUndo;
  2329.                 end;
  2330.             UndoZoom:  begin
  2331.                     ZoomOut;
  2332.                     if info^.magnification < 2 then
  2333.                         WhatToUndo := NothingToUndo;
  2334.                 end;
  2335.             UndoOutLine:  begin
  2336.                     undo;
  2337.                     if WandAutoMeasure then
  2338.                         UndoLastMeasurement(true);
  2339.                     WhatToUndo := NothingToUndo;
  2340.                     UpdatePicWindow;
  2341.                 end;
  2342.             UndoSliceDelete, UndoFirstSliceDelete: 
  2343.                 if info^.StackInfo <> nil then
  2344.                     with info^.StackInfo^ do begin
  2345.                             if WhatToUndo = UndoFirstSliceDelete then
  2346.                                 CurrentSlice := 0;
  2347.                             aok := AddSlice(false);
  2348.                             if aok then begin
  2349.                                     Undo;
  2350.                                     UpdatePicWindow;
  2351.                                 end
  2352.                             else if CurrentSlice = 0 then
  2353.                                 CurrentSlice := 1;
  2354.                         end;
  2355.             UndoLUT:  begin
  2356.                     UndoLutChange;
  2357.                     DrawMap;
  2358.                     DensitySlicing := false;
  2359.                 end;
  2360.             otherwise begin
  2361.                     if UndoFromClip then
  2362.                         OpPending := false;
  2363.                     if not OpPending then
  2364.                         undo;
  2365.                     WhatToUndo := NothingToUndo;
  2366.                     if IsInsertionPoint then begin
  2367.                             InsertionPoint := TextStart;
  2368.                             TextStr := '';
  2369.                         end;
  2370.                     UpdatePicWindow;
  2371.                     if OpPending and (CurrentOp = PasteOp) then begin
  2372.                             OpPending := false;
  2373.                             KillRoi;
  2374.                         end;
  2375.                     OpPending := false;
  2376.                 end;
  2377.         end; {case}
  2378.     end;
  2379.  
  2380.  
  2381.  
  2382. end.